mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
Report voted fractions for a given root (#11421)
* Report voted fractions for a given root * unused parameters * comment update * change test Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
@@ -14,25 +14,27 @@ import (
|
||||
var errNilState = errors.New("nil state")
|
||||
|
||||
// UnrealizedCheckpoints returns the justification and finalization checkpoints of the
|
||||
// given state as if it was progressed with empty slots until the next epoch.
|
||||
func UnrealizedCheckpoints(st state.BeaconState) (*ethpb.Checkpoint, *ethpb.Checkpoint, error) {
|
||||
// given state as if it was progressed with empty slots until the next epoch. It
|
||||
// also returns the total active balance during the epoch.
|
||||
func UnrealizedCheckpoints(st state.BeaconState) (uint64, *ethpb.Checkpoint, *ethpb.Checkpoint, error) {
|
||||
if st == nil || st.IsNil() {
|
||||
return nil, nil, errNilState
|
||||
return 0, nil, nil, errNilState
|
||||
}
|
||||
|
||||
if slots.ToEpoch(st.Slot()) <= params.BeaconConfig().GenesisEpoch+1 {
|
||||
jc := st.CurrentJustifiedCheckpoint()
|
||||
fc := st.FinalizedCheckpoint()
|
||||
return jc, fc, nil
|
||||
return 0, jc, fc, nil
|
||||
}
|
||||
|
||||
activeBalance, prevTarget, currentTarget, err := st.UnrealizedCheckpointBalances()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return 0, nil, nil, err
|
||||
}
|
||||
|
||||
justification := processJustificationBits(st, activeBalance, prevTarget, currentTarget)
|
||||
return computeCheckpoints(st, justification)
|
||||
jc, fc, err := computeCheckpoints(st, justification)
|
||||
return activeBalance, jc, fc, err
|
||||
}
|
||||
|
||||
// ProcessJustificationAndFinalizationPreCompute processes justification and finalization during
|
||||
|
||||
@@ -243,10 +243,12 @@ func TestUnrealizedCheckpoints(t *testing.T) {
|
||||
_, _, err = altair.InitializePrecomputeValidators(context.Background(), state)
|
||||
require.NoError(t, err)
|
||||
|
||||
jc, fc, err := precompute.UnrealizedCheckpoints(state)
|
||||
ab, jc, fc, err := precompute.UnrealizedCheckpoints(state)
|
||||
require.NoError(t, err)
|
||||
require.DeepEqual(t, test.expectedJustified, jc.Epoch)
|
||||
require.DeepEqual(t, test.expectedFinalized, fc.Epoch)
|
||||
eb := params.BeaconConfig().MinGenesisActiveValidatorCount * params.BeaconConfig().MaxEffectiveBalance
|
||||
require.Equal(t, eb, ab)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,3 +161,21 @@ func (n *Node) nodeTreeDump(ctx context.Context, nodes []*v1.ForkChoiceNode) ([]
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
// VotedFraction returns the fraction of the committee that voted directly for
|
||||
// this node.
|
||||
func (f *ForkChoice) VotedFraction(root [32]byte) (uint64, error) {
|
||||
f.store.nodesLock.RLock()
|
||||
defer f.store.nodesLock.RUnlock()
|
||||
|
||||
// Avoid division by zero before a block is inserted.
|
||||
if f.store.committeeBalance == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
node, ok := f.store.nodeByRoot[root]
|
||||
if !ok || node == nil {
|
||||
return 0, ErrNilNode
|
||||
}
|
||||
return node.balance * 100 / f.store.committeeBalance, nil
|
||||
}
|
||||
|
||||
@@ -261,3 +261,45 @@ func TestNode_SetFullyValidated(t *testing.T) {
|
||||
require.Equal(t, storeNodes[i].timestamp, respNode.Timestamp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_VotedFraction(t *testing.T) {
|
||||
f := setup(1, 1)
|
||||
ctx := context.Background()
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, [32]byte{'A'}, 1, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
||||
state, blkRoot, err = prepareForkchoiceState(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, [32]byte{'B'}, 1, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
||||
|
||||
// No division by zero error
|
||||
vote, err := f.VotedFraction([32]byte{'b'})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(0), vote)
|
||||
|
||||
// Zero balance in the node
|
||||
f.store.committeeBalance = 100 * params.BeaconConfig().MaxEffectiveBalance
|
||||
vote, err = f.VotedFraction([32]byte{'b'})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(0), vote)
|
||||
|
||||
// Attestations are not counted until we process Head
|
||||
balances := []uint64{params.BeaconConfig().MaxEffectiveBalance, params.BeaconConfig().MaxEffectiveBalance}
|
||||
_, err = f.Head(context.Background(), balances)
|
||||
require.NoError(t, err)
|
||||
f.ProcessAttestation(context.Background(), []uint64{0, 1}, [32]byte{'b'}, 2)
|
||||
vote, err = f.VotedFraction([32]byte{'b'})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(0), vote)
|
||||
|
||||
// After we call head the voted fraction is obtained.
|
||||
_, err = f.Head(context.Background(), balances)
|
||||
require.NoError(t, err)
|
||||
vote, err = f.VotedFraction([32]byte{'b'})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(2), vote)
|
||||
|
||||
// Check for non-existent root
|
||||
_, err = f.VotedFraction([32]byte{'c'})
|
||||
require.ErrorIs(t, err, ErrNilNode)
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ type Store struct {
|
||||
highestReceivedSlot types.Slot // The highest received slot in the chain.
|
||||
receivedBlocksLastEpoch [fieldparams.SlotsPerEpoch]types.Slot // Using `highestReceivedSlot`. The slot of blocks received in the last epoch.
|
||||
allTipsAreInvalid bool // tracks if all tips are not viable for head
|
||||
committeeBalance uint64 // tracks the total active validator balance divided by slots per epoch. Requires a lock on nodes to read/write
|
||||
}
|
||||
|
||||
// Node defines the individual block which includes its block parent, ancestor and how much weight accounted for it.
|
||||
|
||||
@@ -90,12 +90,14 @@ func (s *Store) pullTips(state state.BeaconState, node *Node, jc, fc *ethpb.Chec
|
||||
return jc, fc
|
||||
}
|
||||
|
||||
uj, uf, err := precompute.UnrealizedCheckpoints(state)
|
||||
ab, uj, uf, err := precompute.UnrealizedCheckpoints(state)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("could not compute unrealized checkpoints")
|
||||
uj, uf = jc, fc
|
||||
}
|
||||
|
||||
s.committeeBalance = ab / uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
|
||||
// Update store's unrealized checkpoints.
|
||||
if uj.Epoch > s.unrealizedJustifiedCheckpoint.Epoch {
|
||||
s.unrealizedJustifiedCheckpoint = &forkchoicetypes.Checkpoint{
|
||||
|
||||
@@ -64,6 +64,7 @@ type Getter interface {
|
||||
HighestReceivedBlockSlot() types.Slot
|
||||
ReceivedBlocksLastEpoch() (uint64, error)
|
||||
ForkChoiceDump(context.Context) (*v1.ForkChoiceResponse, error)
|
||||
VotedFraction(root [32]byte) (uint64, error)
|
||||
}
|
||||
|
||||
// Setter allows to set forkchoice information
|
||||
|
||||
@@ -43,3 +43,8 @@ func (n *Node) BestChild() uint64 {
|
||||
func (n *Node) BestDescendant() uint64 {
|
||||
return n.bestDescendant
|
||||
}
|
||||
|
||||
// VotedFraction is not implemented for protoarray
|
||||
func (*ForkChoice) VotedFraction(_ [32]byte) (uint64, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ func (s *Store) pullTips(state state.BeaconState, node *Node, jc, fc *ethpb.Chec
|
||||
return jc, fc
|
||||
}
|
||||
|
||||
uj, uf, err := precompute.UnrealizedCheckpoints(state)
|
||||
_, uj, uf, err := precompute.UnrealizedCheckpoints(state)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug("could not compute unrealized checkpoints")
|
||||
uj, uf = jc, fc
|
||||
|
||||
Reference in New Issue
Block a user