From c1f2c36704925df3259c7a02742af68e41defd60 Mon Sep 17 00:00:00 2001 From: Raul Jordan Date: Mon, 8 Aug 2022 17:04:09 +0000 Subject: [PATCH] Respond With Empty Payloads Pre-Merge (#11184) * regression test * build * nil check * fix test * gazelle * lint --- beacon-chain/execution/BUILD.bazel | 1 + beacon-chain/execution/engine_client.go | 27 ++++++++++++++++++ beacon-chain/execution/engine_client_test.go | 16 +++++++++++ consensus-types/blocks/BUILD.bazel | 1 + consensus-types/blocks/factory.go | 30 +++++++++++++------- consensus-types/blocks/factory_test.go | 4 ++- testing/util/block.go | 3 ++ 7 files changed, 71 insertions(+), 11 deletions(-) diff --git a/beacon-chain/execution/BUILD.bazel b/beacon-chain/execution/BUILD.bazel index 57735c650..f3e59346c 100644 --- a/beacon-chain/execution/BUILD.bazel +++ b/beacon-chain/execution/BUILD.bazel @@ -38,6 +38,7 @@ go_library( "//beacon-chain/state/stategen:go_default_library", "//beacon-chain/state/v1:go_default_library", "//config/features:go_default_library", + "//config/fieldparams:go_default_library", "//config/params:go_default_library", "//consensus-types/blocks:go_default_library", "//consensus-types/interfaces:go_default_library", diff --git a/beacon-chain/execution/engine_client.go b/beacon-chain/execution/engine_client.go index 958f8f47c..4a324522c 100644 --- a/beacon-chain/execution/engine_client.go +++ b/beacon-chain/execution/engine_client.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/holiman/uint256" "github.com/pkg/errors" + fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams" "github.com/prysmaticlabs/prysm/config/params" "github.com/prysmaticlabs/prysm/consensus-types/blocks" "github.com/prysmaticlabs/prysm/consensus-types/interfaces" @@ -329,6 +330,17 @@ func (s *Service) ReconstructFullBellatrixBlock( if err != nil { return nil, err } + if header.IsNil() { + return nil, errors.New("execution payload header in blinded block was nil") + } + + // If the payload header has a block hash of 0x0, it means we are pre-merge and should + // simply return the block with an empty execution payload. + if bytes.Equal(header.BlockHash(), params.BeaconConfig().ZeroHash[:]) { + payload := buildEmptyExecutionPayload() + return blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload) + } + executionBlockHash := common.BytesToHash(header.BlockHash()) executionBlock, err := s.ExecutionBlockByHash(ctx, executionBlockHash, true /* with txs */) if err != nil { @@ -460,3 +472,18 @@ func tDStringToUint256(td string) (*uint256.Int, error) { } return i, nil } + +func buildEmptyExecutionPayload() *pb.ExecutionPayload { + return &pb.ExecutionPayload{ + ParentHash: make([]byte, fieldparams.RootLength), + FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), + StateRoot: make([]byte, fieldparams.RootLength), + ReceiptsRoot: make([]byte, fieldparams.RootLength), + LogsBloom: make([]byte, fieldparams.LogsBloomLength), + PrevRandao: make([]byte, fieldparams.RootLength), + BaseFeePerGas: make([]byte, fieldparams.RootLength), + BlockHash: make([]byte, fieldparams.RootLength), + Transactions: make([][]byte, 0), + ExtraData: make([]byte, 0), + } +} diff --git a/beacon-chain/execution/engine_client_test.go b/beacon-chain/execution/engine_client_test.go index 5d74bf231..b4364d86a 100644 --- a/beacon-chain/execution/engine_client_test.go +++ b/beacon-chain/execution/engine_client_test.go @@ -420,6 +420,22 @@ func TestReconstructFullBellatrixBlock(t *testing.T) { _, err = service.ReconstructFullBellatrixBlock(ctx, wrapped) require.ErrorContains(t, want, err) }) + t.Run("pre-merge execution payload", func(t *testing.T) { + service := &Service{} + bellatrixBlock := util.NewBlindedBeaconBlockBellatrix() + wanted := util.NewBeaconBlockBellatrix() + wanted.Block.Slot = 1 + // Make sure block hash is the zero hash. + bellatrixBlock.Block.Body.ExecutionPayloadHeader.BlockHash = make([]byte, 32) + bellatrixBlock.Block.Slot = 1 + wrapped, err := blocks.NewSignedBeaconBlock(bellatrixBlock) + require.NoError(t, err) + wantedWrapped, err := blocks.NewSignedBeaconBlock(wanted) + require.NoError(t, err) + reconstructed, err := service.ReconstructFullBellatrixBlock(ctx, wrapped) + require.NoError(t, err) + require.DeepEqual(t, wantedWrapped, reconstructed) + }) t.Run("properly reconstructs block with correct payload", func(t *testing.T) { fix := fixtures() payload, ok := fix["ExecutionPayload"].(*pb.ExecutionPayload) diff --git a/consensus-types/blocks/BUILD.bazel b/consensus-types/blocks/BUILD.bazel index f41999acd..020a5a476 100644 --- a/consensus-types/blocks/BUILD.bazel +++ b/consensus-types/blocks/BUILD.bazel @@ -40,6 +40,7 @@ go_test( "//config/fieldparams:go_default_library", "//consensus-types/interfaces:go_default_library", "//consensus-types/primitives:go_default_library", + "//encoding/bytesutil:go_default_library", "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//proto/prysm/v1alpha1/validator-client:go_default_library", diff --git a/consensus-types/blocks/factory.go b/consensus-types/blocks/factory.go index ad1e7f529..631c042a1 100644 --- a/consensus-types/blocks/factory.go +++ b/consensus-types/blocks/factory.go @@ -154,20 +154,30 @@ func BuildSignedBeaconBlockFromExecutionPayload( return nil, errors.Wrap(err, "could not get execution payload header") default: } - payloadRoot, err := payload.HashTreeRoot() + wrappedPayload, err := WrappedExecutionPayload(payload) if err != nil { - return nil, errors.Wrap(err, "could not hash tree root execution payload") + return nil, err } - payloadHeaderRoot, err := payloadHeader.HashTreeRoot() + empty, err := IsEmptyExecutionData(wrappedPayload) if err != nil { - return nil, errors.Wrap(err, "could not hash tree root payload header") + return nil, err } - if payloadRoot != payloadHeaderRoot { - return nil, fmt.Errorf( - "payload %#x and header %#x roots do not match", - payloadRoot, - payloadHeaderRoot, - ) + if !empty { + payloadRoot, err := payload.HashTreeRoot() + if err != nil { + return nil, errors.Wrap(err, "could not hash tree root execution payload") + } + payloadHeaderRoot, err := payloadHeader.HashTreeRoot() + if err != nil { + return nil, errors.Wrap(err, "could not hash tree root payload header") + } + if payloadRoot != payloadHeaderRoot { + return nil, fmt.Errorf( + "payload %#x and header %#x roots do not match", + payloadRoot, + payloadHeaderRoot, + ) + } } syncAgg, err := b.Body().SyncAggregate() if err != nil { diff --git a/consensus-types/blocks/factory_test.go b/consensus-types/blocks/factory_test.go index f6659d32b..3ac157aa1 100644 --- a/consensus-types/blocks/factory_test.go +++ b/consensus-types/blocks/factory_test.go @@ -6,6 +6,7 @@ import ( "testing" fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams" + "github.com/prysmaticlabs/prysm/encoding/bytesutil" enginev1 "github.com/prysmaticlabs/prysm/proto/engine/v1" eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/runtime/version" @@ -241,6 +242,7 @@ func TestBuildSignedBeaconBlockFromExecutionPayload(t *testing.T) { require.Equal(t, true, errors.Is(err, ErrUnsupportedGetter)) }) t.Run("payload header root and payload root mismatch", func(t *testing.T) { + blockHash := bytesutil.Bytes32(1) payload := &enginev1.ExecutionPayload{ ParentHash: make([]byte, fieldparams.RootLength), FeeRecipient: make([]byte, 20), @@ -249,7 +251,7 @@ func TestBuildSignedBeaconBlockFromExecutionPayload(t *testing.T) { LogsBloom: make([]byte, 256), PrevRandao: make([]byte, fieldparams.RootLength), BaseFeePerGas: make([]byte, fieldparams.RootLength), - BlockHash: make([]byte, fieldparams.RootLength), + BlockHash: blockHash, Transactions: make([][]byte, 0), } wrapped, err := WrappedExecutionPayload(payload) diff --git a/testing/util/block.go b/testing/util/block.go index a1cf1d082..f6bb96aa6 100644 --- a/testing/util/block.go +++ b/testing/util/block.go @@ -749,6 +749,8 @@ func HydrateBeaconBlockBodyBellatrix(b *ethpb.BeaconBlockBodyBellatrix) *ethpb.B PrevRandao: make([]byte, fieldparams.RootLength), BaseFeePerGas: make([]byte, fieldparams.RootLength), BlockHash: make([]byte, fieldparams.RootLength), + Transactions: make([][]byte, 0), + ExtraData: make([]byte, 0), } } return b @@ -815,6 +817,7 @@ func HydrateBlindedBeaconBlockBodyBellatrix(b *ethpb.BlindedBeaconBlockBodyBella BaseFeePerGas: make([]byte, 32), BlockHash: make([]byte, 32), TransactionsRoot: make([]byte, fieldparams.RootLength), + ExtraData: make([]byte, 0), } } return b