From 8c1e180dd1802a631bc8c661a636fd7ea8863ddd Mon Sep 17 00:00:00 2001 From: Potuz Date: Tue, 2 Jan 2024 19:45:55 -0300 Subject: [PATCH] Simplify fcu 2 (#13400) * change getPayloadAttribute signature * Unify different FCU arguments --- beacon-chain/blockchain/execution_engine.go | 47 ++++---- .../blockchain/execution_engine_test.go | 103 +++++++++--------- .../blockchain/forkchoice_update_execution.go | 12 +- beacon-chain/blockchain/process_block.go | 10 +- time/slots/slottime.go | 9 ++ time/slots/slottime_test.go | 7 ++ 6 files changed, 101 insertions(+), 87 deletions(-) diff --git a/beacon-chain/blockchain/execution_engine.go b/beacon-chain/blockchain/execution_engine.go index ccce18442..564648a69 100644 --- a/beacon-chain/blockchain/execution_engine.go +++ b/beacon-chain/blockchain/execution_engine.go @@ -32,22 +32,18 @@ const blobCommitmentVersionKZG uint8 = 0x01 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: // 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. -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") 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() { log.Error("Head block is 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") return nil, nil } - pid, err := s.notifyForkchoiceUpdate(ctx, ¬ifyForkchoiceUpdateArg{ + pid, err := s.notifyForkchoiceUpdate(ctx, &fcuConfig{ headState: st, headRoot: r, - headBlock: b.Block(), + headBlock: b, attributes: arg.attributes, }) 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. // 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()) // 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 { val, ok = s.trackedProposer(st, slot) if !ok { - return false, emptyAttri + return emptyAttri } } 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) if err != nil { log.WithError(err).Error("Could not process slots to get payload attribute") - return false, emptyAttri + return emptyAttri } } if e > stateEpoch { + emptyAttri := payloadattribute.EmptyWithVersion(st.Version()) val, ok = s.trackedProposer(st, slot) if !ok { - return false, emptyAttri + return emptyAttri } } // Get previous randao. prevRando, err := helpers.RandaoMix(st, time.CurrentEpoch(st)) if err != nil { log.WithError(err).Error("Could not get randao mix to get payload attribute") - return false, emptyAttri + return emptyAttri } // Get timestamp. t, err := slots.ToTime(uint64(s.genesisTime.Unix()), slot) if err != nil { log.WithError(err).Error("Could not get timestamp to get payload attribute") - return false, emptyAttri + return emptyAttri } var attr payloadattribute.Attributer @@ -331,7 +328,7 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, withdrawals, err := st.ExpectedWithdrawals() if err != nil { log.WithError(err).Error("Could not get expected withdrawals to get payload attribute") - return false, emptyAttri + return emptyAttri } attr, err = payloadattribute.New(&enginev1.PayloadAttributesV3{ Timestamp: uint64(t.Unix()), @@ -342,13 +339,13 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, }) if err != nil { log.WithError(err).Error("Could not get payload attribute") - return false, emptyAttri + return emptyAttri } case version.Capella: withdrawals, err := st.ExpectedWithdrawals() if err != nil { log.WithError(err).Error("Could not get expected withdrawals to get payload attribute") - return false, emptyAttri + return emptyAttri } attr, err = payloadattribute.New(&enginev1.PayloadAttributesV2{ Timestamp: uint64(t.Unix()), @@ -358,7 +355,7 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, }) if err != nil { log.WithError(err).Error("Could not get payload attribute") - return false, emptyAttri + return emptyAttri } case version.Bellatrix: attr, err = payloadattribute.New(&enginev1.PayloadAttributes{ @@ -368,14 +365,14 @@ func (s *Service) getPayloadAttribute(ctx context.Context, st state.BeaconState, }) if err != nil { log.WithError(err).Error("Could not get payload attribute") - return false, emptyAttri + return emptyAttri } default: 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. diff --git a/beacon-chain/blockchain/execution_engine_test.go b/beacon-chain/blockchain/execution_engine_test.go index 5a54008cf..3c76db73b 100644 --- a/beacon-chain/blockchain/execution_engine_test.go +++ b/beacon-chain/blockchain/execution_engine_test.go @@ -56,11 +56,14 @@ func Test_NotifyForkchoiceUpdate_GetPayloadAttrErrorCanContinue(t *testing.T) { require.NoError(t, err) require.NoError(t, fcs.InsertNode(ctx, state, blkRoot)) - b, err := consensusblocks.NewBeaconBlock(ðpb.BeaconBlockBellatrix{ - Body: ðpb.BeaconBlockBodyBellatrix{ - ExecutionPayload: &v1.ExecutionPayload{}, + sb := ðpb.SignedBeaconBlockBellatrix{ + Block: ðpb.BeaconBlockBellatrix{ + Body: ðpb.BeaconBlockBodyBellatrix{ + ExecutionPayload: &v1.ExecutionPayload{}, + }, }, - }) + } + b, err := consensusblocks.NewSignedBeaconBlock(sb) require.NoError(t, err) 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` s, err := state_native.InitializeFromProtoPhase0(ðpb.BeaconState{}) require.NoError(t, err) - arg := ¬ifyForkchoiceUpdateArg{ + arg := &fcuConfig{ headState: s, headRoot: [32]byte{}, headBlock: b, @@ -113,7 +116,7 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) { tests := []struct { name string - blk interfaces.ReadOnlyBeaconBlock + blk interfaces.ReadOnlySignedBeaconBlock headRoot [32]byte finalizedRoot [32]byte justifiedRoot [32]byte @@ -122,24 +125,24 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) { }{ { name: "phase0 block", - blk: func() interfaces.ReadOnlyBeaconBlock { - b, err := consensusblocks.NewBeaconBlock(ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}) + blk: func() interfaces.ReadOnlySignedBeaconBlock { + b, err := consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlock{Block: ðpb.BeaconBlock{Body: ðpb.BeaconBlockBody{}}}) require.NoError(t, err) return b }(), }, { name: "altair block", - blk: func() interfaces.ReadOnlyBeaconBlock { - b, err := consensusblocks.NewBeaconBlock(ðpb.BeaconBlockAltair{Body: ðpb.BeaconBlockBodyAltair{}}) + blk: func() interfaces.ReadOnlySignedBeaconBlock { + b, err := consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockAltair{Block: ðpb.BeaconBlockAltair{Body: ðpb.BeaconBlockBodyAltair{}}}) require.NoError(t, err) return b }(), }, { name: "not execution block", - blk: func() interfaces.ReadOnlyBeaconBlock { - b, err := consensusblocks.NewBeaconBlock(ðpb.BeaconBlockBellatrix{ + blk: func() interfaces.ReadOnlySignedBeaconBlock { + b, err := consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: ðpb.BeaconBlockBellatrix{ Body: ðpb.BeaconBlockBodyBellatrix{ ExecutionPayload: &v1.ExecutionPayload{ ParentHash: make([]byte, fieldparams.RootLength), @@ -152,19 +155,19 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) { BlockHash: make([]byte, fieldparams.RootLength), }, }, - }) + }}) require.NoError(t, err) return b }(), }, { name: "happy case: finalized root is altair block", - blk: func() interfaces.ReadOnlyBeaconBlock { - b, err := consensusblocks.NewBeaconBlock(ðpb.BeaconBlockBellatrix{ + blk: func() interfaces.ReadOnlySignedBeaconBlock { + b, err := consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: ðpb.BeaconBlockBellatrix{ Body: ðpb.BeaconBlockBodyBellatrix{ ExecutionPayload: &v1.ExecutionPayload{}, }, - }) + }}) require.NoError(t, err) return b }(), @@ -173,12 +176,12 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) { }, { name: "happy case: finalized root is bellatrix block", - blk: func() interfaces.ReadOnlyBeaconBlock { - b, err := consensusblocks.NewBeaconBlock(ðpb.BeaconBlockBellatrix{ + blk: func() interfaces.ReadOnlySignedBeaconBlock { + b, err := consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: ðpb.BeaconBlockBellatrix{ Body: ðpb.BeaconBlockBodyBellatrix{ ExecutionPayload: &v1.ExecutionPayload{}, }, - }) + }}) require.NoError(t, err) return b }(), @@ -187,12 +190,12 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) { }, { name: "forkchoice updated with optimistic block", - blk: func() interfaces.ReadOnlyBeaconBlock { - b, err := consensusblocks.NewBeaconBlock(ðpb.BeaconBlockBellatrix{ + blk: func() interfaces.ReadOnlySignedBeaconBlock { + b, err := consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: ðpb.BeaconBlockBellatrix{ Body: ðpb.BeaconBlockBodyBellatrix{ ExecutionPayload: &v1.ExecutionPayload{}, }, - }) + }}) require.NoError(t, err) return b }(), @@ -202,12 +205,12 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) { }, { name: "forkchoice updated with invalid block", - blk: func() interfaces.ReadOnlyBeaconBlock { - b, err := consensusblocks.NewBeaconBlock(ðpb.BeaconBlockBellatrix{ + blk: func() interfaces.ReadOnlySignedBeaconBlock { + b, err := consensusblocks.NewSignedBeaconBlock(ðpb.SignedBeaconBlockBellatrix{Block: ðpb.BeaconBlockBellatrix{ Body: ðpb.BeaconBlockBodyBellatrix{ ExecutionPayload: &v1.ExecutionPayload{}, }, - }) + }}) require.NoError(t, err) return b }(), @@ -225,7 +228,7 @@ func Test_NotifyForkchoiceUpdate(t *testing.T) { st, _ := util.DeterministicGenesisState(t, 1) require.NoError(t, beaconDB.SaveState(ctx, st, tt.finalizedRoot)) require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, tt.finalizedRoot)) - arg := ¬ifyForkchoiceUpdateArg{ + arg := &fcuConfig{ headState: st, headRoot: tt.headRoot, 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.SaveGenesisBlockRoot(ctx, bra)) - a := ¬ifyForkchoiceUpdateArg{ + a := &fcuConfig{ headState: st, - headBlock: wbd.Block(), + headBlock: wbd, headRoot: brd, } _, 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.SaveGenesisBlockRoot(ctx, bra)) - a := ¬ifyForkchoiceUpdateArg{ + a := &fcuConfig{ headState: st, - headBlock: wbg.Block(), + headBlock: wbg, headRoot: brg, } _, err = service.notifyForkchoiceUpdate(ctx, a) @@ -780,23 +783,23 @@ func Test_GetPayloadAttribute(t *testing.T) { ctx := tr.ctx st, _ := util.DeterministicGenesisStateBellatrix(t, 1) - hasPayload, _ := service.getPayloadAttribute(ctx, st, 0, []byte{}) - require.Equal(t, false, hasPayload) + attr := service.getPayloadAttribute(ctx, st, 0, []byte{}) + require.Equal(t, true, attr.IsEmpty()) service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, Index: 0}) // Cache hit, advance state, no fee recipient slot := primitives.Slot(1) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) - hasPayload, attr := service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) - require.Equal(t, true, hasPayload) + attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) + require.Equal(t, false, attr.IsEmpty()) require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String()) // Cache hit, advance state, has fee recipient suggestedAddr := common.HexToAddress("123") service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, FeeRecipient: primitives.ExecutionAddress(suggestedAddr), Index: 0}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) - hasPayload, attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) - require.Equal(t, true, hasPayload) + attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) + require.Equal(t, false, attr.IsEmpty()) require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient())) } @@ -810,8 +813,8 @@ func Test_GetPayloadAttribute_PrepareAllPayloads(t *testing.T) { ctx := tr.ctx st, _ := util.DeterministicGenesisStateBellatrix(t, 1) - hasPayload, attr := service.getPayloadAttribute(ctx, st, 0, []byte{}) - require.Equal(t, true, hasPayload) + attr := service.getPayloadAttribute(ctx, st, 0, []byte{}) + require.Equal(t, false, attr.IsEmpty()) require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String()) } @@ -820,15 +823,15 @@ func Test_GetPayloadAttributeV2(t *testing.T) { ctx := tr.ctx st, _ := util.DeterministicGenesisStateCapella(t, 1) - hasPayload, _ := service.getPayloadAttribute(ctx, st, 0, []byte{}) - require.Equal(t, false, hasPayload) + attr := service.getPayloadAttribute(ctx, st, 0, []byte{}) + require.Equal(t, true, attr.IsEmpty()) // Cache hit, advance state, no fee recipient service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, Index: 0}) slot := primitives.Slot(1) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) - hasPayload, attr := service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) - require.Equal(t, true, hasPayload) + attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) + require.Equal(t, false, attr.IsEmpty()) require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String()) a, err := attr.Withdrawals() require.NoError(t, err) @@ -838,8 +841,8 @@ func Test_GetPayloadAttributeV2(t *testing.T) { suggestedAddr := common.HexToAddress("123") service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, FeeRecipient: primitives.ExecutionAddress(suggestedAddr), Index: 0}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) - hasPayload, attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) - require.Equal(t, true, hasPayload) + attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) + require.Equal(t, false, attr.IsEmpty()) require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient())) a, err = attr.Withdrawals() require.NoError(t, err) @@ -851,15 +854,15 @@ func Test_GetPayloadAttributeDeneb(t *testing.T) { ctx := tr.ctx st, _ := util.DeterministicGenesisStateDeneb(t, 1) - hasPayload, _ := service.getPayloadAttribute(ctx, st, 0, []byte{}) - require.Equal(t, false, hasPayload) + attr := service.getPayloadAttribute(ctx, st, 0, []byte{}) + require.Equal(t, true, attr.IsEmpty()) // Cache hit, advance state, no fee recipient slot := primitives.Slot(1) service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, Index: 0}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) - hasPayload, attr := service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) - require.Equal(t, true, hasPayload) + attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) + require.Equal(t, false, attr.IsEmpty()) require.Equal(t, params.BeaconConfig().EthBurnAddressHex, common.BytesToAddress(attr.SuggestedFeeRecipient()).String()) a, err := attr.Withdrawals() require.NoError(t, err) @@ -869,8 +872,8 @@ func Test_GetPayloadAttributeDeneb(t *testing.T) { suggestedAddr := common.HexToAddress("123") service.cfg.TrackedValidatorsCache.Set(cache.TrackedValidator{Active: true, FeeRecipient: primitives.ExecutionAddress(suggestedAddr), Index: 0}) service.cfg.PayloadIDCache.Set(slot, [32]byte{}, [8]byte{}) - hasPayload, attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) - require.Equal(t, true, hasPayload) + attr = service.getPayloadAttribute(ctx, st, slot, params.BeaconConfig().ZeroHash[:]) + require.Equal(t, false, attr.IsEmpty()) require.Equal(t, suggestedAddr, common.BytesToAddress(attr.SuggestedFeeRecipient())) a, err = attr.Withdrawals() require.NoError(t, err) diff --git a/beacon-chain/blockchain/forkchoice_update_execution.go b/beacon-chain/blockchain/forkchoice_update_execution.go index 88a968b5d..fec9ae4a2 100644 --- a/beacon-chain/blockchain/forkchoice_update_execution.go +++ b/beacon-chain/blockchain/forkchoice_update_execution.go @@ -11,6 +11,7 @@ import ( "github.com/prysmaticlabs/prysm/v4/config/features" "github.com/prysmaticlabs/prysm/v4/config/params" "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/time/slots" "github.com/sirupsen/logrus" @@ -49,6 +50,7 @@ type fcuConfig struct { headBlock interfaces.ReadOnlySignedBeaconBlock headRoot [32]byte proposingSlot primitives.Slot + attributes payloadattribute.Attributer } // 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() // Note: Use the service context here to avoid the parent context being ended during a forkchoice update. ctx = trace.NewContext(s.ctx, span) - fcuArgs := ¬ifyForkchoiceUpdateArg{ + fcuArgs := &fcuConfig{ headState: args.headState, headRoot: args.headRoot, - headBlock: args.headBlock.Block(), + headBlock: args.headBlock, } _, tracked := s.trackedProposer(args.headState, args.proposingSlot) if tracked && !features.Get().DisableReorgLateBlocks { if s.shouldOverrideFCU(args.headRoot, args.proposingSlot) { return nil } - var has bool - has, fcuArgs.attributes = s.getPayloadAttribute(ctx, args.headState, args.proposingSlot, args.headRoot[:]) - if !has { - log.Error("could not get payload attributes for tracked proposer") - } + fcuArgs.attributes = s.getPayloadAttribute(ctx, args.headState, args.proposingSlot, args.headRoot[:]) } _, err := s.notifyForkchoiceUpdate(ctx, fcuArgs) if err != nil { diff --git a/beacon-chain/blockchain/process_block.go b/beacon-chain/blockchain/process_block.go index fd8d705cd..ad20f91df 100644 --- a/beacon-chain/blockchain/process_block.go +++ b/beacon-chain/blockchain/process_block.go @@ -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") } } - arg := ¬ifyForkchoiceUpdateArg{ + arg := &fcuConfig{ headState: preState, headRoot: lastBR, - headBlock: lastB.Block(), + headBlock: lastB, } if _, err := s.notifyForkchoiceUpdate(ctx, arg); err != nil { return err @@ -711,12 +711,12 @@ func (s *Service) lateBlockTasks(ctx context.Context) { } s.headLock.RUnlock() s.cfg.ForkChoiceStore.RLock() - fcuArgs := ¬ifyForkchoiceUpdateArg{ + fcuArgs := &fcuConfig{ headState: headState, 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) s.cfg.ForkChoiceStore.RUnlock() if err != nil { diff --git a/time/slots/slottime.go b/time/slots/slottime.go index 3ace1b97a..61bea59c7 100644 --- a/time/slots/slottime.go +++ b/time/slots/slottime.go @@ -16,6 +16,9 @@ import ( // incoming objects. (24 mins with mainnet spec) 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 func startFromTime(genesis time.Time, slot primitives.Slot) time.Time { 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 { 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 +} diff --git a/time/slots/slottime_test.go b/time/slots/slottime_test.go index cb8271eb1..42bc79466 100644 --- a/time/slots/slottime_test.go +++ b/time/slots/slottime_test.go @@ -600,3 +600,10 @@ func TestTimeIntoSlot(t *testing.T) { require.Equal(t, true, TimeIntoSlot(genesisTime) > 900*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)) +}