Simplify fcu 2 (#13400)

* change getPayloadAttribute signature

* Unify different FCU arguments
This commit is contained in:
Potuz 2024-01-02 19:45:55 -03:00 committed by GitHub
parent 886d76fe7c
commit 8c1e180dd1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 87 deletions

View File

@ -32,22 +32,18 @@ const blobCommitmentVersionKZG uint8 = 0x01
var defaultLatestValidHash = bytesutil.PadTo([]byte{0xff}, 32) var defaultLatestValidHash = bytesutil.PadTo([]byte{0xff}, 32)
// notifyForkchoiceUpdateArg is the argument for the forkchoice update notification `notifyForkchoiceUpdate`.
type notifyForkchoiceUpdateArg struct {
headState state.BeaconState
headRoot [32]byte
headBlock interfaces.ReadOnlyBeaconBlock
attributes payloadattribute.Attributer
}
// notifyForkchoiceUpdate signals execution engine the fork choice updates. Execution engine should: // notifyForkchoiceUpdate signals execution engine the fork choice updates. Execution engine should:
// 1. Re-organizes the execution payload chain and corresponding state to make head_block_hash the head. // 1. Re-organizes the execution payload chain and corresponding state to make head_block_hash the head.
// 2. Applies finality to the execution state: it irreversibly persists the chain of all execution payloads and corresponding state, up to and including finalized_block_hash. // 2. Applies finality to the execution state: it irreversibly persists the chain of all execution payloads and corresponding state, up to and including finalized_block_hash.
func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkchoiceUpdateArg) (*enginev1.PayloadIDBytes, error) { func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *fcuConfig) (*enginev1.PayloadIDBytes, error) {
ctx, span := trace.StartSpan(ctx, "blockChain.notifyForkchoiceUpdate") ctx, span := trace.StartSpan(ctx, "blockChain.notifyForkchoiceUpdate")
defer span.End() defer span.End()
headBlk := arg.headBlock if arg.headBlock.IsNil() {
log.Error("Head block is nil")
return nil, nil
}
headBlk := arg.headBlock.Block()
if headBlk == nil || headBlk.IsNil() || headBlk.Body().IsNil() { if headBlk == nil || headBlk.IsNil() || headBlk.Body().IsNil() {
log.Error("Head block is nil") log.Error("Head block is nil")
return nil, nil return nil, nil
@ -122,10 +118,10 @@ func (s *Service) notifyForkchoiceUpdate(ctx context.Context, arg *notifyForkcho
log.WithError(err).Error("Could not get head state") log.WithError(err).Error("Could not get head state")
return nil, nil return nil, nil
} }
pid, err := s.notifyForkchoiceUpdate(ctx, &notifyForkchoiceUpdateArg{ pid, err := s.notifyForkchoiceUpdate(ctx, &fcuConfig{
headState: st, headState: st,
headRoot: r, headRoot: r,
headBlock: b.Block(), headBlock: b,
attributes: arg.attributes, attributes: arg.attributes,
}) })
if err != nil { if err != nil {
@ -280,7 +276,7 @@ func (s *Service) pruneInvalidBlock(ctx context.Context, root, parentRoot, lvh [
// getPayloadAttributes returns the payload attributes for the given state and slot. // getPayloadAttributes returns the payload attributes for the given state and slot.
// The attribute is required to initiate a payload build process in the context of an `engine_forkchoiceUpdated` call. // The attribute is required to initiate a payload build process in the context of an `engine_forkchoiceUpdated` call.
func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot primitives.Slot, headRoot []byte) (bool, payloadattribute.Attributer) { func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, slot primitives.Slot, headRoot []byte) payloadattribute.Attributer {
emptyAttri := payloadattribute.EmptyWithVersion(st.Version()) emptyAttri := payloadattribute.EmptyWithVersion(st.Version())
// If it is an epoch boundary then process slots to get the right // If it is an epoch boundary then process slots to get the right
@ -293,7 +289,7 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
if e == stateEpoch { if e == stateEpoch {
val, ok = s.trackedProposer(st, slot) val, ok = s.trackedProposer(st, slot)
if !ok { if !ok {
return false, emptyAttri return emptyAttri
} }
} }
st = st.Copy() st = st.Copy()
@ -302,27 +298,28 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
st, err = transition.ProcessSlotsUsingNextSlotCache(ctx, st, headRoot, slot) st, err = transition.ProcessSlotsUsingNextSlotCache(ctx, st, headRoot, slot)
if err != nil { if err != nil {
log.WithError(err).Error("Could not process slots to get payload attribute") log.WithError(err).Error("Could not process slots to get payload attribute")
return false, emptyAttri return emptyAttri
} }
} }
if e > stateEpoch { if e > stateEpoch {
emptyAttri := payloadattribute.EmptyWithVersion(st.Version())
val, ok = s.trackedProposer(st, slot) val, ok = s.trackedProposer(st, slot)
if !ok { if !ok {
return false, emptyAttri return emptyAttri
} }
} }
// Get previous randao. // Get previous randao.
prevRando, err := helpers.RandaoMix(st, time.CurrentEpoch(st)) prevRando, err := helpers.RandaoMix(st, time.CurrentEpoch(st))
if err != nil { if err != nil {
log.WithError(err).Error("Could not get randao mix to get payload attribute") log.WithError(err).Error("Could not get randao mix to get payload attribute")
return false, emptyAttri return emptyAttri
} }
// Get timestamp. // Get timestamp.
t, err := slots.ToTime(uint64(s.genesisTime.Unix()), slot) t, err := slots.ToTime(uint64(s.genesisTime.Unix()), slot)
if err != nil { if err != nil {
log.WithError(err).Error("Could not get timestamp to get payload attribute") log.WithError(err).Error("Could not get timestamp to get payload attribute")
return false, emptyAttri return emptyAttri
} }
var attr payloadattribute.Attributer var attr payloadattribute.Attributer
@ -331,7 +328,7 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
withdrawals, err := st.ExpectedWithdrawals() withdrawals, err := st.ExpectedWithdrawals()
if err != nil { if err != nil {
log.WithError(err).Error("Could not get expected withdrawals to get payload attribute") log.WithError(err).Error("Could not get expected withdrawals to get payload attribute")
return false, emptyAttri return emptyAttri
} }
attr, err = payloadattribute.New(&enginev1.PayloadAttributesV3{ attr, err = payloadattribute.New(&enginev1.PayloadAttributesV3{
Timestamp: uint64(t.Unix()), Timestamp: uint64(t.Unix()),
@ -342,13 +339,13 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
}) })
if err != nil { if err != nil {
log.WithError(err).Error("Could not get payload attribute") log.WithError(err).Error("Could not get payload attribute")
return false, emptyAttri return emptyAttri
} }
case version.Capella: case version.Capella:
withdrawals, err := st.ExpectedWithdrawals() withdrawals, err := st.ExpectedWithdrawals()
if err != nil { if err != nil {
log.WithError(err).Error("Could not get expected withdrawals to get payload attribute") log.WithError(err).Error("Could not get expected withdrawals to get payload attribute")
return false, emptyAttri return emptyAttri
} }
attr, err = payloadattribute.New(&enginev1.PayloadAttributesV2{ attr, err = payloadattribute.New(&enginev1.PayloadAttributesV2{
Timestamp: uint64(t.Unix()), Timestamp: uint64(t.Unix()),
@ -358,7 +355,7 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
}) })
if err != nil { if err != nil {
log.WithError(err).Error("Could not get payload attribute") log.WithError(err).Error("Could not get payload attribute")
return false, emptyAttri return emptyAttri
} }
case version.Bellatrix: case version.Bellatrix:
attr, err = payloadattribute.New(&enginev1.PayloadAttributes{ attr, err = payloadattribute.New(&enginev1.PayloadAttributes{
@ -368,14 +365,14 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState,
}) })
if err != nil { if err != nil {
log.WithError(err).Error("Could not get payload attribute") log.WithError(err).Error("Could not get payload attribute")
return false, emptyAttri return emptyAttri
} }
default: default:
log.WithField("version", st.Version()).Error("Could not get payload attribute due to unknown state version") log.WithField("version", st.Version()).Error("Could not get payload attribute due to unknown state version")
return false, emptyAttri return emptyAttri
} }
return true, attr return attr
} }
// removeInvalidBlockAndState removes the invalid block, blob and its corresponding state from the cache and DB. // removeInvalidBlockAndState removes the invalid block, blob and its corresponding state from the cache and DB.

View File

@ -56,11 +56,14 @@ func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, fcs.InsertNode(ctx, state, blkRoot)) require.NoError(t, fcs.InsertNode(ctx, state, blkRoot))
b, err := consensusblocks.NewBeaconBlock(&ethpb.BeaconBlockBellatrix{ sb := &ethpb.SignedBeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{ Block: &ethpb.BeaconBlockBellatrix{
ExecutionPayload: &v1.ExecutionPayload{}, Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{},
},
}, },
}) }
b, err := consensusblocks.NewSignedBeaconBlock(sb)
require.NoError(t, err) require.NoError(t, err)
pid := &v1.PayloadIDBytes{1} pid := &v1.PayloadIDBytes{1}
@ -72,7 +75,7 @@ func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) {
// Intentionally generate a bad state such that `hash_tree_root` fails during `process_slot` // Intentionally generate a bad state such that `hash_tree_root` fails during `process_slot`
s, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{}) s, err := state_native.InitializeFromProtoPhase0(&ethpb.BeaconState{})
require.NoError(t, err) require.NoError(t, err)
arg := &notifyForkchoiceUpdateArg{ arg := &fcuConfig{
headState: s, headState: s,
headRoot: [32]byte{}, headRoot: [32]byte{},
headBlock: b, headBlock: b,
@ -113,7 +116,7 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
blk interfaces.ReadOnlyBeaconBlock blk interfaces.ReadOnlySignedBeaconBlock
headRoot [32]byte headRoot [32]byte
finalizedRoot [32]byte finalizedRoot [32]byte
justifiedRoot [32]byte justifiedRoot [32]byte
@ -122,24 +125,24 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
}{ }{
{ {
name: "phase0 block", name: "phase0 block",
blk: func() interfaces.ReadOnlyBeaconBlock { blk: func() interfaces.ReadOnlySignedBeaconBlock {
b, err := consensusblocks.NewBeaconBlock(&ethpb.BeaconBlock{Body: &ethpb.BeaconBlockBody{}}) b, err := consensusblocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlock{Block: &ethpb.BeaconBlock{Body: &ethpb.BeaconBlockBody{}}})
require.NoError(t, err) require.NoError(t, err)
return b return b
}(), }(),
}, },
{ {
name: "altair block", name: "altair block",
blk: func() interfaces.ReadOnlyBeaconBlock { blk: func() interfaces.ReadOnlySignedBeaconBlock {
b, err := consensusblocks.NewBeaconBlock(&ethpb.BeaconBlockAltair{Body: &ethpb.BeaconBlockBodyAltair{}}) b, err := consensusblocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockAltair{Block: &ethpb.BeaconBlockAltair{Body: &ethpb.BeaconBlockBodyAltair{}}})
require.NoError(t, err) require.NoError(t, err)
return b return b
}(), }(),
}, },
{ {
name: "not execution block", name: "not execution block",
blk: func() interfaces.ReadOnlyBeaconBlock { blk: func() interfaces.ReadOnlySignedBeaconBlock {
b, err := consensusblocks.NewBeaconBlock(&ethpb.BeaconBlockBellatrix{ b, err := consensusblocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockBellatrix{Block: &ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{ Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{ ExecutionPayload: &v1.ExecutionPayload{
ParentHash: make([]byte, fieldparams.RootLength), ParentHash: make([]byte, fieldparams.RootLength),
@ -152,19 +155,19 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
BlockHash: make([]byte, fieldparams.RootLength), BlockHash: make([]byte, fieldparams.RootLength),
}, },
}, },
}) }})
require.NoError(t, err) require.NoError(t, err)
return b return b
}(), }(),
}, },
{ {
name: "happy case: finalized root is altair block", name: "happy case: finalized root is altair block",
blk: func() interfaces.ReadOnlyBeaconBlock { blk: func() interfaces.ReadOnlySignedBeaconBlock {
b, err := consensusblocks.NewBeaconBlock(&ethpb.BeaconBlockBellatrix{ b, err := consensusblocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockBellatrix{Block: &ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{ Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{}, ExecutionPayload: &v1.ExecutionPayload{},
}, },
}) }})
require.NoError(t, err) require.NoError(t, err)
return b return b
}(), }(),
@ -173,12 +176,12 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
}, },
{ {
name: "happy case: finalized root is bellatrix block", name: "happy case: finalized root is bellatrix block",
blk: func() interfaces.ReadOnlyBeaconBlock { blk: func() interfaces.ReadOnlySignedBeaconBlock {
b, err := consensusblocks.NewBeaconBlock(&ethpb.BeaconBlockBellatrix{ b, err := consensusblocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockBellatrix{Block: &ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{ Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{}, ExecutionPayload: &v1.ExecutionPayload{},
}, },
}) }})
require.NoError(t, err) require.NoError(t, err)
return b return b
}(), }(),
@ -187,12 +190,12 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
}, },
{ {
name: "forkchoice updated with optimistic block", name: "forkchoice updated with optimistic block",
blk: func() interfaces.ReadOnlyBeaconBlock { blk: func() interfaces.ReadOnlySignedBeaconBlock {
b, err := consensusblocks.NewBeaconBlock(&ethpb.BeaconBlockBellatrix{ b, err := consensusblocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockBellatrix{Block: &ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{ Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{}, ExecutionPayload: &v1.ExecutionPayload{},
}, },
}) }})
require.NoError(t, err) require.NoError(t, err)
return b return b
}(), }(),
@ -202,12 +205,12 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
}, },
{ {
name: "forkchoice updated with invalid block", name: "forkchoice updated with invalid block",
blk: func() interfaces.ReadOnlyBeaconBlock { blk: func() interfaces.ReadOnlySignedBeaconBlock {
b, err := consensusblocks.NewBeaconBlock(&ethpb.BeaconBlockBellatrix{ b, err := consensusblocks.NewSignedBeaconBlock(&ethpb.SignedBeaconBlockBellatrix{Block: &ethpb.BeaconBlockBellatrix{
Body: &ethpb.BeaconBlockBodyBellatrix{ Body: &ethpb.BeaconBlockBodyBellatrix{
ExecutionPayload: &v1.ExecutionPayload{}, ExecutionPayload: &v1.ExecutionPayload{},
}, },
}) }})
require.NoError(t, err) require.NoError(t, err)
return b return b
}(), }(),
@ -225,7 +228,7 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) {
st, _ := util.DeterministicGenesisState(t, 1) st, _ := util.DeterministicGenesisState(t, 1)
require.NoError(t, beaconDB.SaveState(ctx, st, tt.finalizedRoot)) require.NoError(t, beaconDB.SaveState(ctx, st, tt.finalizedRoot))
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, tt.finalizedRoot)) require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, tt.finalizedRoot))
arg := &notifyForkchoiceUpdateArg{ arg := &fcuConfig{
headState: st, headState: st,
headRoot: tt.headRoot, headRoot: tt.headRoot,
headBlock: tt.blk, headBlock: tt.blk,
@ -305,9 +308,9 @@ func Test_NotifyForkchoiceUpdate_NIlLVH(t *testing.T) {
require.NoError(t, beaconDB.SaveState(ctx, st, bra)) require.NoError(t, beaconDB.SaveState(ctx, st, bra))
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bra)) require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bra))
a := &notifyForkchoiceUpdateArg{ a := &fcuConfig{
headState: st, headState: st,
headBlock: wbd.Block(), headBlock: wbd,
headRoot: brd, headRoot: brd,
} }
_, err = service.notifyForkchoiceUpdate(ctx, a) _, err = service.notifyForkchoiceUpdate(ctx, a)
@ -442,9 +445,9 @@ func Test_NotifyForkchoiceUpdateRecursive_DoublyLinkedTree(t *testing.T) {
require.NoError(t, beaconDB.SaveState(ctx, st, bra)) require.NoError(t, beaconDB.SaveState(ctx, st, bra))
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bra)) require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, bra))
a := &notifyForkchoiceUpdateArg{ a := &fcuConfig{
headState: st, headState: st,
headBlock: wbg.Block(), headBlock: wbg,
headRoot: brg, headRoot: brg,
} }
_, err = service.notifyForkchoiceUpdate(ctx, a) _, err = service.notifyForkchoiceUpdate(ctx, a)
@ -780,23 +783,23 @@ func Test_GetPayloadAttribute(t *testing.T) {
ctx := tr.ctx ctx := tr.ctx
st, _ := util.DeterministicGenesisStateBellatrix(t, 1) st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
hasPayload, _ := service.getPayloadAttribute(ctx, st, 0, []byte{}) attr := service.getPayloadAttribute(ctx, st, 0, []byte{})
require.Equal(t, false, hasPayload) require.Equal(t, true, attr.IsEmpty())
service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, Index: 0}) service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, Index: 0})
// Cache hit, advance state, no fee recipient // Cache hit, advance state, no fee recipient
slot := primitives.Slot(1) slot := primitives.Slot(1)
service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{})
hasPayload, attr := service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:])
require.Equal(t, true, hasPayload) require.Equal(t, false, attr.IsEmpty())
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String()) require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
// Cache hit, advance state, has fee recipient // Cache hit, advance state, has fee recipient
suggestedAddr := common.HexToAddress("123") suggestedAddr := common.HexToAddress("123")
service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, FeeRecipient: primitives.ExecutionAddress(suggestedAddr), Index: 0}) service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, FeeRecipient: primitives.ExecutionAddress(suggestedAddr), Index: 0})
service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{})
hasPayload, attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:])
require.Equal(t, true, hasPayload) require.Equal(t, false, attr.IsEmpty())
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient())) require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
} }
@ -810,8 +813,8 @@ func Test_GetPayloadAttribute_PrepareAllPayloads(t *testing.T) {
ctx := tr.ctx ctx := tr.ctx
st, _ := util.DeterministicGenesisStateBellatrix(t, 1) st, _ := util.DeterministicGenesisStateBellatrix(t, 1)
hasPayload, attr := service.getPayloadAttribute(ctx, st, 0, []byte{}) attr := service.getPayloadAttribute(ctx, st, 0, []byte{})
require.Equal(t, true, hasPayload) require.Equal(t, false, attr.IsEmpty())
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String()) require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
} }
@ -820,15 +823,15 @@ func Test_GetPayloadAttributeV2(t *testing.T) {
ctx := tr.ctx ctx := tr.ctx
st, _ := util.DeterministicGenesisStateCapella(t, 1) st, _ := util.DeterministicGenesisStateCapella(t, 1)
hasPayload, _ := service.getPayloadAttribute(ctx, st, 0, []byte{}) attr := service.getPayloadAttribute(ctx, st, 0, []byte{})
require.Equal(t, false, hasPayload) require.Equal(t, true, attr.IsEmpty())
// Cache hit, advance state, no fee recipient // Cache hit, advance state, no fee recipient
service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, Index: 0}) service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, Index: 0})
slot := primitives.Slot(1) slot := primitives.Slot(1)
service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{})
hasPayload, attr := service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:])
require.Equal(t, true, hasPayload) require.Equal(t, false, attr.IsEmpty())
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String()) require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
a, err := attr.Withdrawals() a, err := attr.Withdrawals()
require.NoError(t, err) require.NoError(t, err)
@ -838,8 +841,8 @@ func Test_GetPayloadAttributeV2(t *testing.T) {
suggestedAddr := common.HexToAddress("123") suggestedAddr := common.HexToAddress("123")
service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, FeeRecipient: primitives.ExecutionAddress(suggestedAddr), Index: 0}) service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, FeeRecipient: primitives.ExecutionAddress(suggestedAddr), Index: 0})
service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{})
hasPayload, attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:])
require.Equal(t, true, hasPayload) require.Equal(t, false, attr.IsEmpty())
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient())) require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
a, err = attr.Withdrawals() a, err = attr.Withdrawals()
require.NoError(t, err) require.NoError(t, err)
@ -851,15 +854,15 @@ func Test_GetPayloadAttributeDeneb(t *testing.T) {
ctx := tr.ctx ctx := tr.ctx
st, _ := util.DeterministicGenesisStateDeneb(t, 1) st, _ := util.DeterministicGenesisStateDeneb(t, 1)
hasPayload, _ := service.getPayloadAttribute(ctx, st, 0, []byte{}) attr := service.getPayloadAttribute(ctx, st, 0, []byte{})
require.Equal(t, false, hasPayload) require.Equal(t, true, attr.IsEmpty())
// Cache hit, advance state, no fee recipient // Cache hit, advance state, no fee recipient
slot := primitives.Slot(1) slot := primitives.Slot(1)
service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, Index: 0}) service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, Index: 0})
service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{})
hasPayload, attr := service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:])
require.Equal(t, true, hasPayload) require.Equal(t, false, attr.IsEmpty())
require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String()) require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String())
a, err := attr.Withdrawals() a, err := attr.Withdrawals()
require.NoError(t, err) require.NoError(t, err)
@ -869,8 +872,8 @@ func Test_GetPayloadAttributeDeneb(t *testing.T) {
suggestedAddr := common.HexToAddress("123") suggestedAddr := common.HexToAddress("123")
service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, FeeRecipient: primitives.ExecutionAddress(suggestedAddr), Index: 0}) service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, FeeRecipient: primitives.ExecutionAddress(suggestedAddr), Index: 0})
service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{})
hasPayload, attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:])
require.Equal(t, true, hasPayload) require.Equal(t, false, attr.IsEmpty())
require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient())) require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient()))
a, err = attr.Withdrawals() a, err = attr.Withdrawals()
require.NoError(t, err) require.NoError(t, err)

View File

@ -11,6 +11,7 @@ import (
"github.com/prysmaticlabs/prysm/v4/config/features" "github.com/prysmaticlabs/prysm/v4/config/features"
"github.com/prysmaticlabs/prysm/v4/config/params" "github.com/prysmaticlabs/prysm/v4/config/params"
"github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces" "github.com/prysmaticlabs/prysm/v4/consensus-types/interfaces"
payloadattribute "github.com/prysmaticlabs/prysm/v4/consensus-types/payload-attribute"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives" "github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v4/time/slots" "github.com/prysmaticlabs/prysm/v4/time/slots"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -49,6 +50,7 @@ type fcuConfig struct {
headBlock interfaces.ReadOnlySignedBeaconBlock headBlock interfaces.ReadOnlySignedBeaconBlock
headRoot [32]byte headRoot [32]byte
proposingSlot primitives.Slot proposingSlot primitives.Slot
attributes payloadattribute.Attributer
} }
// fockchoiceUpdateWithExecution is a wrapper around notifyForkchoiceUpdate. It decides whether a new call to FCU should be made. // fockchoiceUpdateWithExecution is a wrapper around notifyForkchoiceUpdate. It decides whether a new call to FCU should be made.
@ -57,21 +59,17 @@ func (s *Service) forkchoiceUpdateWithExecution(ctx context.Context, args *fcuCo
defer span.End() defer span.End()
// Note: Use the service context here to avoid the parent context being ended during a forkchoice update. // Note: Use the service context here to avoid the parent context being ended during a forkchoice update.
ctx = trace.NewContext(s.ctx, span) ctx = trace.NewContext(s.ctx, span)
fcuArgs := &notifyForkchoiceUpdateArg{ fcuArgs := &fcuConfig{
headState: args.headState, headState: args.headState,
headRoot: args.headRoot, headRoot: args.headRoot,
headBlock: args.headBlock.Block(), headBlock: args.headBlock,
} }
_, tracked := s.trackedProposer(args.headState, args.proposingSlot) _, tracked := s.trackedProposer(args.headState, args.proposingSlot)
if tracked && !features.Get().DisableReorgLateBlocks { if tracked && !features.Get().DisableReorgLateBlocks {
if s.shouldOverrideFCU(args.headRoot, args.proposingSlot) { if s.shouldOverrideFCU(args.headRoot, args.proposingSlot) {
return nil return nil
} }
var has bool fcuArgs.attributes = s.getPayloadAttribute(ctx, args.headState, args.proposingSlot, args.headRoot[:])
has, fcuArgs.attributes = s.getPayloadAttribute(ctx, args.headState, args.proposingSlot, args.headRoot[:])
if !has {
log.Error("could not get payload attributes for tracked proposer")
}
} }
_, err := s.notifyForkchoiceUpdate(ctx, fcuArgs) _, err := s.notifyForkchoiceUpdate(ctx, fcuArgs)
if err != nil { if err != nil {

View File

@ -342,10 +342,10 @@ func (s *Service) onBlockBatch(ctx context.Context, blks []consensusblocks.ROBlo
return errors.Wrap(err, "could not set optimistic block to valid") return errors.Wrap(err, "could not set optimistic block to valid")
} }
} }
arg := &notifyForkchoiceUpdateArg{ arg := &fcuConfig{
headState: preState, headState: preState,
headRoot: lastBR, headRoot: lastBR,
headBlock: lastB.Block(), headBlock: lastB,
} }
if _, err := s.notifyForkchoiceUpdate(ctx, arg); err != nil { if _, err := s.notifyForkchoiceUpdate(ctx, arg); err != nil {
return err return err
@ -711,12 +711,12 @@ func (s *Service) lateBlockTasks(ctx context.Context) {
} }
s.headLock.RUnlock() s.headLock.RUnlock()
s.cfg.ForkChoiceStore.RLock() s.cfg.ForkChoiceStore.RLock()
fcuArgs := &notifyForkchoiceUpdateArg{ fcuArgs := &fcuConfig{
headState: headState, headState: headState,
headRoot: headRoot, headRoot: headRoot,
headBlock: headBlock.Block(), headBlock: headBlock,
} }
_, fcuArgs.attributes = s.getPayloadAttribute(ctx, headState, s.CurrentSlot()+1, headRoot[:]) fcuArgs.attributes = s.getPayloadAttribute(ctx, headState, s.CurrentSlot()+1, headRoot[:])
_, err = s.notifyForkchoiceUpdate(ctx, fcuArgs) _, err = s.notifyForkchoiceUpdate(ctx, fcuArgs)
s.cfg.ForkChoiceStore.RUnlock() s.cfg.ForkChoiceStore.RUnlock()
if err != nil { if err != nil {

View File

@ -16,6 +16,9 @@ import (
// incoming objects. (24 mins with mainnet spec) // incoming objects. (24 mins with mainnet spec)
const MaxSlotBuffer = uint64(1 << 7) const MaxSlotBuffer = uint64(1 << 7)
// votingWindow specifies the deadline for attestations
var votingWindow = params.BeaconConfig().SecondsPerSlot / params.BeaconConfig().IntervalsPerSlot
// startFromTime returns the slot start in terms of genesis time.Time // startFromTime returns the slot start in terms of genesis time.Time
func startFromTime(genesis time.Time, slot primitives.Slot) time.Time { func startFromTime(genesis time.Time, slot primitives.Slot) time.Time {
duration := time.Second * time.Duration(slot.Mul(params.BeaconConfig().SecondsPerSlot)) duration := time.Second * time.Duration(slot.Mul(params.BeaconConfig().SecondsPerSlot))
@ -264,3 +267,9 @@ func SecondsSinceSlotStart(s primitives.Slot, genesisTime, timeStamp uint64) (ui
func TimeIntoSlot(genesisTime uint64) time.Duration { func TimeIntoSlot(genesisTime uint64) time.Duration {
return time.Since(StartTime(genesisTime, CurrentSlot(genesisTime))) return time.Since(StartTime(genesisTime, CurrentSlot(genesisTime)))
} }
// WithinVotingWindow returns whether the current time is within the voting window
// (eg. 4 seconds on mainnet) of the current slot.
func WithinVotingWindow(genesisTime uint64) bool {
return TimeIntoSlot(genesisTime) < time.Duration(votingWindow)*time.Second
}

View File

@ -600,3 +600,10 @@ func TestTimeIntoSlot(t *testing.T) {
require.Equal(t, true, TimeIntoSlot(genesisTime) > 900*time.Millisecond) require.Equal(t, true, TimeIntoSlot(genesisTime) > 900*time.Millisecond)
require.Equal(t, true, TimeIntoSlot(genesisTime) < 3000*time.Millisecond) require.Equal(t, true, TimeIntoSlot(genesisTime) < 3000*time.Millisecond)
} }
func TestWithinVotingWindow(t *testing.T) {
genesisTime := uint64(time.Now().Add(-37 * time.Second).Unix())
require.Equal(t, true, WithinVotingWindow(genesisTime))
genesisTime = uint64(time.Now().Add(-40 * time.Second).Unix())
require.Equal(t, false, WithinVotingWindow(genesisTime))
}