Skip to content

Commit

Permalink
add BlockValue to GetPayloadV2/V3 result (ethereum#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
roberto-bayardo authored Jan 8, 2023
1 parent ed01dbb commit 2b556db
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 50 deletions.
50 changes: 29 additions & 21 deletions core/beacon/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ type executableDataMarshaling struct {
Transactions []hexutil.Bytes
}

type ExecutableDataV2 struct {
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
BlockValue *big.Int `json:"blockValue" gencodec:"required"`
}

type PayloadStatusV1 struct {
Status string `json:"status"`
LatestValidHash *common.Hash `json:"latestValidHash"`
Expand Down Expand Up @@ -206,27 +211,30 @@ func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) {
return block, nil
}

// BlockToExecutableData constructs the executableData structure by filling the
// fields from the given block. It assumes the given block is post-merge block.
// Additional blob contents are provided as well.
func BlockToExecutableData(block *types.Block) *ExecutableData {
return &ExecutableData{
BlockHash: block.Hash(),
ParentHash: block.ParentHash(),
FeeRecipient: block.Coinbase(),
StateRoot: block.Root(),
Number: block.NumberU64(),
GasLimit: block.GasLimit(),
GasUsed: block.GasUsed(),
BaseFeePerGas: block.BaseFee(),
ExcessDataGas: block.ExcessDataGas(),
Timestamp: block.Time(),
ReceiptsRoot: block.ReceiptHash(),
LogsBloom: block.Bloom().Bytes(),
Transactions: encodeTransactions(block.Transactions()),
Random: block.MixDigest(),
ExtraData: block.Extra(),
Withdrawals: block.Withdrawals(),
// BlockToExecutableData constructs the ExecutableDataV2 structure by filling the fields from the
// given block, and setting BlockValue field to 'fees'. It assumes the given block is a post-merge
// block.
func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutableDataV2 {
return &ExecutableDataV2{
ExecutionPayload: &ExecutableData{
BlockHash: block.Hash(),
ParentHash: block.ParentHash(),
FeeRecipient: block.Coinbase(),
StateRoot: block.Root(),
Number: block.NumberU64(),
GasLimit: block.GasLimit(),
GasUsed: block.GasUsed(),
BaseFeePerGas: block.BaseFee(),
ExcessDataGas: block.ExcessDataGas(),
Timestamp: block.Time(),
ReceiptsRoot: block.ReceiptHash(),
LogsBloom: block.Bloom().Bytes(),
Transactions: encodeTransactions(block.Transactions()),
Random: block.MixDigest(),
ExtraData: block.Extra(),
Withdrawals: block.Withdrawals(),
},
BlockValue: fees,
}
}

Expand Down
6 changes: 3 additions & 3 deletions eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,11 +352,11 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID beacon.PayloadID) (*beacon.Execu
if err != nil {
return nil, err
}
return data, nil
return data.ExecutionPayload, nil
}

// GetPayloadV2 returns a cached payload by id.
func (api *ConsensusAPI) GetPayloadV2(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) {
func (api *ConsensusAPI) GetPayloadV2(payloadID beacon.PayloadID) (*beacon.ExecutableDataV2, error) {
log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID)
data := api.localBlocks.get(payloadID)
if data == nil {
Expand All @@ -366,7 +366,7 @@ func (api *ConsensusAPI) GetPayloadV2(payloadID beacon.PayloadID) (*beacon.Execu
}

// GetPayloadV3 returns a cached payload by id.
func (api *ConsensusAPI) GetPayloadV3(payloadID beacon.PayloadID) (*beacon.ExecutableData, error) {
func (api *ConsensusAPI) GetPayloadV3(payloadID beacon.PayloadID) (*beacon.ExecutableDataV2, error) {
data, err := api.GetPayloadV2(payloadID)
if err != nil {
return nil, err
Expand Down
17 changes: 9 additions & 8 deletions eth/catalyst/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.Pay
if err != nil {
return nil, err
}
return payload.ResolveFull(), nil
return payload.ResolveFull().ExecutionPayload, nil
}

func TestEmptyBlocks(t *testing.T) {
Expand Down Expand Up @@ -896,7 +896,7 @@ func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
if err != nil {
t.Fatalf("error preparing payload, err=%v", err)
}
data := *payload.Resolve()
data := *payload.Resolve().ExecutionPayload
resp2, err := api.NewPayloadV1(data)
if err != nil {
t.Fatalf("error sending NewPayload, err=%v", err)
Expand Down Expand Up @@ -1028,13 +1028,13 @@ func TestEIP4844(t *testing.T) {
if err != nil {
t.Fatalf("error getting payload, err=%v", err)
}
if status, err := api.NewPayloadV3(*execData); err != nil {
if status, err := api.NewPayloadV3(*execData.ExecutionPayload); err != nil {
t.Fatalf("error validating payload: %v", err)
} else if status.Status != beacon.VALID {
t.Fatalf("invalid payload")
}

fcState.HeadBlockHash = execData.BlockHash
fcState.HeadBlockHash = execData.ExecutionPayload.BlockHash
_, err = api.ForkchoiceUpdatedV2(fcState, nil)
if err != nil {
t.Fatalf("error preparing payload, err=%v", err)
Expand Down Expand Up @@ -1080,10 +1080,11 @@ func TestEIP4844Withdrawals(t *testing.T) {
if err != nil {
t.Fatalf("error getting payload, err=%v", err)
}
if execData.StateRoot != parent.Root {
t.Fatalf("mismatch state roots (got: %s, want: %s)", execData.StateRoot, blocks[8].Root())
ep := execData.ExecutionPayload
if ep.StateRoot != parent.Root {
t.Fatalf("mismatch state roots (got: %s, want: %s)", ep.StateRoot, blocks[8].Root())
}
if execData.Withdrawals == nil || len(execData.Withdrawals) != 0 {
t.Fatalf("expected empty withdrawals list. got %v", execData.Withdrawals)
if ep.Withdrawals == nil || len(ep.Withdrawals) != 0 {
t.Fatalf("expected empty withdrawals list. got %v", ep.Withdrawals)
}
}
2 changes: 1 addition & 1 deletion eth/catalyst/queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (q *payloadQueue) put(id beacon.PayloadID, payload *miner.Payload) {
}

// get retrieves a previously stored payload item or nil if it does not exist.
func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutableData {
func (q *payloadQueue) get(id beacon.PayloadID) *beacon.ExecutableDataV2 {
q.lock.RLock()
defer q.lock.RUnlock()

Expand Down
5 changes: 3 additions & 2 deletions eth/catalyst/tester.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package catalyst

import (
"math/big"
"sync"
"time"

Expand Down Expand Up @@ -76,8 +77,8 @@ func (tester *FullSyncTester) Start() error {
return
}
// Shoot out consensus events in order to trigger syncing.
data := beacon.BlockToExecutableData(tester.block)
tester.api.NewPayloadV1(*data)
data := beacon.BlockToExecutableData(tester.block, big.NewInt(0))
tester.api.NewPayloadV1(*data.ExecutionPayload)
tester.api.ForkchoiceUpdatedV1(beacon.ForkchoiceStateV1{
HeadBlockHash: tester.block.Hash(),
SafeBlockHash: tester.block.Hash(),
Expand Down
14 changes: 7 additions & 7 deletions miner/payload_building.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (payload *Payload) update(block *types.Block, fees *big.Int, elapsed time.D

// Resolve returns the latest built payload and also terminates the background
// thread for updating payload. It's safe to be called multiple times.
func (payload *Payload) Resolve() *beacon.ExecutableData {
func (payload *Payload) Resolve() *beacon.ExecutableDataV2 {
payload.lock.Lock()
defer payload.lock.Unlock()

Expand All @@ -118,9 +118,9 @@ func (payload *Payload) Resolve() *beacon.ExecutableData {
close(payload.stop)
}
if payload.full != nil {
return beacon.BlockToExecutableData(payload.full)
return beacon.BlockToExecutableData(payload.full, payload.fullFees)
}
return beacon.BlockToExecutableData(payload.empty)
return beacon.BlockToExecutableData(payload.empty, big.NewInt(0))
}

// ResolveToBlobsBundle returns the latest built blobs bundle payload and also terminates the
Expand All @@ -142,16 +142,16 @@ func (payload *Payload) ResolveToBlobsBundle() (*beacon.BlobsBundle, error) {

// ResolveEmpty is basically identical to Resolve, but it expects empty block only.
// It's only used in tests.
func (payload *Payload) ResolveEmpty() *beacon.ExecutableData {
func (payload *Payload) ResolveEmpty() *beacon.ExecutableDataV2 {
payload.lock.Lock()
defer payload.lock.Unlock()

return beacon.BlockToExecutableData(payload.empty)
return beacon.BlockToExecutableData(payload.empty, big.NewInt(0))
}

// ResolveFull is basically identical to Resolve, but it expects full block only.
// It's only used in tests.
func (payload *Payload) ResolveFull() *beacon.ExecutableData {
func (payload *Payload) ResolveFull() *beacon.ExecutableDataV2 {
payload.lock.Lock()
defer payload.lock.Unlock()

Expand All @@ -163,7 +163,7 @@ func (payload *Payload) ResolveFull() *beacon.ExecutableData {
}
payload.cond.Wait()
}
return beacon.BlockToExecutableData(payload.full)
return beacon.BlockToExecutableData(payload.full, payload.fullFees)
}

// buildPayload builds the payload according to the provided parameters.
Expand Down
21 changes: 13 additions & 8 deletions miner/payload_building_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package miner

import (
"math/big"
"reflect"
"testing"
"time"
Expand Down Expand Up @@ -47,28 +48,32 @@ func TestBuildPayload(t *testing.T) {
if err != nil {
t.Fatalf("Failed to build payload %v", err)
}
verify := func(data *beacon.ExecutableData, txs int) {
if data.ParentHash != b.chain.CurrentBlock().Hash() {
verify := func(data *beacon.ExecutableDataV2, txs int, expectedFees *big.Int) {
payload := data.ExecutionPayload
if payload.ParentHash != b.chain.CurrentBlock().Hash() {
t.Fatal("Unexpect parent hash")
}
if data.Random != (common.Hash{}) {
if payload.Random != (common.Hash{}) {
t.Fatal("Unexpect random value")
}
if data.Timestamp != timestamp {
if payload.Timestamp != timestamp {
t.Fatal("Unexpect timestamp")
}
if data.FeeRecipient != recipient {
if payload.FeeRecipient != recipient {
t.Fatal("Unexpect fee recipient")
}
if len(data.Transactions) != txs {
if len(payload.Transactions) != txs {
t.Fatal("Unexpect transaction set")
}
if data.BlockValue.Cmp(expectedFees) != 0 {
t.Fatalf("Block value (%v) != expected fees (%v)", data.BlockValue, expectedFees)
}
}
empty := payload.ResolveEmpty()
verify(empty, 0)
verify(empty, 0, big.NewInt(0))

full := payload.ResolveFull()
verify(full, len(pendingTxs))
verify(full, len(pendingTxs), big.NewInt(2625000000000))

// Ensure resolve can be called multiple times and the
// result should be unchanged
Expand Down

0 comments on commit 2b556db

Please sign in to comment.