mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 13:28:01 -05:00
Fix FFG LMD Consistency Check (Option 2) (#13258)
* Fix FFG LMD Consistency Check with TargetRootForSlot * Add test, removed implementation * convert to epoch and fix self target --------- Co-authored-by: Potuz <potuz@prysmaticlabs.com>
This commit is contained in:
@@ -464,11 +464,11 @@ func (s *Service) IsOptimisticForRoot(ctx context.Context, root [32]byte) (bool,
|
||||
return !isCanonical, nil
|
||||
}
|
||||
|
||||
// TargetRoot wraps the corresponding method in forkchoice
|
||||
func (s *Service) TargetRoot(root [32]byte) ([32]byte, error) {
|
||||
// TargetRootForEpoch wraps the corresponding method in forkchoice
|
||||
func (s *Service) TargetRootForEpoch(root [32]byte, epoch primitives.Epoch) ([32]byte, error) {
|
||||
s.cfg.ForkChoiceStore.RLock()
|
||||
defer s.cfg.ForkChoiceStore.RUnlock()
|
||||
return s.cfg.ForkChoiceStore.TargetRoot(root)
|
||||
return s.cfg.ForkChoiceStore.TargetRootForEpoch(root, epoch)
|
||||
}
|
||||
|
||||
// Ancestor returns the block root of an ancestry block from the input block root.
|
||||
|
||||
@@ -53,7 +53,7 @@ func (s *Service) AttestationTargetState(ctx context.Context, target *ethpb.Chec
|
||||
|
||||
// VerifyLmdFfgConsistency verifies that attestation's LMD and FFG votes are consistency to each other.
|
||||
func (s *Service) VerifyLmdFfgConsistency(ctx context.Context, a *ethpb.Attestation) error {
|
||||
r, err := s.TargetRoot([32]byte(a.Data.BeaconBlockRoot))
|
||||
r, err := s.TargetRootForEpoch([32]byte(a.Data.BeaconBlockRoot), a.Data.Target.Epoch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -638,12 +638,19 @@ func (f *ForkChoice) Slot(root [32]byte) (primitives.Slot, error) {
|
||||
return n.slot, nil
|
||||
}
|
||||
|
||||
// TargetRoot returns the root of the checkpoint block for the given head root
|
||||
func (f *ForkChoice) TargetRoot(root [32]byte) ([32]byte, error) {
|
||||
// TargetRootForEpoch returns the root of the target block for a given epoch.
|
||||
// The epoch parameter is crucial to identify the correct target root. For example:
|
||||
// When inserting a block at slot 63 with block root 0xA and target root 0xB (pointing to the block at slot 32),
|
||||
// and at slot 64, where the block is skipped, the attestation will reference the target root as 0xA (for slot 63), not 0xB (for slot 32).
|
||||
// This implies that if the input slot exceeds the block slot, the target root will be the same as the block root.
|
||||
func (f *ForkChoice) TargetRootForEpoch(root [32]byte, epoch primitives.Epoch) ([32]byte, error) {
|
||||
n, ok := f.store.nodeByRoot[root]
|
||||
if !ok || n == nil {
|
||||
return [32]byte{}, ErrNilNode
|
||||
}
|
||||
if epoch > slots.ToEpoch(n.slot) {
|
||||
return n.root, nil
|
||||
}
|
||||
if n.target == nil {
|
||||
return [32]byte{}, nil
|
||||
}
|
||||
|
||||
@@ -436,21 +436,21 @@ func TestForkChoice_ReceivedBlocksLastEpoch(t *testing.T) {
|
||||
require.Equal(t, uint64(0), count)
|
||||
}
|
||||
|
||||
func TestStore_Target(t *testing.T) {
|
||||
func TestStore_TargetRootForEpoch(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
f := setup(1, 1)
|
||||
|
||||
state, blkRoot, err := prepareForkchoiceState(ctx, params.BeaconConfig().SlotsPerEpoch, [32]byte{'a'}, params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
||||
target, err := f.TargetRoot(blkRoot)
|
||||
target, err := f.TargetRootForEpoch(blkRoot, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, target, blkRoot)
|
||||
|
||||
state, root1, err := prepareForkchoiceState(ctx, params.BeaconConfig().SlotsPerEpoch+1, [32]byte{'b'}, blkRoot, params.BeaconConfig().ZeroHash, 1, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, state, root1))
|
||||
target, err = f.TargetRoot(root1)
|
||||
target, err = f.TargetRootForEpoch(root1, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, target, blkRoot)
|
||||
|
||||
@@ -459,14 +459,14 @@ func TestStore_Target(t *testing.T) {
|
||||
state, root2, err := prepareForkchoiceState(ctx, 2*params.BeaconConfig().SlotsPerEpoch+1, [32]byte{'c'}, root1, params.BeaconConfig().ZeroHash, 1, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, state, root2))
|
||||
target, err = f.TargetRoot(root2)
|
||||
target, err = f.TargetRootForEpoch(root2, 2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, target, root1)
|
||||
|
||||
state, root3, err := prepareForkchoiceState(ctx, 2*params.BeaconConfig().SlotsPerEpoch+2, [32]byte{'d'}, root2, params.BeaconConfig().ZeroHash, 1, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, state, root3))
|
||||
target, err = f.TargetRoot(root2)
|
||||
target, err = f.TargetRootForEpoch(root2, 2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, target, root1)
|
||||
|
||||
@@ -474,7 +474,7 @@ func TestStore_Target(t *testing.T) {
|
||||
s := f.store
|
||||
s.finalizedCheckpoint.Root = root1
|
||||
require.NoError(t, s.prune(ctx))
|
||||
target, err = f.TargetRoot(root1)
|
||||
target, err = f.TargetRootForEpoch(root1, 1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, [32]byte{}, target)
|
||||
|
||||
@@ -483,21 +483,26 @@ func TestStore_Target(t *testing.T) {
|
||||
state, root4, err := prepareForkchoiceState(ctx, 3*params.BeaconConfig().SlotsPerEpoch, [32]byte{'e'}, root1, params.BeaconConfig().ZeroHash, 1, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, state, root4))
|
||||
target, err = f.TargetRoot(root4)
|
||||
target, err = f.TargetRootForEpoch(root4, 3)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, target, root4)
|
||||
|
||||
state, root5, err := prepareForkchoiceState(ctx, 3*params.BeaconConfig().SlotsPerEpoch+1, [32]byte{'f'}, root4, params.BeaconConfig().ZeroHash, 1, 1)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, f.InsertNode(ctx, state, root5))
|
||||
target, err = f.TargetRoot(root5)
|
||||
target, err = f.TargetRootForEpoch(root5, 3)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, target, root4)
|
||||
|
||||
// Target root where the target epoch is same or ahead of the block slot
|
||||
target, err = f.TargetRootForEpoch(root5, 4)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, target, root5)
|
||||
|
||||
// Prune finalization
|
||||
s.finalizedCheckpoint.Root = root4
|
||||
require.NoError(t, s.prune(ctx))
|
||||
target, err = f.TargetRoot(root4)
|
||||
target, err = f.TargetRootForEpoch(root4, 3)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, root4, target)
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ type Getter interface {
|
||||
ShouldOverrideFCU() bool
|
||||
Slot([32]byte) (primitives.Slot, error)
|
||||
LastRoot(primitives.Epoch) [32]byte
|
||||
TargetRoot([32]byte) ([32]byte, error)
|
||||
TargetRootForEpoch([32]byte, primitives.Epoch) ([32]byte, error)
|
||||
}
|
||||
|
||||
// Setter allows to set forkchoice information
|
||||
|
||||
Reference in New Issue
Block a user