Skip to content

Commit

Permalink
Simplify Header.EncodeRLP (#5995)
Browse files Browse the repository at this point in the history
Also cherry-pick ethereum/go-ethereum#24666.

Co-authored-by: Felix Lange <[email protected]>
  • Loading branch information
yperbasis and fjl authored Nov 8, 2022
1 parent 7f9edd6 commit 3280531
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 160 deletions.
181 changes: 28 additions & 153 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (n *BlockNonce) UnmarshalText(input []byte) error {
type Header struct {
ParentHash common.Hash `json:"parentHash" gencodec:"required"`
UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"`
Coinbase common.Address `json:"miner" gencodec:"required"`
Coinbase common.Address `json:"miner"`
Root common.Hash `json:"stateRoot" gencodec:"required"`
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"`
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"`
Expand All @@ -89,27 +89,22 @@ type Header struct {
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash"`
Nonce BlockNonce `json:"nonce"`
BaseFee *big.Int `json:"baseFeePerGas"`
AuRaStep uint64
AuRaSeal []byte
// AuRa extensions (alternative to MixDigest & Nonce)
AuRaStep uint64
AuRaSeal []byte

BaseFee *big.Int `json:"baseFeePerGas"` // EIP-1559

// The verkle proof is ignored in legacy headers
Verkle bool
VerkleProof []byte `json:"verkleProof"`
VerkleKeyVals []verkle.KeyValuePair `json:"verkleKeyVals"`
VerkleProof []byte
VerkleKeyVals []verkle.KeyValuePair
}

func (h Header) EncodingSize() int {
func (h *Header) EncodingSize() int {
encodingSize := 33 /* ParentHash */ + 33 /* UncleHash */ + 21 /* Coinbase */ + 33 /* Root */ + 33 /* TxHash */ +
33 /* ReceiptHash */ + 259 /* Bloom */

if len(h.AuRaSeal) != 0 {
encodingSize += 1 + rlp.IntLenExcludingHead(h.AuRaStep) + 1 + len(h.AuRaSeal)
if len(h.AuRaSeal) >= 56 {
encodingSize += (bits.Len(uint(len(h.AuRaSeal))) + 7) / 8
}
} else {
encodingSize += 33 /* MixDigest */ + 9 /* BlockNonce */
}
encodingSize++
if h.Difficulty != nil {
encodingSize += rlp.BigIntLenExcludingHead(h.Difficulty)
Expand Down Expand Up @@ -138,48 +133,6 @@ func (h Header) EncodingSize() int {
}
encodingSize += len(h.Extra)
}
// size of BaseFee
var baseFeeBitLen, baseFeeLen int
if h.BaseFee != nil {
encodingSize++
baseFeeBitLen = h.BaseFee.BitLen()
if baseFeeBitLen >= 8 {
baseFeeLen = (baseFeeBitLen + 7) / 8
}
encodingSize += baseFeeLen
}

if h.Verkle {
// Encoding of Verkle Proof
encodingSize++
switch len(h.VerkleProof) {
case 0:
case 1:
if h.VerkleProof[0] >= 128 {
encodingSize++
}
default:
if len(h.VerkleProof) >= 56 {
encodingSize += (bits.Len(uint(len(h.VerkleProof))) + 7) / 8
}
encodingSize += len(h.VerkleProof)
}
encodingSize++

var tmpBuffer bytes.Buffer
if err := rlp.Encode(&tmpBuffer, h.VerkleKeyVals); err != nil {
panic(err)
}
encodingSize += tmpBuffer.Len()
}

return encodingSize
}

func (h Header) EncodeRLP(w io.Writer) error {
// Precompute the size of the encoding
encodingSize := 33 /* ParentHash */ + 33 /* UncleHash */ + 21 /* Coinbase */ + 33 /* Root */ + 33 /* TxHash */ +
33 /* ReceiptHash */ + 259 /* Bloom */

if len(h.AuRaSeal) != 0 {
encodingSize += 1 + rlp.IntLenExcludingHead(h.AuRaStep) + 1 + len(h.AuRaSeal)
Expand All @@ -189,6 +142,12 @@ func (h Header) EncodeRLP(w io.Writer) error {
} else {
encodingSize += 33 /* MixDigest */ + 9 /* BlockNonce */
}

if h.BaseFee != nil {
encodingSize++
encodingSize += rlp.BigIntLenExcludingHead(h.BaseFee)
}

if h.Verkle {
// Encoding of Verkle Proof
encodingSize++
Expand All @@ -208,62 +167,16 @@ func (h Header) EncodeRLP(w io.Writer) error {

var tmpBuffer bytes.Buffer
if err := rlp.Encode(&tmpBuffer, h.VerkleKeyVals); err != nil {
return nil
panic(err)
}
encodingSize += tmpBuffer.Len()
}

encodingSize++
var diffBitLen, diffLen int
if h.Difficulty != nil {
diffBitLen = h.Difficulty.BitLen()
if diffBitLen >= 8 {
diffLen = (diffBitLen + 7) / 8
}
}
encodingSize += diffLen

encodingSize++
var numberBitLen, numberLen int
if h.Number != nil {
numberBitLen = h.Number.BitLen()
if numberBitLen >= 8 {
numberLen = (numberBitLen + 7) / 8
}
}
encodingSize += numberLen

encodingSize++
encodingSize += rlp.IntLenExcludingHead(h.GasLimit)
return encodingSize
}

encodingSize++
encodingSize += rlp.IntLenExcludingHead(h.GasUsed)

encodingSize++
encodingSize += rlp.IntLenExcludingHead(h.Time)
// size of Extra
encodingSize++
switch len(h.Extra) {
case 0:
case 1:
if h.Extra[0] >= 128 {
encodingSize++
}
default:
if len(h.Extra) >= 56 {
encodingSize += (bits.Len(uint(len(h.Extra))) + 7) / 8
}
encodingSize += len(h.Extra)
}
var baseFeeBitLen, baseFeeLen int
if h.BaseFee != nil {
encodingSize++
baseFeeBitLen = h.BaseFee.BitLen()
if baseFeeBitLen >= 8 {
baseFeeLen = (baseFeeBitLen + 7) / 8
}
encodingSize += baseFeeLen
}
func (h *Header) EncodeRLP(w io.Writer) error {
encodingSize := h.EncodingSize()

var b [33]byte
// Prefix
Expand Down Expand Up @@ -318,37 +231,11 @@ func (h Header) EncodeRLP(w io.Writer) error {
if _, err := w.Write(h.Bloom.Bytes()); err != nil {
return err
}
if diffBitLen < 8 {
if diffBitLen > 0 {
b[0] = byte(h.Difficulty.Uint64())
} else {
b[0] = 128
}
if _, err := w.Write(b[:1]); err != nil {
return err
}
} else {
b[0] = 128 + byte(diffLen)
h.Difficulty.FillBytes(b[1 : 1+diffLen])
if _, err := w.Write(b[:1+diffLen]); err != nil {
return err
}
if err := rlp.EncodeBigInt(h.Difficulty, w, b[:]); err != nil {
return err
}
if numberBitLen < 8 {
if numberBitLen > 0 {
b[0] = byte(h.Number.Uint64())
} else {
b[0] = 128
}
if _, err := w.Write(b[:1]); err != nil {
return err
}
} else {
b[0] = 128 + byte(numberLen)
h.Number.FillBytes(b[1 : 1+numberLen])
if _, err := w.Write(b[:1+numberLen]); err != nil {
return err
}
if err := rlp.EncodeBigInt(h.Number, w, b[:]); err != nil {
return err
}
if err := rlp.EncodeInt(h.GasLimit, w, b[:]); err != nil {
return err
Expand Down Expand Up @@ -388,21 +275,8 @@ func (h Header) EncodeRLP(w io.Writer) error {
}

if h.BaseFee != nil {
if baseFeeBitLen < 8 {
if baseFeeBitLen > 0 {
b[0] = byte(h.BaseFee.Uint64())
} else {
b[0] = 128
}
if _, err := w.Write(b[:1]); err != nil {
return err
}
} else {
b[0] = 128 + byte(baseFeeLen)
h.BaseFee.FillBytes(b[1 : 1+baseFeeLen])
if _, err := w.Write(b[:1+baseFeeLen]); err != nil {
return err
}
if err := rlp.EncodeBigInt(h.BaseFee, w, b[:]); err != nil {
return err
}
}

Expand Down Expand Up @@ -544,6 +418,7 @@ func (h *Header) DecodeRLP(s *rlp.Stream) error {
}
rlp.DecodeBytes(rawKv, h.VerkleKeyVals)
}

if err := s.ListEnd(); err != nil {
return fmt.Errorf("close header struct: %w", err)
}
Expand Down
13 changes: 6 additions & 7 deletions core/types/gen_header_json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions rlp/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,28 @@ func EncodeInt(i uint64, w io.Writer, buffer []byte) error {
return err
}

func EncodeBigInt(i *big.Int, w io.Writer, buffer []byte) error {
bitLen := 0 // treat nil as 0
if i != nil {
bitLen = i.BitLen()
}
if bitLen < 8 {
if bitLen > 0 {
buffer[0] = byte(i.Uint64())
} else {
buffer[0] = 0x80
}
_, err := w.Write(buffer[:1])
return err
}

size := (bitLen + 7) / 8
buffer[0] = 0x80 + byte(size)
i.FillBytes(buffer[1 : 1+size])
_, err := w.Write(buffer[:1+size])
return err
}

func EncodeString(s []byte, w io.Writer, buffer []byte) error {
switch len(s) {
case 0:
Expand Down

0 comments on commit 3280531

Please sign in to comment.