From 1d2b91fb04f5a7393286fb8de9685199d925ef59 Mon Sep 17 00:00:00 2001 From: Potuz Date: Sat, 28 May 2022 15:27:53 -0300 Subject: [PATCH 1/3] Do not fill in blocks that are not in the finalized branch --- beacon-chain/blockchain/error.go | 2 + .../blockchain/process_block_helpers.go | 4 ++ beacon-chain/blockchain/process_block_test.go | 62 ++++++++++++++++--- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/beacon-chain/blockchain/error.go b/beacon-chain/blockchain/error.go index 8b085e79d491..3beb9573b465 100644 --- a/beacon-chain/blockchain/error.go +++ b/beacon-chain/blockchain/error.go @@ -27,6 +27,8 @@ var ( errWSBlockNotFound = errors.New("weak subjectivity root not found in db") // errWSBlockNotFoundInEpoch is returned when a block is not found in the WS cache or DB within epoch. errWSBlockNotFoundInEpoch = errors.New("weak subjectivity root not found in db within epoch") + // errNotDescendantOfFinalized is returned when a block is not a descendant of the finalized checkpoint + errNotDescendantOfFinalized = errors.New("not descendant of finalized checkpoint") ) // An invalid block is the block that fails state transition based on the core protocol rules. diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index cd071bbb38a1..74cf4c2376d0 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -376,6 +376,10 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa higherThanFinalized = slot > fSlot } + if len(pendingRoots) > 0 && pendingRoots[len(pendingRoots)-1] != bytesutil.ToBytes32(finalized.Root) { + return errNotDescendantOfFinalized + } + // Insert parent nodes to fork choice store in reverse order. // Lower slots should be at the end of the list. for i := len(pendingNodes) - 1; i >= 0; i-- { diff --git a/beacon-chain/blockchain/process_block_test.go b/beacon-chain/blockchain/process_block_test.go index 48772093afd1..74c7830d7d98 100644 --- a/beacon-chain/blockchain/process_block_test.go +++ b/beacon-chain/blockchain/process_block_test.go @@ -730,7 +730,6 @@ func TestFillForkChoiceMissingBlocks_CanSave_ProtoArray(t *testing.T) { service, err := NewService(ctx, opts...) require.NoError(t, err) service.cfg.ForkChoiceStore = protoarray.New(0, 0) - service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Root: make([]byte, 32)}, [32]byte{}) genesisStateRoot := [32]byte{} genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) @@ -753,12 +752,15 @@ func TestFillForkChoiceMissingBlocks_CanSave_ProtoArray(t *testing.T) { wsb, err = wrapper.WrappedSignedBeaconBlock(blk) require.NoError(t, err) + service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Root: roots[0]}, [32]byte{}) err = service.fillInForkChoiceMissingBlocks( context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) // 5 nodes from the block tree 1. B0 - B3 - B4 - B6 - B8 assert.Equal(t, 5, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") + assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[0])), "Didn't save node") + assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[3])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[4])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[6])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[8])), "Didn't save node") @@ -775,7 +777,6 @@ func TestFillForkChoiceMissingBlocks_CanSave_DoublyLinkedTree(t *testing.T) { service, err := NewService(ctx, opts...) require.NoError(t, err) service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0) - service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Root: make([]byte, 32)}, [32]byte{}) genesisStateRoot := [32]byte{} genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) @@ -799,12 +800,15 @@ func TestFillForkChoiceMissingBlocks_CanSave_DoublyLinkedTree(t *testing.T) { wsb, err = wrapper.WrappedSignedBeaconBlock(blk) require.NoError(t, err) + service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Root: roots[0]}, [32]byte{}) err = service.fillInForkChoiceMissingBlocks( context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) // 5 nodes from the block tree 1. B0 - B3 - B4 - B6 - B8 assert.Equal(t, 5, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") + assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[0])), "Didn't save node") + assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[3])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[4])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[6])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[8])), "Didn't save node") @@ -821,7 +825,6 @@ func TestFillForkChoiceMissingBlocks_RootsMatch_ProtoArray(t *testing.T) { service, err := NewService(ctx, opts...) require.NoError(t, err) service.cfg.ForkChoiceStore = protoarray.New(0, 0) - service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Root: make([]byte, 32)}, [32]byte{}) genesisStateRoot := [32]byte{} genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) @@ -845,6 +848,7 @@ func TestFillForkChoiceMissingBlocks_RootsMatch_ProtoArray(t *testing.T) { wsb, err = wrapper.WrappedSignedBeaconBlock(blk) require.NoError(t, err) + service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Root: roots[0]}, [32]byte{}) err = service.fillInForkChoiceMissingBlocks( context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) @@ -870,7 +874,6 @@ func TestFillForkChoiceMissingBlocks_RootsMatch_DoublyLinkedTree(t *testing.T) { service, err := NewService(ctx, opts...) require.NoError(t, err) service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0) - service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Root: make([]byte, 32)}, [32]byte{}) genesisStateRoot := [32]byte{} genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) @@ -894,6 +897,7 @@ func TestFillForkChoiceMissingBlocks_RootsMatch_DoublyLinkedTree(t *testing.T) { wsb, err = wrapper.WrappedSignedBeaconBlock(blk) require.NoError(t, err) + service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Root: roots[0]}, [32]byte{}) err = service.fillInForkChoiceMissingBlocks( context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) @@ -919,8 +923,6 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_ProtoArray(t *testing.T) { service, err := NewService(ctx, opts...) require.NoError(t, err) service.cfg.ForkChoiceStore = protoarray.New(0, 0) - // Set finalized epoch to 1. - service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Epoch: 1}, [32]byte{}) genesisStateRoot := [32]byte{} genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) @@ -958,6 +960,8 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_ProtoArray(t *testing.T) { require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb)) beaconState, _ := util.DeterministicGenesisState(t, 32) + // Set finalized epoch to 1. + service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Epoch: 1, Root: r63[:]}, [32]byte{}) err = service.fillInForkChoiceMissingBlocks( context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) @@ -980,8 +984,6 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_DoublyLinkedTree(t *testing service, err := NewService(ctx, opts...) require.NoError(t, err) service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0) - // Set finalized epoch to 1. - service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Epoch: 1}, [32]byte{}) genesisStateRoot := [32]byte{} genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) @@ -1019,6 +1021,9 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_DoublyLinkedTree(t *testing require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb)) beaconState, _ := util.DeterministicGenesisState(t, 32) + + // Set finalized epoch to 1. + service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Epoch: 1, Root: r63[:]}, [32]byte{}) err = service.fillInForkChoiceMissingBlocks( context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) @@ -1030,11 +1035,50 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_DoublyLinkedTree(t *testing assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(r63), "Didn't save node") } +func TestFillForkChoiceMissingBlocks_FinalizedSibling_DoublyLinkedTree(t *testing.T) { + ctx := context.Background() + beaconDB := testDB.SetupDB(t) + + opts := []Option{ + WithDatabase(beaconDB), + WithStateGen(stategen.New(beaconDB)), + } + service, err := NewService(ctx, opts...) + require.NoError(t, err) + service.cfg.ForkChoiceStore = doublylinkedtree.New(0, 0) + + genesisStateRoot := [32]byte{} + genesis := blocks.NewGenesisBlock(genesisStateRoot[:]) + wsb, err := wrapper.WrappedSignedBeaconBlock(genesis) + require.NoError(t, err) + require.NoError(t, beaconDB.SaveBlock(ctx, wsb)) + validGenesisRoot, err := genesis.Block.HashTreeRoot() + require.NoError(t, err) + st, err := util.NewBeaconState() + require.NoError(t, err) + + require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st.Copy(), validGenesisRoot)) + roots, err := blockTree1(t, beaconDB, validGenesisRoot[:]) + require.NoError(t, err) + + beaconState, _ := util.DeterministicGenesisState(t, 32) + blk := util.NewBeaconBlock() + blk.Block.Slot = 9 + blk.Block.ParentRoot = roots[8] + + wsb, err = wrapper.WrappedSignedBeaconBlock(blk) + require.NoError(t, err) + + service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Root: roots[1]}, [32]byte{}) + err = service.fillInForkChoiceMissingBlocks( + context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) + require.ErrorIs(t, errNotDescendantOfFinalized, err) +} + // blockTree1 constructs the following tree: // /- B1 // B0 /- B5 - B7 // \- B3 - B4 - B6 - B8 -// (B1, and B3 are all from the same slots) func blockTree1(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][]byte, error) { genesisRoot = bytesutil.PadTo(genesisRoot, 32) b0 := util.NewBeaconBlock() From f113d17577bfcd827870f4eb0efaae43b400c7f3 Mon Sep 17 00:00:00 2001 From: Potuz Date: Sat, 28 May 2022 15:31:41 -0300 Subject: [PATCH 2/3] mark blocks as invalid --- beacon-chain/blockchain/error.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon-chain/blockchain/error.go b/beacon-chain/blockchain/error.go index 3beb9573b465..64338cecec5a 100644 --- a/beacon-chain/blockchain/error.go +++ b/beacon-chain/blockchain/error.go @@ -28,7 +28,7 @@ var ( // errWSBlockNotFoundInEpoch is returned when a block is not found in the WS cache or DB within epoch. errWSBlockNotFoundInEpoch = errors.New("weak subjectivity root not found in db within epoch") // errNotDescendantOfFinalized is returned when a block is not a descendant of the finalized checkpoint - errNotDescendantOfFinalized = errors.New("not descendant of finalized checkpoint") + errNotDescendantOfFinalized = invalidBlock{errors.New("not descendant of finalized checkpoint")} ) // An invalid block is the block that fails state transition based on the core protocol rules. From d80e5225264c524d825de91da711bcff3886d884 Mon Sep 17 00:00:00 2001 From: Potuz Date: Sun, 29 May 2022 17:54:04 -0300 Subject: [PATCH 3/3] Fix old off-by-ones, do not pass finalized state --- .../blockchain/process_block_helpers.go | 21 +++---- beacon-chain/blockchain/process_block_test.go | 60 +++++++++++-------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/beacon-chain/blockchain/process_block_helpers.go b/beacon-chain/blockchain/process_block_helpers.go index 74cf4c2376d0..e66fa89ca598 100644 --- a/beacon-chain/blockchain/process_block_helpers.go +++ b/beacon-chain/blockchain/process_block_helpers.go @@ -349,8 +349,6 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa pendingNodes := make([]interfaces.BeaconBlock, 0) pendingRoots := make([][32]byte, 0) - parentRoot := bytesutil.ToBytes32(blk.ParentRoot()) - slot := blk.Slot() // Fork choice only matters from last finalized slot. finalized, err := s.store.FinalizedCheckpt() if err != nil { @@ -360,23 +358,22 @@ func (s *Service) fillInForkChoiceMissingBlocks(ctx context.Context, blk interfa if err != nil { return err } - higherThanFinalized := slot > fSlot // As long as parent node is not in fork choice store, and parent node is in DB. - for !s.cfg.ForkChoiceStore.HasNode(parentRoot) && s.cfg.BeaconDB.HasBlock(ctx, parentRoot) && higherThanFinalized { - b, err := s.getBlock(ctx, parentRoot) + root := bytesutil.ToBytes32(blk.ParentRoot()) + for !s.cfg.ForkChoiceStore.HasNode(root) && s.cfg.BeaconDB.HasBlock(ctx, root) { + b, err := s.getBlock(ctx, root) if err != nil { return err } - + if b.Block().Slot() <= fSlot { + break + } pendingNodes = append(pendingNodes, b.Block()) - copiedRoot := parentRoot + copiedRoot := root pendingRoots = append(pendingRoots, copiedRoot) - parentRoot = bytesutil.ToBytes32(b.Block().ParentRoot()) - slot = b.Block().Slot() - higherThanFinalized = slot > fSlot + root = bytesutil.ToBytes32(b.Block().ParentRoot()) } - - if len(pendingRoots) > 0 && pendingRoots[len(pendingRoots)-1] != bytesutil.ToBytes32(finalized.Root) { + if len(pendingRoots) > 0 && root != bytesutil.ToBytes32(finalized.Root) { return errNotDescendantOfFinalized } diff --git a/beacon-chain/blockchain/process_block_test.go b/beacon-chain/blockchain/process_block_test.go index 74c7830d7d98..0bb58397162d 100644 --- a/beacon-chain/blockchain/process_block_test.go +++ b/beacon-chain/blockchain/process_block_test.go @@ -757,9 +757,8 @@ func TestFillForkChoiceMissingBlocks_CanSave_ProtoArray(t *testing.T) { context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) - // 5 nodes from the block tree 1. B0 - B3 - B4 - B6 - B8 - assert.Equal(t, 5, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") - assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[0])), "Didn't save node") + // 4 nodes from the block tree 1. B3 - B4 - B6 - B8 + assert.Equal(t, 4, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[3])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[4])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[6])), "Didn't save node") @@ -806,8 +805,7 @@ func TestFillForkChoiceMissingBlocks_CanSave_DoublyLinkedTree(t *testing.T) { require.NoError(t, err) // 5 nodes from the block tree 1. B0 - B3 - B4 - B6 - B8 - assert.Equal(t, 5, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") - assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[0])), "Didn't save node") + assert.Equal(t, 4, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[3])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[4])), "Didn't save node") assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(roots[6])), "Didn't save node") @@ -853,10 +851,10 @@ func TestFillForkChoiceMissingBlocks_RootsMatch_ProtoArray(t *testing.T) { context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) - // 5 nodes from the block tree 1. B0 - B3 - B4 - B6 - B8 - assert.Equal(t, 5, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") + // 4 nodes from the block tree 1. B3 - B4 - B6 - B8 + assert.Equal(t, 4, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") // Ensure all roots and their respective blocks exist. - wantedRoots := [][]byte{roots[0], roots[3], roots[4], roots[6], roots[8]} + wantedRoots := [][]byte{roots[3], roots[4], roots[6], roots[8]} for i, rt := range wantedRoots { assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(rt)), fmt.Sprintf("Didn't save node: %d", i)) assert.Equal(t, true, service.cfg.BeaconDB.HasBlock(context.Background(), bytesutil.ToBytes32(rt))) @@ -902,10 +900,10 @@ func TestFillForkChoiceMissingBlocks_RootsMatch_DoublyLinkedTree(t *testing.T) { context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) - // 5 nodes from the block tree 1. B0 - B3 - B4 - B6 - B8 - assert.Equal(t, 5, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") + // 5 nodes from the block tree 1. B3 - B4 - B6 - B8 + assert.Equal(t, 4, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") // Ensure all roots and their respective blocks exist. - wantedRoots := [][]byte{roots[0], roots[3], roots[4], roots[6], roots[8]} + wantedRoots := [][]byte{roots[3], roots[4], roots[6], roots[8]} for i, rt := range wantedRoots { assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(bytesutil.ToBytes32(rt)), fmt.Sprintf("Didn't save node: %d", i)) assert.Equal(t, true, service.cfg.BeaconDB.HasBlock(context.Background(), bytesutil.ToBytes32(rt))) @@ -936,7 +934,7 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_ProtoArray(t *testing.T) { require.NoError(t, service.cfg.BeaconDB.SaveState(ctx, st.Copy(), validGenesisRoot)) - // Define a tree branch, slot 63 <- 64 <- 65 + // Define a tree branch, slot 63 <- 64 <- 65 <- 66 b63 := util.NewBeaconBlock() b63.Block.Slot = 63 wsb, err = wrapper.WrappedSignedBeaconBlock(b63) @@ -955,22 +953,28 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_ProtoArray(t *testing.T) { b65 := util.NewBeaconBlock() b65.Block.Slot = 65 b65.Block.ParentRoot = r64[:] + r65, err := b65.Block.HashTreeRoot() + require.NoError(t, err) wsb, err = wrapper.WrappedSignedBeaconBlock(b65) require.NoError(t, err) require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb)) + b66 := util.NewBeaconBlock() + b66.Block.Slot = 66 + b66.Block.ParentRoot = r65[:] + wsb, err = wrapper.WrappedSignedBeaconBlock(b66) + require.NoError(t, err) + require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb)) beaconState, _ := util.DeterministicGenesisState(t, 32) - // Set finalized epoch to 1. - service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Epoch: 1, Root: r63[:]}, [32]byte{}) + // Set finalized epoch to 2. + service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Epoch: 2, Root: r64[:]}, [32]byte{}) err = service.fillInForkChoiceMissingBlocks( context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) - // There should be 2 nodes, block 65 and block 64. - assert.Equal(t, 2, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") - - // Block with slot 63 should be in fork choice because it's less than finalized epoch 1. - assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(r63), "Didn't save node") + // We should have saved 1 node: block 65 + assert.Equal(t, 1, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") + assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(r65), "Didn't save node") } func TestFillForkChoiceMissingBlocks_FilterFinalized_DoublyLinkedTree(t *testing.T) { @@ -1016,23 +1020,29 @@ func TestFillForkChoiceMissingBlocks_FilterFinalized_DoublyLinkedTree(t *testing b65 := util.NewBeaconBlock() b65.Block.Slot = 65 b65.Block.ParentRoot = r64[:] + r65, err := b65.Block.HashTreeRoot() + require.NoError(t, err) wsb, err = wrapper.WrappedSignedBeaconBlock(b65) require.NoError(t, err) require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb)) + b66 := util.NewBeaconBlock() + b66.Block.Slot = 66 + b66.Block.ParentRoot = r65[:] + wsb, err = wrapper.WrappedSignedBeaconBlock(b66) + require.NoError(t, err) + require.NoError(t, service.cfg.BeaconDB.SaveBlock(ctx, wsb)) beaconState, _ := util.DeterministicGenesisState(t, 32) // Set finalized epoch to 1. - service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Epoch: 1, Root: r63[:]}, [32]byte{}) + service.store.SetFinalizedCheckptAndPayloadHash(ðpb.Checkpoint{Epoch: 2, Root: r64[:]}, [32]byte{}) err = service.fillInForkChoiceMissingBlocks( context.Background(), wsb.Block(), beaconState.FinalizedCheckpoint(), beaconState.CurrentJustifiedCheckpoint()) require.NoError(t, err) - // There should be 2 nodes, block 65 and block 64. - assert.Equal(t, 2, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") - - // Block with slot 63 should be in fork choice because it's less than finalized epoch 1. - assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(r63), "Didn't save node") + // There should be 1 node: block 65 + assert.Equal(t, 1, service.cfg.ForkChoiceStore.NodeCount(), "Miss match nodes") + assert.Equal(t, true, service.cfg.ForkChoiceStore.HasNode(r65), "Didn't save node") } func TestFillForkChoiceMissingBlocks_FinalizedSibling_DoublyLinkedTree(t *testing.T) {