forked from ethereum-optimism/op-geth
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR updates the header encoding and decoding for celo blocks to be able to support data migrated from celo-blockchain. Our post gingerbread headers actually decode into the op-geth header structure without any changes. Since adding fields to the end of a struct does not cause rlp decoding to fail for previously encoded values. Our pre-gingerbread don't decode into the op-geth header structure because the pre-gingerbread headers miss fields from the middle of the struct so we need to handle those explicitly. The decision on how to decode is made based on introspecting the rlp and looking at the second field which is a hash (length 32 bytes) post-gingerbread, but an address (length 20 bytes) pre-gingerbread. The decision on how to encode is made based on the value of gasLimit if zero then it's a pre-gingerbread header. Additionally we needed to allow genesis blocks in a CeL2 migrated chain context (by checking if Cel2Time is set and non zero) that lack GasLimit and Difficulty because those fields were considered required by op-geth but not present in early Celo. Finally some tests that used blocks with zero gas limits needed to be updated since with a zero gas limit the different encoding was now breaking them, and adding a non zero gas limit meant the block hash changed.
- Loading branch information
Showing
11 changed files
with
239 additions
and
150 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
package types | ||
|
||
import ( | ||
"io" | ||
"math/big" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/rlp" | ||
) | ||
|
||
type IstanbulExtra rlp.RawValue | ||
|
||
type beforeGingerbreadHeader struct { | ||
ParentHash common.Hash `json:"parentHash" gencodec:"required"` | ||
Coinbase common.Address `json:"miner" gencodec:"required"` | ||
Root common.Hash `json:"stateRoot" gencodec:"required"` | ||
TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` | ||
ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` | ||
Bloom Bloom `json:"logsBloom" gencodec:"required"` | ||
Number *big.Int `json:"number" gencodec:"required"` | ||
GasUsed uint64 `json:"gasUsed" gencodec:"required"` | ||
Time uint64 `json:"timestamp" gencodec:"required"` | ||
Extra []byte `json:"extraData" gencodec:"required"` | ||
} | ||
|
||
// This type is required to avoid an infinite loop when decoding | ||
type afterGingerbreadHeader Header | ||
|
||
func (h *Header) DecodeRLP(s *rlp.Stream) error { | ||
var raw rlp.RawValue | ||
err := s.Decode(&raw) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
preGingerbread, err := isPreGingerbreadHeader(raw) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if preGingerbread { // Address | ||
// Before gingerbread | ||
decodedHeader := beforeGingerbreadHeader{} | ||
err = rlp.DecodeBytes(raw, &decodedHeader) | ||
|
||
h.ParentHash = decodedHeader.ParentHash | ||
h.Coinbase = decodedHeader.Coinbase | ||
h.Root = decodedHeader.Root | ||
h.TxHash = decodedHeader.TxHash | ||
h.ReceiptHash = decodedHeader.ReceiptHash | ||
h.Bloom = decodedHeader.Bloom | ||
h.Number = decodedHeader.Number | ||
h.GasUsed = decodedHeader.GasUsed | ||
h.Time = decodedHeader.Time | ||
h.Extra = decodedHeader.Extra | ||
} else { | ||
// After gingerbread | ||
decodedHeader := afterGingerbreadHeader{} | ||
err = rlp.DecodeBytes(raw, &decodedHeader) | ||
|
||
h.ParentHash = decodedHeader.ParentHash | ||
h.UncleHash = decodedHeader.UncleHash | ||
h.Coinbase = decodedHeader.Coinbase | ||
h.Root = decodedHeader.Root | ||
h.TxHash = decodedHeader.TxHash | ||
h.ReceiptHash = decodedHeader.ReceiptHash | ||
h.Bloom = decodedHeader.Bloom | ||
h.Difficulty = decodedHeader.Difficulty | ||
h.Number = decodedHeader.Number | ||
h.GasLimit = decodedHeader.GasLimit | ||
h.GasUsed = decodedHeader.GasUsed | ||
h.Time = decodedHeader.Time | ||
h.Extra = decodedHeader.Extra | ||
h.MixDigest = decodedHeader.MixDigest | ||
h.Nonce = decodedHeader.Nonce | ||
h.BaseFee = decodedHeader.BaseFee | ||
h.WithdrawalsHash = decodedHeader.WithdrawalsHash | ||
h.BlobGasUsed = decodedHeader.BlobGasUsed | ||
h.ExcessBlobGas = decodedHeader.ExcessBlobGas | ||
h.ParentBeaconRoot = decodedHeader.ParentBeaconRoot | ||
} | ||
|
||
return err | ||
} | ||
|
||
// EncodeRLP implements encodes the Header to an RLP data stream. | ||
func (h *Header) EncodeRLP(w io.Writer) error { | ||
// We check for a pre gingerbread header by looking for (GasLimit == 0) | ||
// here. We don't use Difficulty because CopyHeader can end up setting a | ||
// nil Difficulty to a zero difficulty, so testing for nil difficulty is | ||
// not reliable, and post gingerbread difficulty is hardcoded to zero. Also | ||
// testing for base fee is not reliable because some older eth blocks had | ||
// no base fee and they are used in some tests. | ||
if h.GasLimit == 0 { | ||
// Encode the header | ||
encodedHeader := beforeGingerbreadHeader{ | ||
ParentHash: h.ParentHash, | ||
Coinbase: h.Coinbase, | ||
Root: h.Root, | ||
TxHash: h.TxHash, | ||
ReceiptHash: h.ReceiptHash, | ||
Bloom: h.Bloom, | ||
Number: h.Number, | ||
GasUsed: h.GasUsed, | ||
Time: h.Time, | ||
Extra: h.Extra, | ||
} | ||
|
||
return rlp.Encode(w, &encodedHeader) | ||
} | ||
|
||
// After gingerbread | ||
encodedHeader := afterGingerbreadHeader{ | ||
ParentHash: h.ParentHash, | ||
UncleHash: h.UncleHash, | ||
Coinbase: h.Coinbase, | ||
Root: h.Root, | ||
TxHash: h.TxHash, | ||
ReceiptHash: h.ReceiptHash, | ||
Bloom: h.Bloom, | ||
Difficulty: h.Difficulty, | ||
Number: h.Number, | ||
GasLimit: h.GasLimit, | ||
GasUsed: h.GasUsed, | ||
Time: h.Time, | ||
Extra: h.Extra, | ||
MixDigest: h.MixDigest, | ||
Nonce: h.Nonce, | ||
BaseFee: h.BaseFee, | ||
WithdrawalsHash: h.WithdrawalsHash, | ||
BlobGasUsed: h.BlobGasUsed, | ||
ExcessBlobGas: h.ExcessBlobGas, | ||
ParentBeaconRoot: h.ParentBeaconRoot, | ||
} | ||
|
||
return rlp.Encode(w, &encodedHeader) | ||
} | ||
|
||
// isPreGingerbreadHeader introspects the header rlp to check the length of the | ||
// second element of the list (the first element describes the list). Pre | ||
// gingerbread the second element of a header is an address which is 20 bytes | ||
// long, post gingerbread the second element is a hash which is 32 bytes long. | ||
func isPreGingerbreadHeader(buf []byte) (bool, error) { | ||
var contentSize uint64 | ||
var err error | ||
for i := 0; i < 3; i++ { | ||
buf, _, _, contentSize, err = rlp.ReadNext(buf) | ||
if err != nil { | ||
return false, err | ||
} | ||
} | ||
|
||
return contentSize == common.AddressLength, nil | ||
} |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.