Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-add header fields with values used in Ethereum 2.0 #2124

Merged
merged 9 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 60 additions & 14 deletions core/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package types

import (
"encoding/binary"
"encoding/json"
"fmt"
"io"
Expand All @@ -35,10 +36,39 @@ import (

var (
EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
EmptyUncleHash = rlpHash([]*Header(nil)) // 1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347
EmptyRandomness = Randomness{}
EmptyEpochSnarkData = EpochSnarkData{}
EmptyMixDigest = common.HexToHash("0000000000000000000000000000000000000000000000000000000000000000")
)

// A BlockNonce is a 64-bit hash which proves (combined with the
// mix-hash) that a sufficient amount of computation has been carried
// out on a block.
type BlockNonce [8]byte

// EncodeNonce converts the given integer to a block nonce.
func EncodeNonce(i uint64) BlockNonce {
var n BlockNonce
binary.BigEndian.PutUint64(n[:], i)
return n
}

// Uint64 returns the integer value of a block nonce.
func (n BlockNonce) Uint64() uint64 {
return binary.BigEndian.Uint64(n[:])
}

// MarshalText encodes n as a hex string with 0x prefix.
func (n BlockNonce) MarshalText() ([]byte, error) {
return hexutil.Bytes(n[:]).MarshalText()
}

// UnmarshalText implements encoding.TextUnmarshaler.
func (n *BlockNonce) UnmarshalText(input []byte) error {
return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
}

//go:generate gencodec -type Header -field-override headerMarshaling -out gen_header_json.go

// Header represents a block header in the Ethereum blockchain.
Expand All @@ -60,16 +90,22 @@ type Header struct {
extraError error

GasLimit uint64 `json:"gasLimit" rlp:"optional"`
// Proof-of-work fields for Eth compatibility
Difficulty *big.Int `json:"difficulty" rlp:"optional"`
Nonce BlockNonce `json:"nonce" rlp:"optional"`
UncleHash common.Hash `json:"sha3Uncles" rlp:"optional"`
MixDigest common.Hash `json:"mixHash" rlp:"optional"`
}

// field type overrides for gencodec
type headerMarshaling struct {
Number *hexutil.Big
GasLimit hexutil.Uint64
GasUsed hexutil.Uint64
Time hexutil.Uint64
Extra hexutil.Bytes
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
Number *hexutil.Big
GasLimit hexutil.Uint64
GasUsed hexutil.Uint64
Time hexutil.Uint64
Extra hexutil.Bytes
Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON
Difficulty *hexutil.Big
}

// Hash returns the block hash of the header, which is simply the keccak256 hash of its
Expand Down Expand Up @@ -286,15 +322,19 @@ func NewBlockWithHeader(header *Header) *Block {
func CopyHeader(h *Header) *Header {
cpy := Header{
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: new(big.Int),
GasLimit: h.GasLimit,
GasUsed: h.GasUsed,
Time: h.Time,
MixDigest: h.MixDigest,
Nonce: h.Nonce,
}

if h.Number != nil {
Expand Down Expand Up @@ -345,17 +385,23 @@ func (b *Block) Transaction(hash common.Hash) *Transaction {
}

func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) }
func (b *Block) GasLimit() uint64 { return b.header.GasLimit }
func (b *Block) GasUsed() uint64 { return b.header.GasUsed }
func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) }
func (b *Block) Time() uint64 { return b.header.Time }
func (b *Block) TotalDifficulty() *big.Int { return new(big.Int).Add(b.header.Number, big.NewInt(1)) }
func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() }
func (b *Block) Bloom() Bloom { return b.header.Bloom }
func (b *Block) Coinbase() common.Address { return b.header.Coinbase }
func (b *Block) Root() common.Hash { return b.header.Root }
func (b *Block) ParentHash() common.Hash { return b.header.ParentHash }
func (b *Block) TxHash() common.Hash { return b.header.TxHash }
func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash }
func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) }

func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() }
func (b *Block) MixDigest() common.Hash { return b.header.MixDigest }
func (b *Block) Nonce() uint64 { return binary.BigEndian.Uint64(b.header.Nonce[:]) }
func (b *Block) Bloom() Bloom { return b.header.Bloom }
func (b *Block) Coinbase() common.Address { return b.header.Coinbase }
func (b *Block) Root() common.Hash { return b.header.Root }
func (b *Block) ParentHash() common.Hash { return b.header.ParentHash }
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) Header() *Header { return CopyHeader(b.header) }
func (b *Block) MutableHeader() *Header { return b.header }
Expand Down
24 changes: 24 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.

31 changes: 18 additions & 13 deletions e2e_test/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ func TestEthersJSCompatibility(t *testing.T) {
err = network[0].Tracker.AwaitBlock(ctx, num+1)
require.NoError(t, err)
block := network[0].Tracker.GetProcessedBlock(num)
require.NotNil(t, block)

// Prune state
err = pruneStateOfBlock(ctx, network[0], block.Hash())
Expand Down Expand Up @@ -601,10 +602,10 @@ func TestEthersJSCompatibilityDisable(t *testing.T) {
err = network[0].WsClient.GetRPCClient().CallContext(ctx, &result, "eth_getBlockByNumber", "latest", true)
require.NoError(t, err)

_, ok := result["gasLimit"]
assert.True(t, ok, "gasLimit field should be present on RPC block")
_, ok = result["baseFeePerGas"]
assert.True(t, ok, "baseFeePerGas field should be present on RPC block")
for _, field := range []string{"gasLimit", "baseFeePerGas", "sha3Uncles", "uncles", "nonce", "mixHash", "difficulty"} {
_, ok := result[field]
assert.Truef(t, ok, "%s field should be present on RPC block after GFork", field)
}

// Turn off compatibility and check fields are not present
ec.RPCEthCompatibility = false
Expand All @@ -621,7 +622,7 @@ func TestEthersJSCompatibilityDisable(t *testing.T) {

// After GFork, gasLimit should be returned directly from the header, even if
// RPCEthCompatibility is off, since it is now part of the header hash.
_, ok = result["gasLimit"]
_, ok := result["gasLimit"]
assert.True(t, ok, "gasLimit field must be present on RPC block after GFork")
_, ok = result["baseFeePerGas"]
assert.False(t, ok, "baseFeePerGas field must be present on RPC block")
Expand All @@ -648,10 +649,14 @@ func TestEthersJSCompatibilityDisableBeforeGFork(t *testing.T) {
err = network[0].WsClient.GetRPCClient().CallContext(ctx, &result, "eth_getBlockByNumber", "latest", true)
require.NoError(t, err)

_, ok := result["gasLimit"]
assert.True(t, ok, "gasLimit field should be present on RPC block")
_, ok = result["baseFeePerGas"]
assert.True(t, ok, "baseFeePerGas field should be present on RPC block")
for _, field := range []string{"gasLimit", "baseFeePerGas", "difficulty"} {
_, ok := result[field]
assert.Truef(t, ok, "%s field should be present on RPC block before GFork", field)
}
for _, field := range []string{"sha3Uncles", "uncles", "nonce", "mixHash"} {
_, ok := result[field]
assert.Falsef(t, ok, "%s field should not be present on RPC block before GFork", field)
}

// Turn off compatibility and check fields are not present
ec.RPCEthCompatibility = false
Expand All @@ -666,8 +671,8 @@ func TestEthersJSCompatibilityDisableBeforeGFork(t *testing.T) {
err = network[0].WsClient.GetRPCClient().CallContext(ctx, &result, "eth_getBlockByNumber", "latest", true)
require.NoError(t, err)

_, ok = result["gasLimit"]
assert.False(t, ok, "gasLimit field should not be present on RPC block before GFork")
_, ok = result["baseFeePerGas"]
assert.False(t, ok, "baseFeePerGas field should not be present on RPC block")
for _, field := range []string{"gasLimit", "baseFeePerGas", "sha3Uncles", "uncles", "nonce", "mixHash", "difficulty"} {
_, ok := result[field]
assert.Falsef(t, ok, "%s field should not be present on RPC block before GFork", field)
}
}
15 changes: 9 additions & 6 deletions ethclient/ethclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,11 @@ func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) {
if got != nil && got.Number != nil && got.Number.Sign() == 0 {
got.Number = big.NewInt(0) // hack to make DeepEqual work
}
if got != nil && got.Difficulty != nil && got.Difficulty.Sign() == 0 {
got.Difficulty = big.NewInt(0) // hack to make DeepEqual work
}
if !reflect.DeepEqual(got, tt.want) {
t.Fatalf("HeaderByNumber(%v)\n = %v\nwant %v", tt.block, got, tt.want)
t.Fatalf("HeaderByNumber(%v)\n = %+v\nwant %+v", tt.block, got, tt.want)
}
})
}
Expand Down Expand Up @@ -396,39 +399,39 @@ func testGetBlock(t *testing.T, client *rpc.Client) {
// Get current block number
blockNumber, err := ec.BlockNumber(context.Background())
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("BlockNumber: %v", err)
}
if blockNumber != 1 {
t.Fatalf("BlockNumber returned wrong number: %d", blockNumber)
}
// Get current block by number
block, err := ec.BlockByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("BlockByNumber: %v", err)
}
if block.NumberU64() != blockNumber {
t.Fatalf("BlockByNumber returned wrong block: want %d got %d", blockNumber, block.NumberU64())
}
// Get current block by hash
blockH, err := ec.BlockByHash(context.Background(), block.Hash())
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("BlockByHash: %v", err)
}
if block.Hash() != blockH.Hash() {
t.Fatalf("BlockByHash returned wrong block: want %v got %v", block.Hash().Hex(), blockH.Hash().Hex())
}
// Get header by number
header, err := ec.HeaderByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("HeaderByNumber: %v", err)
}
if block.Header().Hash() != header.Hash() {
t.Fatalf("HeaderByNumber returned wrong header: want %v got %v", block.Header().Hash().Hex(), header.Hash().Hex())
}
// Get header by hash
headerH, err := ec.HeaderByHash(context.Background(), block.Hash())
if err != nil {
t.Fatalf("unexpected error: %v", err)
t.Fatalf("HeaderByHash: %v", err)
}
if block.Header().Hash() != headerH.Hash() {
t.Fatalf("HeaderByHash returned wrong header: want %v got %v", block.Header().Hash().Hex(), headerH.Hash().Hex())
Expand Down
9 changes: 9 additions & 0 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,15 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
"transactionsRoot": head.TxHash,
"receiptsRoot": head.ReceiptHash,
}
// Former proof-of-work fields, now constants, see https://eips.ethereum.org/EIPS/eip-3675#block-structure
// Set after GFork
if head.Difficulty != nil {
result["difficulty"] = (*hexutil.Big)(head.Difficulty)
result["nonce"] = head.Nonce
result["sha3Uncles"] = head.UncleHash
result["uncles"] = []interface{}{}
result["mixHash"] = head.MixDigest
}

return result
}
Expand Down
4 changes: 4 additions & 0 deletions miner/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ func prepareBlock(w *worker) (*blockState, error) {
b.gasPool = new(core.GasPool).AddGas(b.gasLimit)
if w.chainConfig.IsGFork(header.Number) {
header.GasLimit = b.gasLimit
header.Difficulty = big.NewInt(0)
header.Nonce = types.EncodeNonce(0)
header.UncleHash = types.EmptyUncleHash
header.MixDigest = types.EmptyMixDigest
}

// Play our part in generating the random beacon.
Expand Down
2 changes: 1 addition & 1 deletion monorepo_commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
d216e7599f499adec2e0200e599f601ea5424cde
a70a729f9785ad0130d8605493b008210cb22326