diff --git a/dot/core/service_integration_test.go b/dot/core/service_integration_test.go index 8ecc48697c..7ecd5be0a2 100644 --- a/dot/core/service_integration_test.go +++ b/dot/core/service_integration_test.go @@ -279,7 +279,7 @@ func TestHandleChainReorg_WithReorg_NoTransactions(t *testing.T) { height := 5 branch := 3 branches := map[int]int{branch: 1} - state.AddBlocksToStateWithFixedBranches(t, s.blockState.(*state.BlockState), height, branches, 0) + state.AddBlocksToStateWithFixedBranches(t, s.blockState.(*state.BlockState), height, branches) leaves := s.blockState.(*state.BlockState).Leaves() require.Equal(t, 2, len(leaves)) diff --git a/dot/rpc/modules/chain_integration_test.go b/dot/rpc/modules/chain_integration_test.go index 7ca227cf40..bc11a6a267 100644 --- a/dot/rpc/modules/chain_integration_test.go +++ b/dot/rpc/modules/chain_integration_test.go @@ -387,9 +387,15 @@ func newTestStateService(t *testing.T) *state.Service { } func loadTestBlocks(t *testing.T, gh common.Hash, bs *state.BlockState, rt runtime.Instance) { + digest := types.NewDigest() + prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + require.NoError(t, err) + err = digest.Add(*prd) + require.NoError(t, err) + header1 := &types.Header{ Number: big.NewInt(1), - Digest: types.NewDigest(), + Digest: digest, ParentHash: gh, StateRoot: trie.EmptyHash, } @@ -399,16 +405,10 @@ func loadTestBlocks(t *testing.T, gh common.Hash, bs *state.BlockState, rt runti Body: sampleBodyBytes, } - err := bs.AddBlock(block1) + err = bs.AddBlock(block1) require.NoError(t, err) bs.StoreRuntime(header1.Hash(), rt) - digest := types.NewDigest() - prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() - require.NoError(t, err) - err = digest.Add(*prd) - require.NoError(t, err) - header2 := &types.Header{ Number: big.NewInt(2), Digest: digest, diff --git a/dot/rpc/modules/childstate_integration_test.go b/dot/rpc/modules/childstate_integration_test.go index 86bb683497..6b3cb17de6 100644 --- a/dot/rpc/modules/childstate_integration_test.go +++ b/dot/rpc/modules/childstate_integration_test.go @@ -266,11 +266,18 @@ func setupChildStateStorage(t *testing.T) (*ChildStateModule, common.Hash) { err = st.Storage.StoreTrie(tr, nil) require.NoError(t, err) + digest := types.NewDigest() + prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + require.NoError(t, err) + err = digest.Add(*prd) + require.NoError(t, err) + b := &types.Block{ Header: types.Header{ ParentHash: bb.Header.Hash(), Number: big.NewInt(0).Add(big.NewInt(1), bb.Header.Number), StateRoot: stateRoot, + Digest: digest, }, Body: types.Body{}, } diff --git a/dot/rpc/modules/state_integration_test.go b/dot/rpc/modules/state_integration_test.go index 4b7c59fa05..db5834eb2f 100644 --- a/dot/rpc/modules/state_integration_test.go +++ b/dot/rpc/modules/state_integration_test.go @@ -530,11 +530,18 @@ func setupStateModule(t *testing.T) (*StateModule, *common.Hash, *common.Hash) { err = chain.Storage.StoreTrie(ts, nil) require.NoError(t, err) + digest := types.NewDigest() + prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + require.NoError(t, err) + err = digest.Add(*prd) + require.NoError(t, err) + b := &types.Block{ Header: types.Header{ ParentHash: chain.Block.BestBlockHash(), Number: big.NewInt(3), StateRoot: sr1, + Digest: digest, }, Body: *types.NewBody([]types.Extrinsic{[]byte{}}), } diff --git a/dot/rpc/modules/system_integration_test.go b/dot/rpc/modules/system_integration_test.go index f9da374a5c..3d14ea1a1a 100644 --- a/dot/rpc/modules/system_integration_test.go +++ b/dot/rpc/modules/system_integration_test.go @@ -319,11 +319,19 @@ func setupSystemModule(t *testing.T) *SystemModule { err = chain.Storage.StoreTrie(ts, nil) require.NoError(t, err) + + digest := types.NewDigest() + prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + require.NoError(t, err) + err = digest.Add(*prd) + require.NoError(t, err) + err = chain.Block.AddBlock(&types.Block{ Header: types.Header{ Number: big.NewInt(3), ParentHash: chain.Block.BestBlockHash(), StateRoot: ts.MustRoot(), + Digest: digest, }, Body: types.Body{}, }) diff --git a/dot/state/block.go b/dot/state/block.go index 6ad1ec04a8..e31d8f40c9 100644 --- a/dot/state/block.go +++ b/dot/state/block.go @@ -483,7 +483,7 @@ func (bs *BlockState) BestBlockHash() common.Hash { return common.Hash{} } - return bs.bt.DeepestBlockHash() + return bs.bt.BestBlockHash() } // BestBlockHeader returns the block header of the current head of the chain diff --git a/dot/state/block_test.go b/dot/state/block_test.go index 120fc4a847..50e6513f5f 100644 --- a/dot/state/block_test.go +++ b/dot/state/block_test.go @@ -80,7 +80,7 @@ func TestGetBlockByNumber(t *testing.T) { blockHeader := &types.Header{ ParentHash: testGenesisHeader.Hash(), Number: big.NewInt(1), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), } block := &types.Block{ @@ -102,7 +102,7 @@ func TestAddBlock(t *testing.T) { // Create header header0 := &types.Header{ Number: big.NewInt(1), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: testGenesisHeader.Hash(), } // Create blockHash @@ -119,7 +119,7 @@ func TestAddBlock(t *testing.T) { // Create header & blockData for block 2 header1 := &types.Header{ Number: big.NewInt(2), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: blockHash0, } blockHash1 := header1.Hash() @@ -244,6 +244,7 @@ func TestAddBlock_BlockNumberToHash(t *testing.T) { Header: types.Header{ ParentHash: bestHash, Number: big.NewInt(0).Add(bestHeader.Number, big.NewInt(1)), + Digest: createPrimaryBABEDigest(t), }, Body: types.Body{}, } @@ -324,7 +325,7 @@ func TestGetHashByNumber(t *testing.T) { header := &types.Header{ Number: big.NewInt(1), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: testGenesisHeader.Hash(), } @@ -347,7 +348,7 @@ func TestAddBlock_WithReOrg(t *testing.T) { header1a := &types.Header{ Number: big.NewInt(1), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: testGenesisHeader.Hash(), } @@ -366,7 +367,7 @@ func TestAddBlock_WithReOrg(t *testing.T) { header1b := &types.Header{ Number: big.NewInt(1), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: testGenesisHeader.Hash(), ExtrinsicsRoot: common.Hash{99}, } @@ -386,7 +387,7 @@ func TestAddBlock_WithReOrg(t *testing.T) { header2b := &types.Header{ Number: big.NewInt(2), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: header1b.Hash(), ExtrinsicsRoot: common.Hash{99}, } @@ -410,7 +411,7 @@ func TestAddBlock_WithReOrg(t *testing.T) { header2a := &types.Header{ Number: big.NewInt(2), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: header1a.Hash(), } @@ -424,7 +425,7 @@ func TestAddBlock_WithReOrg(t *testing.T) { header3a := &types.Header{ Number: big.NewInt(3), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: header2a.Hash(), } @@ -456,7 +457,7 @@ func TestAddBlockToBlockTree(t *testing.T) { header := &types.Header{ Number: big.NewInt(1), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: testGenesisHeader.Hash(), } diff --git a/dot/state/storage_test.go b/dot/state/storage_test.go index 6954af5b32..b455a66231 100644 --- a/dot/state/storage_test.go +++ b/dot/state/storage_test.go @@ -72,6 +72,7 @@ func TestStorage_GetStorageByBlockHash(t *testing.T) { ParentHash: testGenesisHeader.Hash(), Number: big.NewInt(1), StateRoot: root, + Digest: createPrimaryBABEDigest(t), }, Body: *body, } diff --git a/dot/state/test_helpers.go b/dot/state/test_helpers.go index 3ea8c4fed4..62c8def253 100644 --- a/dot/state/test_helpers.go +++ b/dot/state/test_helpers.go @@ -16,6 +16,7 @@ import ( runtime "github.com/ChainSafe/gossamer/lib/runtime/storage" "github.com/ChainSafe/gossamer/lib/trie" "github.com/ChainSafe/gossamer/lib/utils" + "github.com/ChainSafe/gossamer/pkg/scale" "github.com/stretchr/testify/require" ) @@ -35,6 +36,23 @@ func NewInMemoryDB(t *testing.T) chaindb.Database { return db } +func createPrimaryBABEDigest(t *testing.T) scale.VaryingDataTypeSlice { + babeDigest := types.NewBabeDigest() + err := babeDigest.Set(types.BabePrimaryPreDigest{AuthorityIndex: 0}) + require.NoError(t, err) + + bdEnc, err := scale.Marshal(babeDigest) + require.NoError(t, err) + + digest := types.NewDigest() + err = digest.Add(types.PreRuntimeDigest{ + ConsensusEngineID: types.BabeEngineID, + Data: bdEnc, + }) + require.NoError(t, err) + return digest +} + // branch tree randomly type testBranch struct { hash common.Hash @@ -134,7 +152,7 @@ func AddBlocksToState(t *testing.T, blockState *BlockState, depth int, // AddBlocksToStateWithFixedBranches adds blocks to a BlockState up to depth, with fixed branches // branches are provided with a map of depth -> # of branches -func AddBlocksToStateWithFixedBranches(t *testing.T, blockState *BlockState, depth int, branches map[int]int, r byte) { +func AddBlocksToStateWithFixedBranches(t *testing.T, blockState *BlockState, depth int, branches map[int]int) { previousHash := blockState.BestBlockHash() tb := []testBranch{} arrivalTime := time.Now() @@ -190,10 +208,11 @@ func AddBlocksToStateWithFixedBranches(t *testing.T, blockState *BlockState, dep previousHash = branch.hash for i := branch.depth; i < depth; i++ { + d, err := types.NewBabePrimaryPreDigest(0, uint64(i+j+99), [32]byte{}, [64]byte{}).ToPreRuntimeDigest() + require.NoError(t, err) + require.NotNil(t, d) digest := types.NewDigest() - _ = digest.Add(types.PreRuntimeDigest{ - Data: []byte{byte(i), byte(j), r}, - }) + _ = digest.Add(*d) block := &types.Block{ Header: types.Header{ @@ -206,7 +225,7 @@ func AddBlocksToStateWithFixedBranches(t *testing.T, blockState *BlockState, dep } hash := block.Header.Hash() - err := blockState.AddBlockWithArrivalTime(block, arrivalTime) + err = blockState.AddBlockWithArrivalTime(block, arrivalTime) require.Nil(t, err) blockState.StoreRuntime(hash, rt) @@ -244,6 +263,7 @@ func generateBlockWithRandomTrie(t *testing.T, serv *Service, ParentHash: *parent, Number: big.NewInt(bNum), StateRoot: trieStateRoot, + Digest: createPrimaryBABEDigest(t), }, Body: *body, } diff --git a/dot/sync/chain_processor_test.go b/dot/sync/chain_processor_test.go index 8f2c594b81..78083e6145 100644 --- a/dot/sync/chain_processor_test.go +++ b/dot/sync/chain_processor_test.go @@ -207,7 +207,7 @@ func TestChainProcessor_HandleJustification(t *testing.T) { d, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() require.NoError(t, err) digest := types.NewDigest() - err = digest.Add(d) + err = digest.Add(*d) require.NoError(t, err) header := &types.Header{ diff --git a/dot/sync/message_test.go b/dot/sync/message_test.go index 2f7b4ffc12..c8878b05d0 100644 --- a/dot/sync/message_test.go +++ b/dot/sync/message_test.go @@ -21,13 +21,19 @@ func addTestBlocksToState(t *testing.T, depth int, blockState BlockState) { previousNum, err := blockState.BestBlockNumber() require.Nil(t, err) + digest := types.NewDigest() + prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + require.NoError(t, err) + err = digest.Add(*prd) + require.NoError(t, err) + for i := 1; i <= depth; i++ { block := &types.Block{ Header: types.Header{ ParentHash: previousHash, Number: big.NewInt(int64(i)).Add(previousNum, big.NewInt(int64(i))), StateRoot: trie.EmptyHash, - Digest: types.NewDigest(), + Digest: digest, }, Body: types.Body{}, } @@ -362,7 +368,7 @@ func TestService_checkOrGetDescendantHash(t *testing.T) { branches := map[int]int{ 8: 1, } - state.AddBlocksToStateWithFixedBranches(t, s.blockState.(*state.BlockState), 16, branches, 1) + state.AddBlocksToStateWithFixedBranches(t, s.blockState.(*state.BlockState), 16, branches) // base case ancestor, err := s.blockState.GetHashByNumber(big.NewInt(1)) diff --git a/dot/types/babe.go b/dot/types/babe.go index 4156d592a5..7e47b52a93 100644 --- a/dot/types/babe.go +++ b/dot/types/babe.go @@ -114,3 +114,31 @@ func GetSlotFromHeader(header *Header) (uint64, error) { return slotNumber, nil } + +// IsPrimary returns true if the block was authored in a primary slot, false otherwise. +func IsPrimary(header *Header) (bool, error) { + if header == nil { + return false, fmt.Errorf("cannot have nil header") + } + + if len(header.Digest.Types) == 0 { + return false, fmt.Errorf("chain head missing digest") + } + + preDigest, ok := header.Digest.Types[0].Value().(PreRuntimeDigest) + if !ok { + return false, fmt.Errorf("first digest item is not pre-digest: type=%T", header.Digest.Types[0].Value()) + } + + digest, err := DecodeBabePreDigest(preDigest.Data) + if err != nil { + return false, fmt.Errorf("cannot decode BabePreDigest from pre-digest: %s", err) + } + + switch digest.(type) { + case BabePrimaryPreDigest: + return true, nil + default: + return false, nil + } +} diff --git a/lib/blocktree/blocktree.go b/lib/blocktree/blocktree.go index 1c1450f9bf..82e55d1932 100644 --- a/lib/blocktree/blocktree.go +++ b/lib/blocktree/blocktree.go @@ -63,7 +63,7 @@ func NewBlockTreeFromRoot(root *types.Header) *BlockTree { // AddBlock inserts the block as child of its parent node // Note: Assumes block has no children -func (bt *BlockTree) AddBlock(header *types.Header, arrivalTime time.Time) error { +func (bt *BlockTree) AddBlock(header *types.Header, arrivalTime time.Time) (err error) { bt.Lock() defer bt.Unlock() @@ -84,12 +84,21 @@ func (bt *BlockTree) AddBlock(header *types.Header, arrivalTime time.Time) error return errUnexpectedNumber } + var isPrimary bool + if header.Number.Uint64() != 0 { + isPrimary, err = types.IsPrimary(header) + if err != nil { + return fmt.Errorf("failed to check if block was primary: %w", err) + } + } + n := &node{ hash: header.Hash(), parent: parent, children: []*node{}, number: number, arrivalTime: arrivalTime, + isPrimary: isPrimary, } parent.addChild(n) @@ -199,18 +208,6 @@ func (bt *BlockTree) String() string { return fmt.Sprintf("%s\n%s\n", metadata, tree.Print()) } -// longestPath returns the path from the root to the deepest leaf in the blocktree -func (bt *BlockTree) longestPath() []*node { - dl := bt.deepestLeaf() - var path []*node - for curr := dl; ; curr = curr.parent { - path = append([]*node{curr}, path...) - if curr.parent == nil { - return path - } - } -} - // subChain returns the path from the node with Hash start to the node with Hash end func (bt *BlockTree) subChain(start, end Hash) ([]*node, error) { sn := bt.getNode(start) @@ -241,27 +238,31 @@ func (bt *BlockTree) SubBlockchain(start, end Hash) ([]Hash, error) { } -// deepestLeaf returns the deepest leaf in the block tree. -func (bt *BlockTree) deepestLeaf() *node { - return bt.leaves.deepestLeaf() +// best returns the best node in the block tree using the fork choice rule. +func (bt *BlockTree) best() *node { + return bt.leaves.bestBlock() } -// DeepestBlockHash returns the hash of the deepest block in the blocktree -// If there is multiple deepest blocks, it returns the one with the earliest arrival time. -func (bt *BlockTree) DeepestBlockHash() Hash { +// BestBlockHash returns the hash of the block that is considered "best" based on the +// fork-choice rule. It returns the head of the chain with the most primary blocks. +// If there are multiple chains with the same number of primaries, it returns the one +// with the highest head number. +// If there are multiple chains with the same number of primaries and the same height, +// it returns the one with the head block that arrived the earliest. +func (bt *BlockTree) BestBlockHash() Hash { bt.RLock() defer bt.RUnlock() if bt.leaves == nil { + // this shouldn't happen return Hash{} } - deepest := bt.leaves.deepestLeaf() - if deepest == nil { - return Hash{} + if len(bt.root.children) == 0 { + return bt.root.hash } - return deepest.hash + return bt.best().hash } // IsDescendantOf returns true if the child is a descendant of parent, false otherwise. @@ -337,13 +338,13 @@ func (bt *BlockTree) GetHashByNumber(num *big.Int) (common.Hash, error) { bt.RLock() defer bt.RUnlock() - deepest := bt.leaves.deepestLeaf() - if deepest.number.Cmp(num) == -1 { + best := bt.leaves.bestBlock() + if best.number.Cmp(num) == -1 { return common.Hash{}, ErrNumGreaterThanHighest } - if deepest.number.Cmp(num) == 0 { - return deepest.hash, nil + if best.number.Cmp(num) == 0 { + return best.hash, nil } if bt.root.number.Cmp(num) == 1 { @@ -354,7 +355,7 @@ func (bt *BlockTree) GetHashByNumber(num *big.Int) (common.Hash, error) { return bt.root.hash, nil } - curr := deepest.parent + curr := best.parent for { if curr == nil { return common.Hash{}, ErrNodeNotFound diff --git a/lib/blocktree/blocktree_test.go b/lib/blocktree/blocktree_test.go index b7d2bc1639..40b7f80147 100644 --- a/lib/blocktree/blocktree_test.go +++ b/lib/blocktree/blocktree_test.go @@ -8,12 +8,12 @@ import ( "fmt" "math/big" "math/rand" - "reflect" "testing" "time" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/pkg/scale" "github.com/stretchr/testify/require" ) @@ -37,6 +37,23 @@ func newBlockTreeFromNode(root *node) *BlockTree { } } +func createPrimaryBABEDigest(t *testing.T) scale.VaryingDataTypeSlice { + babeDigest := types.NewBabeDigest() + err := babeDigest.Set(types.BabePrimaryPreDigest{AuthorityIndex: 0}) + require.NoError(t, err) + + bdEnc, err := scale.Marshal(babeDigest) + require.NoError(t, err) + + digest := types.NewDigest() + err = digest.Add(types.PreRuntimeDigest{ + ConsensusEngineID: types.BabeEngineID, + Data: bdEnc, + }) + require.NoError(t, err) + return digest +} + func createTestBlockTree(t *testing.T, header *types.Header, number int) (*BlockTree, []testBranch) { bt := NewBlockTreeFromRoot(header) previousHash := header.Hash() @@ -52,7 +69,7 @@ func createTestBlockTree(t *testing.T, header *types.Header, number int) (*Block header := &types.Header{ ParentHash: previousHash, Number: big.NewInt(int64(i)), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() @@ -83,7 +100,7 @@ func createTestBlockTree(t *testing.T, header *types.Header, number int) (*Block ParentHash: previousHash, Number: big.NewInt(int64(i) + 1), StateRoot: common.Hash{0x1}, - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() @@ -100,9 +117,14 @@ func createTestBlockTree(t *testing.T, header *types.Header, number int) (*Block } func createFlatTree(t *testing.T, number int) (*BlockTree, []common.Hash) { - bt := NewBlockTreeFromRoot(testHeader) - require.NotNil(t, bt) + rootHeader := &types.Header{ + ParentHash: zeroHash, + Number: big.NewInt(0), + Digest: createPrimaryBABEDigest(t), + } + bt := NewBlockTreeFromRoot(rootHeader) + require.NotNil(t, bt) previousHash := bt.root.hash hashes := []common.Hash{bt.root.hash} @@ -110,7 +132,7 @@ func createFlatTree(t *testing.T, number int) (*BlockTree, []common.Hash) { header := &types.Header{ ParentHash: previousHash, Number: big.NewInt(int64(i)), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() @@ -162,6 +184,7 @@ func TestBlockTree_AddBlock(t *testing.T) { header := &types.Header{ ParentHash: hashes[1], Number: big.NewInt(2), + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() @@ -197,28 +220,6 @@ func TestNode_isDecendantOf(t *testing.T) { } } -func TestBlockTree_LongestPath(t *testing.T) { - bt, hashes := createFlatTree(t, 3) - - // Insert a block to create a competing path - header := &types.Header{ - ParentHash: hashes[0], - Number: big.NewInt(1), - } - - header.Hash() - err := bt.AddBlock(header, time.Unix(0, 0)) - require.NotNil(t, err) - - longestPath := bt.longestPath() - - for i, n := range longestPath { - if n.hash != hashes[i] { - t.Errorf("expected Hash: 0x%X got: 0x%X\n", hashes[i], n.hash) - } - } -} - func TestBlockTree_Subchain(t *testing.T) { bt, hashes := createFlatTree(t, 4) expectedPath := hashes[1:] @@ -227,7 +228,7 @@ func TestBlockTree_Subchain(t *testing.T) { extraBlock := &types.Header{ ParentHash: hashes[0], Number: big.NewInt(1), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), } extraBlock.Hash() @@ -246,7 +247,7 @@ func TestBlockTree_Subchain(t *testing.T) { } } -func TestBlockTree_DeepestLeaf(t *testing.T) { +func TestBlockTree_Best_AllPrimary(t *testing.T) { arrivalTime := int64(256) var expected Hash @@ -265,10 +266,7 @@ func TestBlockTree_DeepestLeaf(t *testing.T) { t.Logf("leaf=%s number=%d arrivalTime=%s", leaf, node.number, node.arrivalTime) } - deepestLeaf := bt.deepestLeaf() - if deepestLeaf.hash != expected { - t.Fatalf("Fail: got %s expected %s", deepestLeaf.hash, expected) - } + require.Equal(t, expected, bt.best().hash) } func TestBlockTree_GetNode(t *testing.T) { @@ -279,6 +277,7 @@ func TestBlockTree_GetNode(t *testing.T) { ParentHash: branch.hash, Number: big.NewInt(0).Add(branch.number, big.NewInt(1)), StateRoot: Hash{0x2}, + Digest: createPrimaryBABEDigest(t), } err := bt.AddBlock(header, time.Unix(0, 0)) @@ -307,20 +306,15 @@ func TestBlockTree_GetAllBlocksAtNumber(t *testing.T) { previousHash := btHashes[4] for i := 4; i <= btNumber; i++ { - digest := types.NewDigest() - err := digest.Add(types.ConsensusDigest{ - ConsensusEngineID: types.BabeEngineID, - Data: common.MustHexToBytes("0x0118ca239392960473fe1bc65f94ee27d890a49c1b200c006ff5dcc525330ecc16770100000000000000b46f01874ce7abbb5220e8fd89bede0adad14c73039d91e28e881823433e723f0100000000000000d684d9176d6eb69887540c9a89fa6097adea82fc4b0ff26d1062b488f352e179010000000000000068195a71bdde49117a616424bdc60a1733e96acb1da5aeab5d268cf2a572e94101000000000000001a0575ef4ae24bdfd31f4cb5bd61239ae67c12d4e64ae51ac756044aa6ad8200010000000000000018168f2aad0081a25728961ee00627cfe35e39833c805016632bf7c14da5800901000000000000000000000000000000000000000000000000000000000000000000000000000000"), //nolint:lll - }) - require.NoError(t, err) header := &types.Header{ ParentHash: previousHash, + StateRoot: common.Hash{0x99}, Number: big.NewInt(int64(i) + 1), - Digest: digest, + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() - err = bt.AddBlock(header, time.Unix(0, 0)) + err := bt.AddBlock(header, time.Unix(0, 0)) require.NoError(t, err) previousHash = hash @@ -333,20 +327,15 @@ func TestBlockTree_GetAllBlocksAtNumber(t *testing.T) { previousHash = btHashes[2] for i := 2; i <= btNumber; i++ { - digest := types.NewDigest() - err := digest.Add(types.SealDigest{ - ConsensusEngineID: types.BabeEngineID, - Data: common.MustHexToBytes("0x4625284883e564bc1e4063f5ea2b49846cdddaa3761d04f543b698c1c3ee935c40d25b869247c36c6b8a8cbbd7bb2768f560ab7c276df3c62df357a7e3b1ec8d"), //nolint:lll - }) - require.NoError(t, err) header := &types.Header{ ParentHash: previousHash, + StateRoot: common.Hash{0x88}, Number: big.NewInt(int64(i) + 1), - Digest: digest, + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() - err = bt.AddBlock(header, time.Unix(0, 0)) + err := bt.AddBlock(header, time.Unix(0, 0)) require.NoError(t, err) previousHash = hash @@ -356,9 +345,7 @@ func TestBlockTree_GetAllBlocksAtNumber(t *testing.T) { } hashes = bt.root.getNodesWithNumber(big.NewInt(int64(desiredNumber)), []common.Hash{}) - if !reflect.DeepEqual(hashes, expected) { - t.Fatalf("Fail: did not get all expected hashes got %v expected %v", hashes, expected) - } + require.Equal(t, expected, hashes) } func TestBlockTree_IsDecendantOf(t *testing.T) { @@ -458,7 +445,7 @@ func TestBlockTree_Prune(t *testing.T) { func TestBlockTree_GetHashByNumber(t *testing.T) { bt, _ := createTestBlockTree(t, testHeader, 8) - best := bt.DeepestBlockHash() + best := bt.BestBlockHash() bn := bt.getNode(best) for i := int64(0); i < bn.number.Int64(); i++ { @@ -477,14 +464,14 @@ func TestBlockTree_GetHashByNumber(t *testing.T) { require.Error(t, err) } -func TestBlockTree_AllLeavesHasSameNumberAndArrivalTime_DeepestBlockHash_ShouldHasConsistentOutput(t *testing.T) { +func TestBlockTree_BestBlockHash_AllChainsEqual(t *testing.T) { bt := NewBlockTreeFromRoot(testHeader) previousHash := testHeader.Hash() branches := []testBranch{} const fixedArrivalTime = 99 - const deep = 8 + const depth = 4 // create a base tree with a fixed amount of blocks // and all block with the same arrival time @@ -503,11 +490,11 @@ func TestBlockTree_AllLeavesHasSameNumberAndArrivalTime_DeepestBlockHash_ShouldH |> c -> d -> e -> f -> g -> h (2) **/ - for i := 1; i <= deep; i++ { + for i := 1; i <= depth; i++ { header := &types.Header{ ParentHash: previousHash, Number: big.NewInt(int64(i)), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() @@ -518,7 +505,7 @@ func TestBlockTree_AllLeavesHasSameNumberAndArrivalTime_DeepestBlockHash_ShouldH previousHash = hash // the last block on the base tree should not generates a branch - if i < deep { + if i < depth { branches = append(branches, testBranch{ hash: hash, number: bt.getNode(hash).number, @@ -530,12 +517,12 @@ func TestBlockTree_AllLeavesHasSameNumberAndArrivalTime_DeepestBlockHash_ShouldH for _, branch := range branches { previousHash = branch.hash - for i := int(branch.number.Uint64()); i < deep; i++ { + for i := int(branch.number.Uint64()); i < depth; i++ { header := &types.Header{ ParentHash: previousHash, Number: big.NewInt(int64(i) + 1), StateRoot: common.Hash{0x1}, - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() @@ -556,30 +543,31 @@ func TestBlockTree_AllLeavesHasSameNumberAndArrivalTime_DeepestBlockHash_ShouldH require.Equal(t, curr.arrivalTime, next.arrivalTime) } - require.Len(t, leaves, deep) + require.Len(t, leaves, depth) + require.Contains(t, leaves, bt.best()) - // expects currentDeepestLeaf nil till call deepestLeaf() function - require.Nil(t, bt.leaves.currentDeepestLeaf) - deepestLeaf := bt.deepestLeaf() + // check that highest returned was one with lowest hash + expected := leaves[0].hash + for _, leaf := range leaves { + if bytes.Compare(leaf.hash[:], expected[:]) < 0 { + expected = leaf.hash + } + } - require.Equal(t, deepestLeaf, bt.leaves.currentDeepestLeaf) - require.Contains(t, leaves, deepestLeaf) + require.Equal(t, bt.best().hash, expected) - // adding a new node with a greater number, should update the currentDeepestLeaf + // adding a new node with a greater number should update the best block header := &types.Header{ ParentHash: previousHash, - Number: big.NewInt(int64(deepestLeaf.number.Uint64() + 1)), + Number: big.NewInt(int64(bt.best().number.Uint64() + 1)), StateRoot: common.Hash{0x1}, - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() err := bt.AddBlock(header, time.Unix(0, fixedArrivalTime)) require.NoError(t, err) - - deepestLeaf = bt.deepestLeaf() - require.Equal(t, hash, deepestLeaf.hash) - require.Equal(t, hash, bt.leaves.currentDeepestLeaf.hash) + require.Equal(t, hash, bt.best().hash) } func TestBlockTree_DeepCopy(t *testing.T) { @@ -627,3 +615,99 @@ func equalLeaves(lm *leafMap, lmCopy *leafMap) bool { } return true } + +func TestBlockTree_best(t *testing.T) { + // test basic case where two chains have different amount of primaries + bt := NewEmptyBlockTree() + bt.root = &node{ + hash: common.Hash{0}, + } + + bt.root.children = []*node{ + { + hash: common.Hash{1}, + parent: bt.root, + isPrimary: true, + }, + { + hash: common.Hash{2}, + parent: bt.root, + isPrimary: false, + }, + } + + bt.leaves = newEmptyLeafMap() + bt.leaves.store(bt.root.children[0].hash, bt.root.children[0]) + bt.leaves.store(bt.root.children[1].hash, bt.root.children[1]) + require.Equal(t, bt.root.children[0].hash, bt.BestBlockHash()) + + // test case where two chains have the same amount of primaries + // and the head numbers are also equal + // should pick the chain with the lowest arrival time or block hash + bt = NewEmptyBlockTree() + bt.root = &node{ + hash: common.Hash{0}, + } + + bt.root.children = []*node{ + { + hash: common.Hash{1}, + parent: bt.root, + number: big.NewInt(1), + isPrimary: true, + }, + { + hash: common.Hash{2}, + parent: bt.root, + isPrimary: false, + }, + } + + bt.root.children[1].children = []*node{ + { + hash: common.Hash{3}, + parent: bt.root.children[1], + number: big.NewInt(1), + isPrimary: true, + }, + } + + bt.leaves = newEmptyLeafMap() + bt.leaves.store(bt.root.children[0].hash, bt.root.children[0]) + bt.leaves.store(bt.root.children[1].children[0].hash, bt.root.children[1].children[0]) + require.Equal(t, bt.root.children[0].hash, bt.BestBlockHash()) + + // test case where three chains have the same amount of primaries + // and the head numbers are also equal + // should pick the chain with the lowest arrival time or block hash + bt = NewEmptyBlockTree() + bt.root = &node{ + hash: common.Hash{0}, + } + + bt.root.children = []*node{ + { + hash: common.Hash{3}, + parent: bt.root, + number: big.NewInt(1), + isPrimary: true, + }, + { + hash: common.Hash{2}, + parent: bt.root, + isPrimary: false, + }, + { + hash: common.Hash{1}, + parent: bt.root, + number: big.NewInt(1), + isPrimary: true, + }, + } + + bt.leaves = newEmptyLeafMap() + bt.leaves.store(bt.root.children[0].hash, bt.root.children[0]) + bt.leaves.store(bt.root.children[1].hash, bt.root.children[1]) + bt.leaves.store(bt.root.children[2].hash, bt.root.children[2]) + require.Equal(t, bt.root.children[2].hash, bt.BestBlockHash()) +} diff --git a/lib/blocktree/leaves.go b/lib/blocktree/leaves.go index f7c1f4ecc0..86dbe366c6 100644 --- a/lib/blocktree/leaves.go +++ b/lib/blocktree/leaves.go @@ -4,6 +4,7 @@ package blocktree import ( + "bytes" "errors" "math/big" "sync" @@ -13,7 +14,6 @@ import ( // leafMap provides quick lookup for existing leaves type leafMap struct { - currentDeepestLeaf *node sync.RWMutex smap *sync.Map // map[common.Hash]*node } @@ -56,9 +56,9 @@ func (lm *leafMap) replace(oldNode, newNode *node) { lm.store(newNode.hash, newNode) } -// DeepestLeaf searches the stored leaves to the find the one with the greatest number. +// highestLeaf searches the stored leaves to the find the one with the greatest number. // If there are two leaves with the same number, choose the one with the earliest arrival time. -func (lm *leafMap) deepestLeaf() *node { +func (lm *leafMap) highestLeaf() *node { lm.RLock() defer lm.RUnlock() @@ -66,41 +66,30 @@ func (lm *leafMap) deepestLeaf() *node { var deepest *node lm.smap.Range(func(h, n interface{}) bool { - if n == nil { + node := n.(*node) + if node == nil { + // this should never happen return true } - node := n.(*node) - if max.Cmp(node.number) < 0 { max = node.number deepest = node } else if max.Cmp(node.number) == 0 && node.arrivalTime.Before(deepest.arrivalTime) { deepest = node + } else if max.Cmp(node.number) == 0 && node.arrivalTime.Equal(deepest.arrivalTime) { + // there are two leaf nodes with the same number *and* arrival time, just pick the one + // with the lower hash in lexicographical order. + // practically, this is very unlikely to happen. + if bytes.Compare(node.hash[:], deepest.hash[:]) < 0 { + deepest = node + } } return true }) - if lm.currentDeepestLeaf != nil { - if lm.currentDeepestLeaf.hash == deepest.hash { - return lm.currentDeepestLeaf - } - - // update the current deepest leaf if the found deepest has a greater number or - // if the current and the found deepest has the same number however the current - // arrived later then the found deepest - if deepest.number.Cmp(lm.currentDeepestLeaf.number) == 1 { - lm.currentDeepestLeaf = deepest - } else if deepest.number.Cmp(lm.currentDeepestLeaf.number) == 0 && - deepest.arrivalTime.Before(lm.currentDeepestLeaf.arrivalTime) { - lm.currentDeepestLeaf = deepest - } - } else { - lm.currentDeepestLeaf = deepest - } - - return lm.currentDeepestLeaf + return deepest } func (lm *leafMap) toMap() map[common.Hash]*node { @@ -133,3 +122,43 @@ func (lm *leafMap) nodes() []*node { return nodes } + +func (lm *leafMap) bestBlock() *node { + lm.RLock() + defer lm.RUnlock() + + // map of primary ancestor count -> *node + counts := make(map[int][]*node) + highest := 0 + + lm.smap.Range(func(_, nn interface{}) bool { + n := nn.(*node) + count := n.primaryAncestorCount(0) + if count > highest { + highest = count + } + + nodesWithCount, has := counts[count] + if !has { + counts[count] = []*node{n} + } else { + counts[count] = append(nodesWithCount, n) + } + + return true + }) + + // there's just one node with the highest amount of primary ancestors, + // so let's return it + if len(counts[highest]) == 1 { + return counts[highest][0] + } + + // there are multple with the highest count, run them through `highestLeaf` + lm2 := newEmptyLeafMap() + for _, node := range counts[highest] { + lm2.store(node.hash, node) + } + + return lm2.highestLeaf() +} diff --git a/lib/blocktree/node.go b/lib/blocktree/node.go index 791584ffab..d0efb29e5f 100644 --- a/lib/blocktree/node.go +++ b/lib/blocktree/node.go @@ -19,6 +19,7 @@ type node struct { children []*node // Nodes of children blocks number *big.Int // block number arrivalTime time.Time // Arrival time of the block + isPrimary bool // whether the block was authored in a primary slot or not } // addChild appends Node to n's list of children @@ -236,3 +237,17 @@ func (n *node) deleteChild(toDelete *node) { } } } + +func (n *node) primaryAncestorCount(count int) int { + if n == nil { + return count + } + + if n.isPrimary && n.parent != nil { + // if parent is nil, we're at the root node + // we don't need to count it, as all blocks have the root as an ancestor + count++ + } + + return n.parent.primaryAncestorCount(count) +} diff --git a/lib/blocktree/node_test.go b/lib/blocktree/node_test.go index 7525e22d72..333db53f96 100644 --- a/lib/blocktree/node_test.go +++ b/lib/blocktree/node_test.go @@ -61,3 +61,18 @@ func TestNode_Prune(t *testing.T) { } } } + +func TestNode_primaryAncestorCount(t *testing.T) { + bt, hashes := createFlatTree(t, 16) + require.Equal(t, 0, bt.root.primaryAncestorCount(0)) + require.Equal(t, 15, bt.getNode(hashes[15]).primaryAncestorCount(0)) + + for i, hash := range hashes { + n := bt.getNode(hash) + if i%2 == 0 { + n.isPrimary = false + } + } + + require.Equal(t, 8, bt.getNode(hashes[15]).primaryAncestorCount(0)) +} diff --git a/lib/grandpa/grandpa_test.go b/lib/grandpa/grandpa_test.go index 6a438bebea..f52c86f7a1 100644 --- a/lib/grandpa/grandpa_test.go +++ b/lib/grandpa/grandpa_test.go @@ -5,7 +5,6 @@ package grandpa import ( "math/big" - "math/rand" "sort" "sync" "testing" @@ -181,7 +180,7 @@ func TestGetVotesForBlock_NoDescendantVotes(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() // 1/3 of voters equivocate; ie. vote for both blocks @@ -218,7 +217,7 @@ func TestGetVotesForBlock_DescendantVotes(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() a, err := st.Block.GetHeader(leaves[0]) @@ -270,7 +269,7 @@ func TestGetPossibleSelectedAncestors_SameAncestor(t *testing.T) { // this creates a tree with 3 branches all starting at depth 6 branches := make(map[int]int) branches[6] = 2 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, 0) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() require.Equal(t, 3, len(leaves)) @@ -326,7 +325,7 @@ func TestGetPossibleSelectedAncestors_VaryingAncestor(t *testing.T) { branches := make(map[int]int) branches[6] = 1 branches[7] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() require.Equal(t, 3, len(leaves)) @@ -382,7 +381,7 @@ func TestGetPossibleSelectedAncestors_VaryingAncestor_MoreBranches(t *testing.T) branches := make(map[int]int) branches[6] = 2 branches[7] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() require.Equal(t, 4, len(leaves)) @@ -442,7 +441,7 @@ func TestGetPossibleSelectedBlocks_OneBlock(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -477,7 +476,7 @@ func TestGetPossibleSelectedBlocks_EqualVotes_SameAncestor(t *testing.T) { branches := make(map[int]int) branches[6] = 2 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() require.Equal(t, 3, len(leaves)) @@ -525,7 +524,7 @@ func TestGetPossibleSelectedBlocks_EqualVotes_VaryingAncestor(t *testing.T) { branches := make(map[int]int) branches[6] = 1 branches[7] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() require.Equal(t, 3, len(leaves)) @@ -573,7 +572,7 @@ func TestGetPossibleSelectedBlocks_OneThirdEquivocating(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() // 1/3 of voters equivocate; ie. vote for both blocks @@ -616,7 +615,7 @@ func TestGetPossibleSelectedBlocks_MoreThanOneThirdEquivocating(t *testing.T) { branches := make(map[int]int) branches[6] = 1 branches[7] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() // this tests a byzantine case where >1/3 of voters equivocate; ie. vote for multiple blocks @@ -664,7 +663,7 @@ func TestGetPreVotedBlock_OneBlock(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -698,7 +697,7 @@ func TestGetPreVotedBlock_MultipleCandidates(t *testing.T) { branches := make(map[int]int) branches[6] = 1 branches[7] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() require.Equal(t, 3, len(leaves)) @@ -749,7 +748,7 @@ func TestGetPreVotedBlock_EvenMoreCandidates(t *testing.T) { branches[5] = 1 branches[6] = 1 branches[7] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(0)) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() require.Equal(t, 6, len(leaves)) @@ -817,7 +816,7 @@ func TestIsCompletable(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -855,7 +854,7 @@ func TestFindParentWithNumber(t *testing.T) { // no branches needed branches := make(map[int]int) - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() v, err := NewVoteFromHash(leaves[0], st.Block) @@ -877,7 +876,7 @@ func TestGetBestFinalCandidate_OneBlock(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -916,7 +915,7 @@ func TestGetBestFinalCandidate_PrecommitAncestor(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -960,7 +959,7 @@ func TestGetBestFinalCandidate_NoPrecommit(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -997,7 +996,7 @@ func TestGetBestFinalCandidate_PrecommitOnAnotherChain(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -1093,7 +1092,7 @@ func TestIsFinalisable_True(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -1131,7 +1130,7 @@ func TestIsFinalisable_False(t *testing.T) { branches := make(map[int]int) branches[2] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 3, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 3, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -1176,7 +1175,7 @@ func TestGetGrandpaGHOST_CommonAncestor(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -1213,7 +1212,7 @@ func TestGetGrandpaGHOST_MultipleCandidates(t *testing.T) { branches := make(map[int]int) branches[3] = 1 branches[7] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, byte(rand.Intn(256))) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() require.Equal(t, 3, len(leaves)) diff --git a/lib/grandpa/message_handler_test.go b/lib/grandpa/message_handler_test.go index 437d755c4c..fafb7eb761 100644 --- a/lib/grandpa/message_handler_test.go +++ b/lib/grandpa/message_handler_test.go @@ -206,7 +206,7 @@ func TestMessageHandler_NeighbourMessage(t *testing.T) { digest := types.NewDigest() prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() require.NoError(t, err) - err = digest.Add(prd) + err = digest.Add(*prd) require.NoError(t, err) body, err := types.NewBodyFromBytes([]byte{0}) @@ -379,7 +379,7 @@ func TestMessageHandler_CatchUpRequest_WithResponse(t *testing.T) { digest := types.NewDigest() prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() require.NoError(t, err) - err = digest.Add(prd) + err = digest.Add(*prd) require.NoError(t, err) block := &types.Block{ Header: types.Header{ diff --git a/lib/grandpa/message_tracker_test.go b/lib/grandpa/message_tracker_test.go index f2b147d118..f71c3ef027 100644 --- a/lib/grandpa/message_tracker_test.go +++ b/lib/grandpa/message_tracker_test.go @@ -55,9 +55,16 @@ func TestMessageTracker_SendMessage(t *testing.T) { parent, err := gs.blockState.BestBlockHeader() require.NoError(t, err) + digest := types.NewDigest() + prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + require.NoError(t, err) + err = digest.Add(*prd) + require.NoError(t, err) + next := &types.Header{ ParentHash: parent.Hash(), Number: big.NewInt(4), + Digest: digest, } gs.keypair = kr.Alice().(*ed25519.Keypair) @@ -101,9 +108,16 @@ func TestMessageTracker_ProcessMessage(t *testing.T) { parent, err := gs.blockState.BestBlockHeader() require.NoError(t, err) + digest := types.NewDigest() + prd, err := types.NewBabeSecondaryPlainPreDigest(0, 1).ToPreRuntimeDigest() + require.NoError(t, err) + err = digest.Add(*prd) + require.NoError(t, err) + next := &types.Header{ ParentHash: parent.Hash(), Number: big.NewInt(4), + Digest: digest, } gs.keypair = kr.Alice().(*ed25519.Keypair) diff --git a/lib/grandpa/round_test.go b/lib/grandpa/round_test.go index 20accba72b..45ba007bc1 100644 --- a/lib/grandpa/round_test.go +++ b/lib/grandpa/round_test.go @@ -420,7 +420,6 @@ func TestPlayGrandpaRound_WithEquivocation(t *testing.T) { fins := make([]chan GrandpaMessage, len(kr.Keys)) done := false - r := byte(rand.Intn(256)) for i := range gss { gs, in, out, fin := setupGrandpa(t, kr.Keys[i]) @@ -434,7 +433,7 @@ func TestPlayGrandpaRound_WithEquivocation(t *testing.T) { // this creates a tree with 2 branches starting at depth 2 branches := make(map[int]int) branches[2] = 1 - state.AddBlocksToStateWithFixedBranches(t, gs.blockState.(*state.BlockState), 4, branches, r) + state.AddBlocksToStateWithFixedBranches(t, gs.blockState.(*state.BlockState), 4, branches) } // should have blocktree for all nodes diff --git a/lib/grandpa/vote_message_test.go b/lib/grandpa/vote_message_test.go index c3da00ba21..0f1eebc12a 100644 --- a/lib/grandpa/vote_message_test.go +++ b/lib/grandpa/vote_message_test.go @@ -72,7 +72,7 @@ func TestCheckForEquivocation_WithEquivocation(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, 0) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() vote1, err := NewVoteFromHash(leaves[0], st.Block) @@ -119,7 +119,7 @@ func TestCheckForEquivocation_WithExistingEquivocation(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, 0) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() vote1, err := NewVoteFromHash(leaves[1], gs.blockState) @@ -279,7 +279,7 @@ func TestValidateMessage_Equivocation(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, 0) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() voteA, err := NewVoteFromHash(leaves[0], st.Block) @@ -360,7 +360,7 @@ func TestValidateMessage_IsNotDescendant(t *testing.T) { branches := make(map[int]int) branches[6] = 1 - state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches, 0) + state.AddBlocksToStateWithFixedBranches(t, st.Block, 8, branches) leaves := gs.blockState.Leaves() gs.head, err = gs.blockState.GetHeader(leaves[0])