Compare commits

...

1 Commits

Author SHA1 Message Date
terence tsao
e70a7de477 Event data use cached proposer index 2025-04-27 08:59:30 -07:00
2 changed files with 49 additions and 29 deletions

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/binary"
"fmt"
"github.com/OffchainLabs/prysm/v6/beacon-chain/cache"
"github.com/OffchainLabs/prysm/v6/beacon-chain/core/time"
@@ -299,9 +300,12 @@ func ProposerIndexAtSlotFromCheckpoint(c *forkchoicetypes.Checkpoint, slot primi
// BeaconProposerIndexAtSlot returns proposer index at the given slot from the
// point of view of the given state as head state
func BeaconProposerIndexAtSlot(ctx context.Context, state state.ReadOnlyBeaconState, slot primitives.Slot) (primitives.ValidatorIndex, error) {
pid, err := GetCachedProposerIndex(state, slot)
if err == nil {
return pid, nil
}
e := slots.ToEpoch(slot)
// The cache uses the state root of the previous epoch - minimum_seed_lookahead last slot as key. (e.g. Starting epoch 1, slot 32, the key would be block root at slot 31)
// For simplicity, the node will skip caching of genesis epoch.
if e > params.BeaconConfig().GenesisEpoch+params.BeaconConfig().MinSeedLookahead {
s, err := slots.EpochEnd(e - 1)
if err != nil {
@@ -312,14 +316,10 @@ func BeaconProposerIndexAtSlot(ctx context.Context, state state.ReadOnlyBeaconSt
return 0, err
}
if r != nil && !bytes.Equal(r, params.BeaconConfig().ZeroHash[:]) {
pid, err := cachedProposerIndexAtSlot(slot, [32]byte(r))
if err == nil {
return pid, nil
}
if err := UpdateProposerIndicesInCache(ctx, state, e); err != nil {
return 0, errors.Wrap(err, "could not update proposer index cache")
}
pid, err = cachedProposerIndexAtSlot(slot, [32]byte(r))
pid, err := cachedProposerIndexAtSlot(slot, [32]byte(r))
if err == nil {
return pid, nil
}
@@ -342,6 +342,34 @@ func BeaconProposerIndexAtSlot(ctx context.Context, state state.ReadOnlyBeaconSt
return ComputeProposerIndex(state, indices, seedWithSlotHash)
}
var ErrProposerNotFound = errors.New("invalid nil or unknown node")
func GetCachedProposerIndex(state state.ReadOnlyBeaconState, slot primitives.Slot) (primitives.ValidatorIndex, error) {
epoch := slots.ToEpoch(slot)
if epoch <= params.BeaconConfig().GenesisEpoch+params.BeaconConfig().MinSeedLookahead {
return 0, fmt.Errorf("epoch %d is too early to get cached proposer index", epoch)
}
endSlot, err := slots.EpochEnd(epoch - 1)
if err != nil {
return 0, err
}
root, err := StateRootAtSlot(state, endSlot)
if err != nil {
return 0, err
}
if root == nil || bytes.Equal(root, params.BeaconConfig().ZeroHash[:]) {
return 0, ErrProposerNotFound
}
proposerIndex, err := cachedProposerIndexAtSlot(slot, [32]byte(root))
if err != nil {
return 0, ErrProposerNotFound
}
return proposerIndex, nil
}
// ComputeProposerIndex returns the index sampled by effective balance, which is used to calculate proposer.
//
// nolint:dupword

View File

@@ -699,35 +699,27 @@ func (s *Server) fillEventData(ctx context.Context, ev payloadattribute.EventDat
var err error
var st state.BeaconState
// If head is in the same block as the proposal slot, we can use the "read only" state cache.
pse := slots.ToEpoch(ev.ProposalSlot)
if slots.ToEpoch(ev.HeadBlock.Block().Slot()) == pse {
st = s.StateGen.StateByRootIfCachedNoCopy(ev.HeadRoot)
}
// If st is nil, we couldn't get the state from the cache, or it isn't in the same epoch.
if st == nil || st.IsNil() {
proposalSlot := ev.ProposalSlot
index, err := helpers.GetCachedProposerIndex(st, proposalSlot)
if err == nil {
ev.ProposerIndex = index
} else {
st, err = s.StateGen.StateByRoot(ctx, ev.HeadRoot)
if err != nil {
return ev, errors.Wrap(err, "could not get head state")
}
// double check that we need to process_slots, just in case we got here via a hot state cache miss.
if slots.ToEpoch(st.Slot()) == pse {
start, err := slots.EpochStart(pse)
if err != nil {
return ev, errors.Wrap(err, "invalid state slot; could not compute epoch start")
}
st, err = transition.ProcessSlotsUsingNextSlotCache(ctx, st, ev.HeadRoot[:], start)
if err != nil {
return ev, errors.Wrap(err, "could not run process blocks on head state into the proposal slot epoch")
}
st, err = transition.ProcessSlotsUsingNextSlotCache(ctx, st, ev.HeadRoot[:], proposalSlot)
if err != nil {
return ev, errors.Wrap(err, "could not run process blocks on head state into the proposal slot epoch")
}
ev.ProposerIndex, err = helpers.BeaconProposerIndexAtSlot(ctx, st, ev.ProposalSlot)
if err != nil {
return ev, errors.Wrap(err, "failed to compute proposer index")
}
}
ev.ProposerIndex, err = helpers.BeaconProposerIndexAtSlot(ctx, st, ev.ProposalSlot)
if err != nil {
return ev, errors.Wrap(err, "failed to compute proposer index")
}
randao, err := helpers.RandaoMix(st, pse)
randao, err := helpers.RandaoMix(st, slots.ToEpoch(proposalSlot))
if err != nil {
return ev, errors.Wrap(err, "could not get head state randado")
}