Skip to content

Commit cb9b5e8

Browse files
terencechainprylabs-bulldozer[bot]rkapka
authored
Use payload attribute type for engine-API (#11719)
* Add payload attribute type * Gazelle * Fix test * Use new payload attribute type * Fix test * Fix test * Update beacon-chain/execution/engine_client.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Feedbacks * Fix suggestion * Update argument, fix test * Return emptyAttri instead of nil Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com> Co-authored-by: Radosław Kapka <rkapka@wp.pl>
1 parent 145eb5a commit cb9b5e8

File tree

14 files changed

+275
-43
lines changed

14 files changed

+275
-43
lines changed

beacon-chain/blockchain/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ go_library(
6464
"//config/params:go_default_library",
6565
"//consensus-types/blocks:go_default_library",
6666
"//consensus-types/interfaces:go_default_library",
67+
"//consensus-types/payload-attribute:go_default_library",
6768
"//consensus-types/primitives:go_default_library",
6869
"//crypto/bls:go_default_library",
6970
"//encoding/bytesutil:go_default_library",

beacon-chain/blockchain/error.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ var (
1919
errInvalidNilSummary = errors.New("nil summary returned from the DB")
2020
// errWrongBlockCount is returned when the wrong number of blocks or block roots is used
2121
errWrongBlockCount = errors.New("wrong number of blocks or block roots")
22-
// block is not a valid optimistic candidate block
23-
errNotOptimisticCandidate = errors.New("block is not suitable for optimistic sync")
2422
// errBlockNotFoundInCacheOrDB is returned when a block is not found in the cache or DB.
2523
errBlockNotFoundInCacheOrDB = errors.New("block not found in cache or db")
2624
// errNilStateFromStategen is returned when a nil state is returned from the state generator.

beacon-chain/blockchain/execution_engine.go

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ import (
1515
"github.com/prysmaticlabs/prysm/v3/config/params"
1616
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
1717
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
18+
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
1819
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
1920
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
2021
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
22+
"github.com/prysmaticlabs/prysm/v3/runtime/version"
2123
"github.com/prysmaticlabs/prysm/v3/time/slots"
2224
"github.com/sirupsen/logrus"
2325
"go.opencensus.io/trace"
@@ -67,10 +69,7 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
6769
}
6870

6971
nextSlot := s.CurrentSlot() + 1 // Cache payload ID for next slot proposer.
70-
hasAttr, attr, proposerId, err := s.getPayloadAttribute(ctx, arg.headState, nextSlot)
71-
if err != nil {
72-
log.WithError(err).Error("Could not get head payload attribute")
73-
}
72+
hasAttr, attr, proposerId := s.getPayloadAttribute(ctx, arg.headState, nextSlot)
7473

7574
payloadID, lastValidHash, err := s.cfg.ExecutionEngineCaller.ForkchoiceUpdated(ctx, fcs, attr)
7675
if err != nil {
@@ -149,7 +148,8 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
149148
log.WithError(err).Error("Could not set head root to valid")
150149
return nil, nil
151150
}
152-
if hasAttr && payloadID != nil { // If the forkchoice update call has an attribute, update the proposer payload ID cache.
151+
// If the forkchoice update call has an attribute, update the proposer payload ID cache.
152+
if hasAttr && payloadID != nil {
153153
var pId [8]byte
154154
copy(pId[:], payloadID[:])
155155
s.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(nextSlot, proposerId, pId, arg.headRoot)
@@ -250,22 +250,25 @@ func (s *Service) notifyNewPayload(ctx context.Context, postStateVersion int,
250250

251251
// getPayloadAttributes returns the payload attributes for the given state and slot.
252252
// The attribute is required to initiate a payload build process in the context of an `engine_forkchoiceUpdated` call.
253-
func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot types.Slot) (bool, *enginev1.PayloadAttributes, types.ValidatorIndex, error) {
253+
func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot types.Slot) (bool, payloadattribute.Attributer, types.ValidatorIndex) {
254+
emptyAttri := payloadattribute.EmptyWithVersion(st.Version())
254255
// Root is `[32]byte{}` since we are retrieving proposer ID of a given slot. During insertion at assignment the root was not known.
255256
proposerID, _, ok := s.cfg.ProposerSlotIndexCache.GetProposerPayloadIDs(slot, [32]byte{} /* root */)
256257
if !ok { // There's no need to build attribute if there is no proposer for slot.
257-
return false, nil, 0, nil
258+
return false, emptyAttri, 0
258259
}
259260

260261
// Get previous randao.
261262
st = st.Copy()
262263
st, err := transition.ProcessSlotsIfPossible(ctx, st, slot)
263264
if err != nil {
264-
return false, nil, 0, err
265+
log.WithError(err).Error("Could not process slots to get payload attribute")
266+
return false, emptyAttri, 0
265267
}
266268
prevRando, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
267269
if err != nil {
268-
return false, nil, 0, nil
270+
log.WithError(err).Error("Could not get randao mix to get payload attribute")
271+
return false, emptyAttri, 0
269272
}
270273

271274
// Get fee recipient.
@@ -283,22 +286,53 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
283286
"Please refer to our documentation for instructions")
284287
}
285288
case err != nil:
286-
return false, nil, 0, errors.Wrap(err, "could not get fee recipient in db")
289+
log.WithError(err).Error("Could not get fee recipient to get payload attribute")
290+
return false, emptyAttri, 0
287291
default:
288292
feeRecipient = recipient
289293
}
290294

291295
// Get timestamp.
292296
t, err := slots.ToTime(uint64(s.genesisTime.Unix()), slot)
293297
if err != nil {
294-
return false, nil, 0, err
298+
log.WithError(err).Error("Could not get timestamp to get payload attribute")
299+
return false, emptyAttri, 0
295300
}
296-
attr := &enginev1.PayloadAttributes{
297-
Timestamp: uint64(t.Unix()),
298-
PrevRandao: prevRando,
299-
SuggestedFeeRecipient: feeRecipient.Bytes(),
301+
302+
var attr payloadattribute.Attributer
303+
switch st.Version() {
304+
case version.Capella:
305+
withdrawals, err := st.ExpectedWithdrawals()
306+
if err != nil {
307+
log.WithError(err).Error("Could not get expected withdrawals to get payload attribute")
308+
return false, emptyAttri, 0
309+
}
310+
attr, err = payloadattribute.New(&enginev1.PayloadAttributesV2{
311+
Timestamp: uint64(t.Unix()),
312+
PrevRandao: prevRando,
313+
SuggestedFeeRecipient: feeRecipient.Bytes(),
314+
Withdrawals: withdrawals,
315+
})
316+
if err != nil {
317+
log.WithError(err).Error("Could not get payload attribute")
318+
return false, emptyAttri, 0
319+
}
320+
case version.Bellatrix:
321+
attr, err = payloadattribute.New(&enginev1.PayloadAttributes{
322+
Timestamp: uint64(t.Unix()),
323+
PrevRandao: prevRando,
324+
SuggestedFeeRecipient: feeRecipient.Bytes(),
325+
})
326+
if err != nil {
327+
log.WithError(err).Error("Could not get payload attribute")
328+
return false, emptyAttri, 0
329+
}
330+
default:
331+
log.WithField("version", st.Version()).Error("Could not get payload attribute due to unknown state version")
332+
return false, emptyAttri, 0
300333
}
301-
return true, attr, proposerID, nil
334+
335+
return true, attr, proposerID
302336
}
303337

304338
// removeInvalidBlockAndState removes the invalid block and its corresponding state from the cache and DB.

beacon-chain/blockchain/execution_engine_test.go

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -792,33 +792,74 @@ func Test_GetPayloadAttribute(t *testing.T) {
792792
// Cache miss
793793
service, err := NewService(ctx, opts...)
794794
require.NoError(t, err)
795-
hasPayload, _, vId, err := service.getPayloadAttribute(ctx, nil, 0)
796-
require.NoError(t, err)
795+
st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
796+
hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0)
797797
require.Equal(t, false, hasPayload)
798798
require.Equal(t, types.ValidatorIndex(0), vId)
799799

800800
// Cache hit, advance state, no fee recipient
801801
suggestedVid := types.ValidatorIndex(1)
802802
slot := types.Slot(1)
803803
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
804-
st, _ := util.DeterministicGenesisState(t, 1)
805804
hook := logTest.NewGlobal()
806-
hasPayload, attr, vId, err := service.getPayloadAttribute(ctx, st, slot)
807-
require.NoError(t, err)
805+
hasPayload, attr, vId := service.getPayloadAttribute(ctx, st, slot)
808806
require.Equal(t, true, hasPayload)
809807
require.Equal(t, suggestedVid, vId)
810-
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient).String())
808+
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
811809
require.LogsContain(t, hook, "Fee recipient is currently using the burn address")
812810

813811
// Cache hit, advance state, has fee recipient
814812
suggestedAddr := common.HexToAddress("123")
815813
require.NoError(t, service.cfg.BeaconDB.SaveFeeRecipientsByValidatorIDs(ctx, []types.ValidatorIndex{suggestedVid}, []common.Address{suggestedAddr}))
816814
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
817-
hasPayload, attr, vId, err = service.getPayloadAttribute(ctx, st, slot)
815+
hasPayload, attr, vId = service.getPayloadAttribute(ctx, st, slot)
816+
require.Equal(t, true, hasPayload)
817+
require.Equal(t, suggestedVid, vId)
818+
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
819+
}
820+
821+
func Test_GetPayloadAttributeV2(t *testing.T) {
822+
ctx := context.Background()
823+
beaconDB := testDB.SetupDB(t)
824+
opts := []Option{
825+
WithDatabase(beaconDB),
826+
WithStateGen(stategen.New(beaconDB, doublylinkedtree.New())),
827+
WithProposerIdsCache(cache.NewProposerPayloadIDsCache()),
828+
}
829+
830+
// Cache miss
831+
service, err := NewService(ctx, opts...)
832+
require.NoError(t, err)
833+
st, _ := util.DeterministicGenesisStateCapella(t, 1)
834+
hasPayload, _, vId := service.getPayloadAttribute(ctx, st, 0)
835+
require.Equal(t, false, hasPayload)
836+
require.Equal(t, types.ValidatorIndex(0), vId)
837+
838+
// Cache hit, advance state, no fee recipient
839+
suggestedVid := types.ValidatorIndex(1)
840+
slot := types.Slot(1)
841+
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
842+
hook := logTest.NewGlobal()
843+
hasPayload, attr, vId := service.getPayloadAttribute(ctx, st, slot)
844+
require.Equal(t, true, hasPayload)
845+
require.Equal(t, suggestedVid, vId)
846+
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
847+
require.LogsContain(t, hook, "Fee recipient is currently using the burn address")
848+
a, err := attr.Withdrawals()
818849
require.NoError(t, err)
850+
require.Equal(t, 0, len(a))
851+
852+
// Cache hit, advance state, has fee recipient
853+
suggestedAddr := common.HexToAddress("123")
854+
require.NoError(t, service.cfg.BeaconDB.SaveFeeRecipientsByValidatorIDs(ctx, []types.ValidatorIndex{suggestedVid}, []common.Address{suggestedAddr}))
855+
service.cfg.ProposerSlotIndexCache.SetProposerAndPayloadIDs(slot, suggestedVid, [8]byte{}, [32]byte{})
856+
hasPayload, attr, vId = service.getPayloadAttribute(ctx, st, slot)
819857
require.Equal(t, true, hasPayload)
820858
require.Equal(t, suggestedVid, vId)
821-
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient))
859+
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
860+
a, err = attr.Withdrawals()
861+
require.NoError(t, err)
862+
require.Equal(t, 0, len(a))
822863
}
823864

824865
func Test_UpdateLastValidatedCheckpoint(t *testing.T) {

beacon-chain/blockchain/receive_block_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func TestService_ReceiveBlock(t *testing.T) {
3333
assert.NoError(t, err)
3434
return blk
3535
}
36-
params.SetupTestConfigCleanupWithLock(t)
36+
//params.SetupTestConfigCleanupWithLock(t)
3737
bc := params.BeaconConfig().Copy()
3838
bc.ShardCommitteePeriod = 0 // Required for voluntary exits test in reasonable time.
3939
params.OverrideBeaconConfig(bc)

beacon-chain/execution/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ go_library(
4141
"//config/params:go_default_library",
4242
"//consensus-types/blocks:go_default_library",
4343
"//consensus-types/interfaces:go_default_library",
44+
"//consensus-types/payload-attribute:go_default_library",
4445
"//container/trie:go_default_library",
4546
"//contracts/deposit:go_default_library",
4647
"//crypto/hash:go_default_library",
@@ -52,6 +53,7 @@ go_library(
5253
"//network/authorization:go_default_library",
5354
"//proto/engine/v1:go_default_library",
5455
"//proto/prysm/v1alpha1:go_default_library",
56+
"//runtime/version:go_default_library",
5557
"//time:go_default_library",
5658
"//time/slots:go_default_library",
5759
"@com_github_ethereum_go_ethereum//:go_default_library",
@@ -108,6 +110,7 @@ go_test(
108110
"//config/params:go_default_library",
109111
"//consensus-types/blocks:go_default_library",
110112
"//consensus-types/interfaces:go_default_library",
113+
"//consensus-types/payload-attribute:go_default_library",
111114
"//consensus-types/primitives:go_default_library",
112115
"//container/trie:go_default_library",
113116
"//contracts/deposit:go_default_library",

beacon-chain/execution/engine_client.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ import (
1919
"github.com/prysmaticlabs/prysm/v3/config/params"
2020
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
2121
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
22+
payloadattribute "github.com/prysmaticlabs/prysm/v3/consensus-types/payload-attribute"
2223
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
2324
pb "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
25+
"github.com/prysmaticlabs/prysm/v3/runtime/version"
2426
"github.com/sirupsen/logrus"
2527
"go.opencensus.io/trace"
2628
)
@@ -30,6 +32,8 @@ const (
3032
NewPayloadMethod = "engine_newPayloadV1"
3133
// ForkchoiceUpdatedMethod v1 request string for JSON-RPC.
3234
ForkchoiceUpdatedMethod = "engine_forkchoiceUpdatedV1"
35+
// ForkchoiceUpdatedMethodV2 v2 request string for JSON-RPC.
36+
ForkchoiceUpdatedMethodV2 = "engine_forkchoiceUpdatedV2"
3337
// GetPayloadMethod v1 request string for JSON-RPC.
3438
GetPayloadMethod = "engine_getPayloadV1"
3539
// ExchangeTransitionConfigurationMethod v1 request string for JSON-RPC.
@@ -66,7 +70,7 @@ type ExecutionPayloadReconstructor interface {
6670
type EngineCaller interface {
6771
NewPayload(ctx context.Context, payload interfaces.ExecutionData) ([]byte, error)
6872
ForkchoiceUpdated(
69-
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
73+
ctx context.Context, state *pb.ForkchoiceState, attrs payloadattribute.Attributer,
7074
) (*pb.PayloadIDBytes, []byte, error)
7175
GetPayload(ctx context.Context, payloadId [8]byte) (*pb.ExecutionPayload, error)
7276
ExchangeTransitionConfiguration(
@@ -114,7 +118,7 @@ func (s *Service) NewPayload(ctx context.Context, payload interfaces.ExecutionDa
114118

115119
// ForkchoiceUpdated calls the engine_forkchoiceUpdatedV1 method via JSON-RPC.
116120
func (s *Service) ForkchoiceUpdated(
117-
ctx context.Context, state *pb.ForkchoiceState, attrs *pb.PayloadAttributes,
121+
ctx context.Context, state *pb.ForkchoiceState, attrs payloadattribute.Attributer,
118122
) (*pb.PayloadIDBytes, []byte, error) {
119123
ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.ForkchoiceUpdated")
120124
defer span.End()
@@ -127,9 +131,31 @@ func (s *Service) ForkchoiceUpdated(
127131
ctx, cancel := context.WithDeadline(ctx, d)
128132
defer cancel()
129133
result := &ForkchoiceUpdatedResponse{}
130-
err := s.rpcClient.CallContext(ctx, result, ForkchoiceUpdatedMethod, state, attrs)
131-
if err != nil {
132-
return nil, nil, handleRPCError(err)
134+
135+
if attrs == nil {
136+
return nil, nil, errors.New("nil payload attributer")
137+
}
138+
switch attrs.Version() {
139+
case version.Bellatrix:
140+
a, err := attrs.PbV1()
141+
if err != nil {
142+
return nil, nil, err
143+
}
144+
err = s.rpcClient.CallContext(ctx, result, ForkchoiceUpdatedMethod, state, a)
145+
if err != nil {
146+
return nil, nil, handleRPCError(err)
147+
}
148+
case version.Capella:
149+
a, err := attrs.PbV2()
150+
if err != nil {
151+
return nil, nil, err
152+
}
153+
err = s.rpcClient.CallContext(ctx, result, ForkchoiceUpdatedMethodV2, state, a)
154+
if err != nil {
155+
return nil, nil, handleRPCError(err)
156+
}
157+
default:
158+
return nil, nil, fmt.Errorf("unknown payload attribute version: %v", attrs.Version())
133159
}
134160

135161
if result.Status == nil {

0 commit comments

Comments
 (0)