diff --git a/beacon-chain/core/blocks/payload.go b/beacon-chain/core/blocks/payload.go index cada9454d0..542cb96903 100644 --- a/beacon-chain/core/blocks/payload.go +++ b/beacon-chain/core/blocks/payload.go @@ -33,6 +33,9 @@ func IsMergeTransitionComplete(st state.BeaconState) (bool, error) { if IsPreBellatrixVersion(st.Version()) { return false, nil } + if st.Version() > version.Bellatrix { + return true, nil + } h, err := st.LatestExecutionPayloadHeader() if err != nil { return false, err @@ -81,6 +84,9 @@ func IsExecutionEnabled(st state.BeaconState, body interfaces.BeaconBlockBody) ( if IsPreBellatrixVersion(st.Version()) { return false, nil } + if st.Version() > version.Bellatrix { + return true, nil + } header, err := st.LatestExecutionPayloadHeader() if err != nil { return false, err @@ -121,7 +127,6 @@ func ValidatePayloadWhenMergeCompletes(st state.BeaconState, payload interfaces. if !complete { return nil } - header, err := st.LatestExecutionPayloadHeader() if err != nil { return err @@ -192,21 +197,23 @@ func ValidatePayload(st state.BeaconState, payload interfaces.ExecutionData) err // transactions_root=hash_tree_root(payload.transactions), // ) func ProcessPayload(st state.BeaconState, payload interfaces.ExecutionData) (state.BeaconState, error) { + if st.Version() >= version.Capella { + withdrawals, err := payload.Withdrawals() + if err != nil { + return nil, errors.Wrap(err, "could not get payload withdrawals") + } + st, err = ProcessWithdrawals(st, withdrawals) + if err != nil { + return nil, errors.Wrap(err, "could not process withdrawals") + } + } if err := ValidatePayloadWhenMergeCompletes(st, payload); err != nil { return nil, err } if err := ValidatePayload(st, payload); err != nil { return nil, err } - header, err := blocks.PayloadToHeader(payload) - if err != nil { - return nil, err - } - wrappedHeader, err := blocks.WrappedExecutionPayloadHeader(header) - if err != nil { - return nil, err - } - if err := st.SetLatestExecutionPayloadHeader(wrappedHeader); err != nil { + if err := st.SetLatestExecutionPayloadHeader(payload); err != nil { return nil, err } return st, nil diff --git a/beacon-chain/core/blocks/payload_test.go b/beacon-chain/core/blocks/payload_test.go index 0899206a50..e6c5f31357 100644 --- a/beacon-chain/core/blocks/payload_test.go +++ b/beacon-chain/core/blocks/payload_test.go @@ -7,12 +7,14 @@ import ( "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers" "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time" "github.com/prysmaticlabs/prysm/v3/beacon-chain/state" + state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native" fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams" consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v3/encoding/bytesutil" "github.com/prysmaticlabs/prysm/v3/encoding/ssz" enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" + ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" "github.com/prysmaticlabs/prysm/v3/testing/require" "github.com/prysmaticlabs/prysm/v3/testing/util" "github.com/prysmaticlabs/prysm/v3/time/slots" @@ -203,6 +205,13 @@ func Test_IsMergeComplete(t *testing.T) { } } +func Test_IsMergeCompleteCapella(t *testing.T) { + st, _ := util.DeterministicGenesisStateCapella(t, 1) + got, err := blocks.IsMergeTransitionComplete(st) + require.NoError(t, err) + require.Equal(t, got, true) +} + func Test_IsExecutionBlock(t *testing.T) { tests := []struct { name string @@ -237,6 +246,16 @@ func Test_IsExecutionBlock(t *testing.T) { } } +func Test_IsExecutionBlockCapella(t *testing.T) { + blk := util.NewBeaconBlockCapella() + blk.Block.Body.ExecutionPayload = emptyPayloadCapella() + wrappedBlock, err := consensusblocks.NewBeaconBlock(blk.Block) + require.NoError(t, err) + got, err := blocks.IsExecutionBlock(wrappedBlock.Body()) + require.NoError(t, err) + require.Equal(t, true, got) +} + func Test_IsExecutionEnabled(t *testing.T) { tests := []struct { name string @@ -330,6 +349,15 @@ func Test_IsExecutionEnabled(t *testing.T) { }) } } +func Test_IsExecutionEnabledCapella(t *testing.T) { + st, _ := util.DeterministicGenesisStateCapella(t, 1) + blk := util.NewBeaconBlockCapella() + body, err := consensusblocks.NewBeaconBlockBody(blk.Block.Body) + require.NoError(t, err) + got, err := blocks.IsExecutionEnabled(st, body) + require.NoError(t, err) + require.Equal(t, true, got) +} func Test_IsExecutionEnabledUsingHeader(t *testing.T) { tests := []struct { @@ -583,6 +611,20 @@ func Test_ProcessPayload(t *testing.T) { } } +func Test_ProcessPayloadCapella(t *testing.T) { + spb := ðpb.BeaconStateCapella{} + st, err := state_native.InitializeFromProtoCapella(spb) + require.NoError(t, err) + header, err := emptyPayloadHeaderCapella() + require.NoError(t, err) + require.NoError(t, st.SetLatestExecutionPayloadHeader(header)) + payload := emptyPayloadCapella() + wrapped, err := consensusblocks.WrappedExecutionPayloadCapella(payload) + require.NoError(t, err) + _, err = blocks.ProcessPayload(st, wrapped) + require.NoError(t, err) +} + func Test_ProcessPayloadHeader(t *testing.T) { st, _ := util.DeterministicGenesisStateBellatrix(t, 1) random, err := helpers.RandaoMix(st, time.CurrentEpoch(st)) @@ -828,6 +870,22 @@ func emptyPayloadHeader() (interfaces.ExecutionData, error) { }) } +func emptyPayloadHeaderCapella() (interfaces.ExecutionData, error) { + return consensusblocks.WrappedExecutionPayloadHeaderCapella(&enginev1.ExecutionPayloadHeaderCapella{ + 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), + TransactionsRoot: make([]byte, fieldparams.RootLength), + WithdrawalsRoot: make([]byte, fieldparams.RootLength), + ExtraData: make([]byte, 0), + }) +} + func emptyPayload() *enginev1.ExecutionPayload { return &enginev1.ExecutionPayload{ ParentHash: make([]byte, fieldparams.RootLength), @@ -842,3 +900,19 @@ func emptyPayload() *enginev1.ExecutionPayload { ExtraData: make([]byte, 0), } } + +func emptyPayloadCapella() *enginev1.ExecutionPayloadCapella { + return &enginev1.ExecutionPayloadCapella{ + 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), + Withdrawals: make([]*enginev1.Withdrawal, 0), + ExtraData: make([]byte, 0), + } +} diff --git a/beacon-chain/state/state-native/setters_payload_header.go b/beacon-chain/state/state-native/setters_payload_header.go index 442c4ebe2f..20dcb854c3 100644 --- a/beacon-chain/state/state-native/setters_payload_header.go +++ b/beacon-chain/state/state-native/setters_payload_header.go @@ -3,6 +3,7 @@ package state_native import ( "github.com/pkg/errors" nativetypes "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native/types" + consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks" "github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces" enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1" _ "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" @@ -19,6 +20,22 @@ func (b *BeaconState) SetLatestExecutionPayloadHeader(val interfaces.ExecutionDa } switch header := val.Proto().(type) { + case *enginev1.ExecutionPayload: + latest, err := consensusblocks.PayloadToHeader(val) + if err != nil { + return errors.Wrap(err, "could not convert payload to header") + } + b.latestExecutionPayloadHeader = latest + b.markFieldAsDirty(nativetypes.LatestExecutionPayloadHeader) + return nil + case *enginev1.ExecutionPayloadCapella: + latest, err := consensusblocks.PayloadToHeaderCapella(val) + if err != nil { + return errors.Wrap(err, "could not convert payload to header") + } + b.latestExecutionPayloadHeaderCapella = latest + b.markFieldAsDirty(nativetypes.LatestExecutionPayloadHeaderCapella) + return nil case *enginev1.ExecutionPayloadHeader: b.latestExecutionPayloadHeader = header b.markFieldAsDirty(nativetypes.LatestExecutionPayloadHeader) diff --git a/consensus-types/blocks/execution.go b/consensus-types/blocks/execution.go index 1a2731c756..94100a3b61 100644 --- a/consensus-types/blocks/execution.go +++ b/consensus-types/blocks/execution.go @@ -647,6 +647,10 @@ func PayloadToHeaderCapella(payload interfaces.ExecutionData) (*enginev1.Executi // IsEmptyExecutionData checks if an execution data is empty underneath. If a single field has // a non-zero value, this function will return false. func IsEmptyExecutionData(data interfaces.ExecutionData) (bool, error) { + _, ok := data.Proto().(*enginev1.ExecutionPayloadCapella) + if ok { + return false, nil + } if !bytes.Equal(data.ParentHash(), make([]byte, fieldparams.RootLength)) { return false, nil }