Skip to content

Commit

Permalink
Merge pull request #16 from vulcanize/new_basefee_fields_and_serializ…
Browse files Browse the repository at this point in the history
…ation

New basefee fields and serialization
  • Loading branch information
i-norden authored Dec 11, 2019
2 parents 262dfc4 + 0d17045 commit a50d3c6
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmd/clef/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,7 @@ func testExternalUI(api *core.SignerAPI) {
[]byte("Extra data Extra data Extra data Extra data Extra data Extra data Extra data Extra data"),
common.HexToHash("0x0000H45H"),
types.BlockNonce{},
nil,
}
cliqueRlp, err := rlp.EncodeToBytes(cliqueHeader)
if err != nil {
Expand Down
160 changes: 160 additions & 0 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ type Header struct {
Extra []byte `json:"extraData" gencodec:"required"`
MixDigest common.Hash `json:"mixHash"`
Nonce BlockNonce `json:"nonce"`
BaseFee *big.Int `json:"baseFee" rlp:"nil"`
}

// field type overrides for gencodec
Expand All @@ -94,9 +95,167 @@ type headerMarshaling struct {
GasUsed hexutil.Uint64
Time hexutil.Uint64
Extra hexutil.Bytes
BaseFee *hexutil.Big
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
}

// EncodeRLP implements rlp.Encoder
func (h *Header) EncodeRLP(w io.Writer) error {
if h.BaseFee == nil {
return rlp.Encode(w, []interface{}{
h.ParentHash,
h.UncleHash,
h.Coinbase,
h.Root,
h.TxHash,
h.ReceiptHash,
h.Bloom,
h.Difficulty,
h.Number,
h.GasLimit,
h.GasUsed,
h.Time,
h.Extra,
h.MixDigest,
h.Nonce,
})
}
return rlp.Encode(w, []interface{}{
h.ParentHash,
h.UncleHash,
h.Coinbase,
h.Root,
h.TxHash,
h.ReceiptHash,
h.Bloom,
h.Difficulty,
h.Number,
h.GasLimit,
h.GasUsed,
h.Time,
h.Extra,
h.MixDigest,
h.Nonce,
h.BaseFee,
})
}

// DecodeRLP implements rlp.Decoder
func (h *Header) DecodeRLP(s *rlp.Stream) error {
_, err := s.List()
if err != nil {
return err
}
parentHash := new(common.Hash)
if err = s.Decode(parentHash); err != nil {
return err
}
uncleHash := new(common.Hash)
if err = s.Decode(uncleHash); err != nil {
return err
}
coinbase := new(common.Address)
if err = s.Decode(coinbase); err != nil {
return err
}
root := new(common.Hash)
if err = s.Decode(root); err != nil {
return err
}
txHash := new(common.Hash)
if err = s.Decode(txHash); err != nil {
return err
}
receiptHash := new(common.Hash)
if err = s.Decode(receiptHash); err != nil {
return err
}
bloom := new(Bloom)
if err = s.Decode(bloom); err != nil {
return err
}
difficulty := new(big.Int)
if err = s.Decode(difficulty); err != nil {
return err
}
number := new(big.Int)
if err = s.Decode(number); err != nil {
return err
}
gasLimit := new(uint64)
if err = s.Decode(gasLimit); err != nil {
return err
}
gasUsed := new(uint64)
if err = s.Decode(gasUsed); err != nil {
return err
}
time := new(uint64)
if err = s.Decode(time); err != nil {
return err
}
extra := new([]byte)
if err = s.Decode(extra); err != nil {
return err
}
mixDigest := new(common.Hash)
if err = s.Decode(mixDigest); err != nil {
return err
}
nonce := new(BlockNonce)
if err = s.Decode(nonce); err != nil {
return err
}
// if this is the end of the list then we are decoding a legacy header
if err = s.ListEnd(); err == nil {
h.ParentHash = *parentHash
h.UncleHash = *uncleHash
h.Coinbase = *coinbase
h.Root = *root
h.TxHash = *txHash
h.ReceiptHash = *receiptHash
h.Bloom = *bloom
h.Difficulty = difficulty
h.Number = number
h.GasLimit = *gasLimit
h.GasUsed = *gasUsed
h.Time = *time
h.Extra = *extra
h.MixDigest = *mixDigest
h.Nonce = *nonce
return nil
}
// if we are not at the end of the list, continue decoding the 1559 header fields
if err != rlp.ErrNotAtEOL {
return err
}
baseFee := new(big.Int)
if err = s.Decode(baseFee); err != nil {
return err
}
// we should now be at the end of the list even for a 1559 transaction
if err = s.ListEnd(); err != nil {
return err
}
h.ParentHash = *parentHash
h.UncleHash = *uncleHash
h.Coinbase = *coinbase
h.Root = *root
h.TxHash = *txHash
h.ReceiptHash = *receiptHash
h.Bloom = *bloom
h.Difficulty = difficulty
h.Number = number
h.GasLimit = *gasLimit
h.GasUsed = *gasUsed
h.Time = *time
h.Extra = *extra
h.MixDigest = *mixDigest
h.Nonce = *nonce
h.BaseFee = baseFee
return nil
}

// Hash returns the block hash of the header, which is simply the keccak256 hash of its
// RLP encoding.
func (h *Header) Hash() common.Hash {
Expand Down Expand Up @@ -318,6 +477,7 @@ func (b *Block) TxHash() common.Hash { return b.header.TxHash }
func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
func (b *Block) UncleHash() common.Hash { return b.header.UncleHash }
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }
func (b *Block) BaseFee() *big.Int { return b.header.BaseFee }

func (b *Block) Header() *Header { return CopyHeader(b.header) }

Expand Down
79 changes: 79 additions & 0 deletions core/types/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ package types

import (
"bytes"

"github.com/ethereum/go-ethereum/params"

//"fmt"
//"github.com/ethereum/go-ethereum/params"
"math/big"
"reflect"
"testing"
Expand Down Expand Up @@ -64,6 +69,80 @@ func TestBlockEncoding(t *testing.T) {
}
}

func TestEIP1559BlockEncoding(t *testing.T) {
tx, err := decodeTx(common.Hex2Bytes("f86903808207d094b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a82554483030d40830c35001ba0612a9c962f0ac2841c671c021e45aeaa23f2892bf34da5d32d7948754cf078bda03a350e0e4e1ff5299228eb921af7c0435dbabd5b3d17f79c925864192ca9d126"))
if err != nil {
t.Fatal(err)
}
txs := Transactions{tx}
header := &Header{
ParentHash: common.HexToHash("0x"),
Coinbase: common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1"),
Root: common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"),
Difficulty: big.NewInt(131072),
Number: big.NewInt(2675001),
GasLimit: 3141592,
GasUsed: 21000,
Time: 1426516743,
MixDigest: common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498"),
Nonce: EncodeNonce(11617697748499542468),
BaseFee: big.NewInt(800000),
}
hash := header.Hash()
rct := NewReceipt([]byte{0}, false, 800000)
rcts := Receipts{rct}
rcts.DeriveFields(params.MainnetChainConfig, hash, 2675001, txs)
block := NewBlock(header, txs, nil, rcts)
blockBytes, err := rlp.EncodeToBytes(block)
if err != nil {
t.Fatal(err)
}
expected := common.FromHex("f90271f90200a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0ed048395d4a0847b0cecfa3f649a9f4e56fd9813cb1bae507fb8a5a8a45009c6a0e596313d377d2ebcd789a5a17bbd6c6cb458be3f3c896db1e307865aa33acea2b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008328d139832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4830c3500f86bf86903808207d094b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a82554483030d40830c35001ba0612a9c962f0ac2841c671c021e45aeaa23f2892bf34da5d32d7948754cf078bda03a350e0e4e1ff5299228eb921af7c0435dbabd5b3d17f79c925864192ca9d126c0")
if !bytes.Equal(blockBytes, expected) {
t.Errorf("encoded block mismatch:\ngot: %x\nwant: %x", blockBytes, expected)
}
}

func TestEIP1559BlockDecoding(t *testing.T) {
blockEnc := common.FromHex("f90271f90200a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017a0ed048395d4a0847b0cecfa3f649a9f4e56fd9813cb1bae507fb8a5a8a45009c6a0e596313d377d2ebcd789a5a17bbd6c6cb458be3f3c896db1e307865aa33acea2b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008328d139832fefd8825208845506eb0780a0bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff49888a13a5a8c8f2bb1c4830c3500f86bf86903808207d094b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a82554483030d40830c35001ba0612a9c962f0ac2841c671c021e45aeaa23f2892bf34da5d32d7948754cf078bda03a350e0e4e1ff5299228eb921af7c0435dbabd5b3d17f79c925864192ca9d126c0")
var block Block
if err := rlp.DecodeBytes(blockEnc, &block); err != nil {
t.Fatal("decode error: ", err)
}

check := func(f string, got, want interface{}) {
if !reflect.DeepEqual(got, want) {
t.Errorf("%s mismatch: got %v, want %v", f, got, want)
}
}
check("Difficulty", block.Difficulty(), big.NewInt(131072))
check("GasLimit", block.GasLimit(), uint64(3141592))
check("GasUsed", block.GasUsed(), uint64(21000))
check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1"))
check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498"))
check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017"))
check("Hash", block.Hash(), common.HexToHash("112545e5bd6c278a01e46061467f23b9e690685d28df917a5ad184171b095770"))
check("Nonce", block.Nonce(), uint64(0xa13a5a8c8f2bb1c4))
check("Time", block.Time(), uint64(1426516743))
check("Size", block.Size(), common.StorageSize(len(blockEnc)))
check("BaseFee", block.BaseFee(), big.NewInt(800000))

tx1, err := decodeTx(common.Hex2Bytes("f86903808207d094b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a82554483030d40830c35001ba0612a9c962f0ac2841c671c021e45aeaa23f2892bf34da5d32d7948754cf078bda03a350e0e4e1ff5299228eb921af7c0435dbabd5b3d17f79c925864192ca9d126"))
if err != nil {
t.Fatal(err)
}
check("len(Transactions)", len(block.Transactions()), 1)
check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())

ourBlockEnc, err := rlp.EncodeToBytes(&block)
if err != nil {
t.Fatal("encode error: ", err)
}
if !bytes.Equal(ourBlockEnc, blockEnc) {
t.Errorf("encoded block mismatch:\ngot: %x\nwant: %x", ourBlockEnc, blockEnc)
}
}

func TestUncleHash(t *testing.T) {
uncles := make([]*Header, 0)
h := CalcUncleHash(uncles)
Expand Down
6 changes: 6 additions & 0 deletions core/types/gen_header_json.go

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

1 change: 1 addition & 0 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,7 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
"timestamp": hexutil.Uint64(head.Time),
"transactionsRoot": head.TxHash,
"receiptsRoot": head.ReceiptHash,
"baseFee": (*hexutil.Big)(head.BaseFee),
}
}

Expand Down

0 comments on commit a50d3c6

Please sign in to comment.