From acc43e694b6ee41ead76ec361b9b7e8ef690e533 Mon Sep 17 00:00:00 2001 From: noot Date: Thu, 27 Jan 2022 16:26:41 -0500 Subject: [PATCH 01/13] initial impl of fork choice rule using primary/secondary slots --- dot/state/block.go | 2 +- dot/types/babe.go | 24 +++++++++++++ lib/blocktree/blocktree.go | 72 +++++++++++++++++++++++--------------- lib/blocktree/leaves.go | 70 +++++++++++++++++++++++++++++------- lib/blocktree/node.go | 13 +++++++ 5 files changed, 138 insertions(+), 43 deletions(-) diff --git a/dot/state/block.go b/dot/state/block.go index 48aca54bd2..231e7dd6f5 100644 --- a/dot/state/block.go +++ b/dot/state/block.go @@ -475,7 +475,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/types/babe.go b/dot/types/babe.go index 4156d592a5..90f6e82fd1 100644 --- a/dot/types/babe.go +++ b/dot/types/babe.go @@ -114,3 +114,27 @@ 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 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") + } + + 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 f3aaf88da7..72f3d5213f 100644 --- a/lib/blocktree/blocktree.go +++ b/lib/blocktree/blocktree.go @@ -76,12 +76,18 @@ func (bt *BlockTree) AddBlock(header *types.Header, arrivalTime time.Time) error return errUnexpectedNumber } + 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) @@ -188,17 +194,17 @@ 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 - } - } -} +// // 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) { @@ -230,27 +236,35 @@ 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() -} - -// 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 { +// // deepestLeaf returns the deepest leaf in the block tree. +// func (bt *BlockTree) deepestLeaf() *node { +// return bt.leaves.deepestLeaf() +// } + +// 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{} - } + best := bt.leaves.bestBlock() + return best.hash + + // deepest := bt.leaves.deepestLeaf() + // if deepest == nil { + // return Hash{} + // } - return deepest.hash + // return deepest.hash } // IsDescendantOf returns true if the child is a descendant of parent, false otherwise. @@ -326,13 +340,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 { @@ -343,7 +357,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/leaves.go b/lib/blocktree/leaves.go index f7c1f4ecc0..0c5833a9e5 100644 --- a/lib/blocktree/leaves.go +++ b/lib/blocktree/leaves.go @@ -13,7 +13,7 @@ import ( // leafMap provides quick lookup for existing leaves type leafMap struct { - currentDeepestLeaf *node + currHighestLeaf *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() @@ -82,25 +82,25 @@ func (lm *leafMap) deepestLeaf() *node { return true }) - if lm.currentDeepestLeaf != nil { - if lm.currentDeepestLeaf.hash == deepest.hash { - return lm.currentDeepestLeaf + if lm.currHighestLeaf != nil { + if lm.currHighestLeaf.hash == deepest.hash { + return lm.currHighestLeaf } // 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 + if deepest.number.Cmp(lm.currHighestLeaf.number) == 1 { + lm.currHighestLeaf = deepest + } else if deepest.number.Cmp(lm.currHighestLeaf.number) == 0 && + deepest.arrivalTime.Before(lm.currHighestLeaf.arrivalTime) { + lm.currHighestLeaf = deepest } } else { - lm.currentDeepestLeaf = deepest + lm.currHighestLeaf = deepest } - return lm.currentDeepestLeaf + return lm.currHighestLeaf } func (lm *leafMap) toMap() map[common.Hash]*node { @@ -133,3 +133,47 @@ 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) + + lm.smap.Range(func(_, nn interface{}) bool { + n := nn.(*node) + count := n.primaryAncestorCount(0) + + nodesWithCount, has := counts[count] + if !has { + counts[count] = []*node{n} + } else { + counts[count] = append(nodesWithCount, n) + } + + return true + }) + + // get highest count + highest := 0 + for count := range counts { + if count > highest { + highest = count + } + } + + // 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..4e584d85b0 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,15 @@ func (n *node) deleteChild(toDelete *node) { } } } + +func (n *node) primaryAncestorCount(count int) int { + if n == nil { + return count + } + + if n.isPrimary { + count++ + } + + return n.parent.primaryAncestorCount(count) +} From f63f0731b0ecccb5c570ca2cca1087f34bf67099 Mon Sep 17 00:00:00 2001 From: noot Date: Thu, 27 Jan 2022 16:44:36 -0500 Subject: [PATCH 02/13] add primaryAncestorCount unit test --- lib/blocktree/blocktree.go | 8 +- lib/blocktree/blocktree_test.go | 135 ++++++++++++++++---------------- lib/blocktree/node.go | 4 +- lib/blocktree/node_test.go | 15 ++++ 4 files changed, 90 insertions(+), 72 deletions(-) diff --git a/lib/blocktree/blocktree.go b/lib/blocktree/blocktree.go index 72f3d5213f..d59c73f8f4 100644 --- a/lib/blocktree/blocktree.go +++ b/lib/blocktree/blocktree.go @@ -236,10 +236,10 @@ 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() +} // 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. diff --git a/lib/blocktree/blocktree_test.go b/lib/blocktree/blocktree_test.go index b7d2bc1639..654994bea2 100644 --- a/lib/blocktree/blocktree_test.go +++ b/lib/blocktree/blocktree_test.go @@ -14,6 +14,7 @@ import ( "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/pkg/scale" "github.com/stretchr/testify/require" ) @@ -100,9 +101,30 @@ 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) + babeDigest := types.NewBabeDigest() + err := babeDigest.Set(types.BabePrimaryPreDigest{AuthorityIndex: 0}) + require.NoError(t, err) + + bdEnc, err := scale.Marshal(babeDigest) + require.NoError(t, err) + digestPrimary := types.NewDigest() + err = digestPrimary.Add(types.PreRuntimeDigest{ + ConsensusEngineID: types.BabeEngineID, + Data: bdEnc, + }) + require.NoError(t, err) + headerPrimary := types.NewEmptyHeader() + headerPrimary.Digest = digestPrimary + + rootHeader := &types.Header{ + ParentHash: zeroHash, + Number: big.NewInt(0), + Digest: digestPrimary, + } + + 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: digestPrimary, } hash := header.Hash() @@ -197,28 +219,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:] @@ -246,30 +246,30 @@ func TestBlockTree_Subchain(t *testing.T) { } } -func TestBlockTree_DeepestLeaf(t *testing.T) { - arrivalTime := int64(256) - var expected Hash +// func TestBlockTree_DeepestLeaf(t *testing.T) { +// arrivalTime := int64(256) +// var expected Hash - bt, _ := createTestBlockTree(t, testHeader, 8) +// bt, _ := createTestBlockTree(t, testHeader, 8) - deepest := big.NewInt(0) +// deepest := big.NewInt(0) - for leaf, node := range bt.leaves.toMap() { - node.arrivalTime = time.Unix(arrivalTime, 0) - arrivalTime-- - if node.number.Cmp(deepest) >= 0 { - deepest = node.number - expected = leaf - } +// for leaf, node := range bt.leaves.toMap() { +// node.arrivalTime = time.Unix(arrivalTime, 0) +// arrivalTime-- +// if node.number.Cmp(deepest) >= 0 { +// deepest = node.number +// expected = leaf +// } - t.Logf("leaf=%s number=%d arrivalTime=%s", leaf, node.number, node.arrivalTime) - } +// 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) - } -} +// deepestLeaf := bt.deepestLeaf() +// if deepestLeaf.hash != expected { +// t.Fatalf("Fail: got %s expected %s", deepestLeaf.hash, expected) +// } +// } func TestBlockTree_GetNode(t *testing.T) { bt, branches := createTestBlockTree(t, testHeader, 16) @@ -458,7 +458,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,7 +477,7 @@ func TestBlockTree_GetHashByNumber(t *testing.T) { require.Error(t, err) } -func TestBlockTree_AllLeavesHasSameNumberAndArrivalTime_DeepestBlockHash_ShouldHasConsistentOutput(t *testing.T) { +func TestBlockTree_AllLeavesHasSameNumberAndArrivalTime_BestBlockHash(t *testing.T) { bt := NewBlockTreeFromRoot(testHeader) previousHash := testHeader.Hash() @@ -559,27 +559,28 @@ func TestBlockTree_AllLeavesHasSameNumberAndArrivalTime_DeepestBlockHash_ShouldH require.Len(t, leaves, deep) // expects currentDeepestLeaf nil till call deepestLeaf() function - require.Nil(t, bt.leaves.currentDeepestLeaf) - deepestLeaf := bt.deepestLeaf() - - require.Equal(t, deepestLeaf, bt.leaves.currentDeepestLeaf) - require.Contains(t, leaves, deepestLeaf) - - // adding a new node with a greater number, should update the currentDeepestLeaf - header := &types.Header{ - ParentHash: previousHash, - Number: big.NewInt(int64(deepestLeaf.number.Uint64() + 1)), - StateRoot: common.Hash{0x1}, - Digest: types.NewDigest(), - } - - 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.Nil(t, bt.leaves.currHighestLeaf) + + // TODO: will need to update this test + // deepestLeaf := bt.best() + // require.Equal(t, deepestLeaf, bt.leaves.currHighestLeaf) + // require.Contains(t, leaves, deepestLeaf) + + // // adding a new node with a greater number, should update the currentDeepestLeaf + // header := &types.Header{ + // ParentHash: previousHash, + // Number: big.NewInt(int64(deepestLeaf.number.Uint64() + 1)), + // StateRoot: common.Hash{0x1}, + // Digest: types.NewDigest(), + // } + + // 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.currHighestLeaf.hash) } func TestBlockTree_DeepCopy(t *testing.T) { diff --git a/lib/blocktree/node.go b/lib/blocktree/node.go index 4e584d85b0..d0efb29e5f 100644 --- a/lib/blocktree/node.go +++ b/lib/blocktree/node.go @@ -243,7 +243,9 @@ func (n *node) primaryAncestorCount(count int) int { return count } - if n.isPrimary { + 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++ } 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)) +} From ab2e531e1f8f6341185b9c44ea04e9250f8fb1b2 Mon Sep 17 00:00:00 2001 From: noot Date: Thu, 27 Jan 2022 16:55:02 -0500 Subject: [PATCH 03/13] add unit test for blocktree.best --- lib/blocktree/blocktree.go | 12 ++++-------- lib/blocktree/blocktree_test.go | 28 +++++++++++++++++++++++++++- lib/blocktree/leaves.go | 3 +++ 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/lib/blocktree/blocktree.go b/lib/blocktree/blocktree.go index d59c73f8f4..6a5660b3fa 100644 --- a/lib/blocktree/blocktree.go +++ b/lib/blocktree/blocktree.go @@ -256,15 +256,11 @@ func (bt *BlockTree) BestBlockHash() Hash { return Hash{} } - best := bt.leaves.bestBlock() - return best.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. diff --git a/lib/blocktree/blocktree_test.go b/lib/blocktree/blocktree_test.go index 654994bea2..7d84838131 100644 --- a/lib/blocktree/blocktree_test.go +++ b/lib/blocktree/blocktree_test.go @@ -477,7 +477,7 @@ func TestBlockTree_GetHashByNumber(t *testing.T) { require.Error(t, err) } -func TestBlockTree_AllLeavesHasSameNumberAndArrivalTime_BestBlockHash(t *testing.T) { +func TestBlockTree_BestBlockHash_AllChainsEqual(t *testing.T) { bt := NewBlockTreeFromRoot(testHeader) previousHash := testHeader.Hash() @@ -628,3 +628,29 @@ func equalLeaves(lm *leafMap, lmCopy *leafMap) bool { } return true } + +func TestBlockTree_best(t *testing.T) { + 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()) +} diff --git a/lib/blocktree/leaves.go b/lib/blocktree/leaves.go index 0c5833a9e5..62f8113da2 100644 --- a/lib/blocktree/leaves.go +++ b/lib/blocktree/leaves.go @@ -8,6 +8,8 @@ import ( "math/big" "sync" + "fmt" + "github.com/ChainSafe/gossamer/lib/common" ) @@ -145,6 +147,7 @@ func (lm *leafMap) bestBlock() *node { n := nn.(*node) count := n.primaryAncestorCount(0) + fmt.Println(n, count) nodesWithCount, has := counts[count] if !has { counts[count] = []*node{n} From 32d0c23c79acffb585c4232ae0f66b66b1473cce Mon Sep 17 00:00:00 2001 From: noot Date: Fri, 28 Jan 2022 11:26:36 -0500 Subject: [PATCH 04/13] update blocktree unit tests --- lib/blocktree/blocktree.go | 12 --- lib/blocktree/blocktree_test.go | 161 +++++++++++++++----------------- lib/blocktree/leaves.go | 33 ++----- 3 files changed, 83 insertions(+), 123 deletions(-) diff --git a/lib/blocktree/blocktree.go b/lib/blocktree/blocktree.go index 6a5660b3fa..c3daf0f423 100644 --- a/lib/blocktree/blocktree.go +++ b/lib/blocktree/blocktree.go @@ -194,18 +194,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) diff --git a/lib/blocktree/blocktree_test.go b/lib/blocktree/blocktree_test.go index 7d84838131..3a5c20ed4f 100644 --- a/lib/blocktree/blocktree_test.go +++ b/lib/blocktree/blocktree_test.go @@ -8,7 +8,6 @@ import ( "fmt" "math/big" "math/rand" - "reflect" "testing" "time" @@ -38,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() @@ -53,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() @@ -84,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() @@ -101,26 +117,10 @@ func createTestBlockTree(t *testing.T, header *types.Header, number int) (*Block } func createFlatTree(t *testing.T, number int) (*BlockTree, []common.Hash) { - babeDigest := types.NewBabeDigest() - err := babeDigest.Set(types.BabePrimaryPreDigest{AuthorityIndex: 0}) - require.NoError(t, err) - - bdEnc, err := scale.Marshal(babeDigest) - require.NoError(t, err) - - digestPrimary := types.NewDigest() - err = digestPrimary.Add(types.PreRuntimeDigest{ - ConsensusEngineID: types.BabeEngineID, - Data: bdEnc, - }) - require.NoError(t, err) - headerPrimary := types.NewEmptyHeader() - headerPrimary.Digest = digestPrimary - rootHeader := &types.Header{ ParentHash: zeroHash, Number: big.NewInt(0), - Digest: digestPrimary, + Digest: createPrimaryBABEDigest(t), } bt := NewBlockTreeFromRoot(rootHeader) @@ -132,7 +132,7 @@ func createFlatTree(t *testing.T, number int) (*BlockTree, []common.Hash) { header := &types.Header{ ParentHash: previousHash, Number: big.NewInt(int64(i)), - Digest: digestPrimary, + Digest: createPrimaryBABEDigest(t), } hash := header.Hash() @@ -184,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() @@ -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,30 +247,27 @@ func TestBlockTree_Subchain(t *testing.T) { } } -// func TestBlockTree_DeepestLeaf(t *testing.T) { -// arrivalTime := int64(256) -// var expected Hash +func TestBlockTree_Best_AllPrimary(t *testing.T) { + arrivalTime := int64(256) + var expected Hash -// bt, _ := createTestBlockTree(t, testHeader, 8) + bt, _ := createTestBlockTree(t, testHeader, 8) -// deepest := big.NewInt(0) + deepest := big.NewInt(0) -// for leaf, node := range bt.leaves.toMap() { -// node.arrivalTime = time.Unix(arrivalTime, 0) -// arrivalTime-- -// if node.number.Cmp(deepest) >= 0 { -// deepest = node.number -// expected = leaf -// } + for leaf, node := range bt.leaves.toMap() { + node.arrivalTime = time.Unix(arrivalTime, 0) + arrivalTime-- + if node.number.Cmp(deepest) >= 0 { + deepest = node.number + expected = leaf + } -// t.Logf("leaf=%s number=%d arrivalTime=%s", leaf, node.number, node.arrivalTime) -// } + 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) { bt, branches := createTestBlockTree(t, testHeader, 16) @@ -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) { @@ -484,7 +471,7 @@ func TestBlockTree_BestBlockHash_AllChainsEqual(t *testing.T) { 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_BestBlockHash_AllChainsEqual(t *testing.T) { |> 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_BestBlockHash_AllChainsEqual(t *testing.T) { 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_BestBlockHash_AllChainsEqual(t *testing.T) { 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,31 +543,31 @@ func TestBlockTree_BestBlockHash_AllChainsEqual(t *testing.T) { 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.currHighestLeaf) - - // TODO: will need to update this test - // deepestLeaf := bt.best() - // require.Equal(t, deepestLeaf, bt.leaves.currHighestLeaf) - // require.Contains(t, leaves, 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 + } + } - // // adding a new node with a greater number, should update the currentDeepestLeaf - // header := &types.Header{ - // ParentHash: previousHash, - // Number: big.NewInt(int64(deepestLeaf.number.Uint64() + 1)), - // StateRoot: common.Hash{0x1}, - // Digest: types.NewDigest(), - // } + require.Equal(t, bt.best().hash, expected) - // hash := header.Hash() - // err := bt.AddBlock(header, time.Unix(0, fixedArrivalTime)) - // require.NoError(t, err) + // adding a new node with a greater number should update the best block + header := &types.Header{ + ParentHash: previousHash, + Number: big.NewInt(int64(bt.best().number.Uint64() + 1)), + StateRoot: common.Hash{0x1}, + Digest: createPrimaryBABEDigest(t), + } - // deepestLeaf = bt.deepestLeaf() - // require.Equal(t, hash, deepestLeaf.hash) - // require.Equal(t, hash, bt.leaves.currHighestLeaf.hash) + hash := header.Hash() + err := bt.AddBlock(header, time.Unix(0, fixedArrivalTime)) + require.NoError(t, err) + require.Equal(t, hash, bt.best().hash) } func TestBlockTree_DeepCopy(t *testing.T) { diff --git a/lib/blocktree/leaves.go b/lib/blocktree/leaves.go index 62f8113da2..14874658f7 100644 --- a/lib/blocktree/leaves.go +++ b/lib/blocktree/leaves.go @@ -4,18 +4,16 @@ package blocktree import ( + "bytes" "errors" "math/big" "sync" - "fmt" - "github.com/ChainSafe/gossamer/lib/common" ) // leafMap provides quick lookup for existing leaves type leafMap struct { - currHighestLeaf *node sync.RWMutex smap *sync.Map // map[common.Hash]*node } @@ -79,30 +77,19 @@ func (lm *leafMap) highestLeaf() *node { 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.currHighestLeaf != nil { - if lm.currHighestLeaf.hash == deepest.hash { - return lm.currHighestLeaf - } - - // 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.currHighestLeaf.number) == 1 { - lm.currHighestLeaf = deepest - } else if deepest.number.Cmp(lm.currHighestLeaf.number) == 0 && - deepest.arrivalTime.Before(lm.currHighestLeaf.arrivalTime) { - lm.currHighestLeaf = deepest - } - } else { - lm.currHighestLeaf = deepest - } - - return lm.currHighestLeaf + return deepest } func (lm *leafMap) toMap() map[common.Hash]*node { @@ -146,8 +133,6 @@ func (lm *leafMap) bestBlock() *node { lm.smap.Range(func(_, nn interface{}) bool { n := nn.(*node) count := n.primaryAncestorCount(0) - - fmt.Println(n, count) nodesWithCount, has := counts[count] if !has { counts[count] = []*node{n} From 70fcf27c79ce82ca6c29d2f85183ec632ce630c2 Mon Sep 17 00:00:00 2001 From: noot Date: Fri, 28 Jan 2022 11:43:55 -0500 Subject: [PATCH 05/13] add more test cases --- lib/blocktree/blocktree_test.go | 70 +++++++++++++++++++++++++++++++++ lib/blocktree/leaves.go | 6 +-- 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/lib/blocktree/blocktree_test.go b/lib/blocktree/blocktree_test.go index 3a5c20ed4f..40b7f80147 100644 --- a/lib/blocktree/blocktree_test.go +++ b/lib/blocktree/blocktree_test.go @@ -617,6 +617,7 @@ func equalLeaves(lm *leafMap, lmCopy *leafMap) bool { } 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}, @@ -638,6 +639,75 @@ func TestBlockTree_best(t *testing.T) { 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 14874658f7..88e6ef1c78 100644 --- a/lib/blocktree/leaves.go +++ b/lib/blocktree/leaves.go @@ -66,12 +66,12 @@ func (lm *leafMap) highestLeaf() *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 From 12e1e17764d3debaf3a510f57c74007b684fe786 Mon Sep 17 00:00:00 2001 From: noot Date: Fri, 28 Jan 2022 16:57:52 -0500 Subject: [PATCH 06/13] fix dot/state tests --- dot/state/block_test.go | 38 ++++++++++++++++++++++++++++---------- dot/state/storage_test.go | 1 + dot/state/test_helpers.go | 1 + lib/blocktree/blocktree.go | 11 +++++++---- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/dot/state/block_test.go b/dot/state/block_test.go index 120fc4a847..a4f1b5cd64 100644 --- a/dot/state/block_test.go +++ b/dot/state/block_test.go @@ -40,6 +40,23 @@ func newTestBlockState(t *testing.T, header *types.Header) *BlockState { return bs } +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 TestSetAndGetHeader(t *testing.T) { bs := newTestBlockState(t, nil) @@ -80,7 +97,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 +119,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 +136,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 +261,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 +342,7 @@ func TestGetHashByNumber(t *testing.T) { header := &types.Header{ Number: big.NewInt(1), - Digest: types.NewDigest(), + Digest: createPrimaryBABEDigest(t), ParentHash: testGenesisHeader.Hash(), } @@ -347,7 +365,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 +384,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 +404,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 +428,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 +442,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 +474,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 8e61eefd1d..947438f1a0 100644 --- a/dot/state/storage_test.go +++ b/dot/state/storage_test.go @@ -73,6 +73,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..d6be9a3362 100644 --- a/dot/state/test_helpers.go +++ b/dot/state/test_helpers.go @@ -244,6 +244,7 @@ func generateBlockWithRandomTrie(t *testing.T, serv *Service, ParentHash: *parent, Number: big.NewInt(bNum), StateRoot: trieStateRoot, + Digest: createPrimaryBABEDigest(t), }, Body: *body, } diff --git a/lib/blocktree/blocktree.go b/lib/blocktree/blocktree.go index c3daf0f423..5bb405db50 100644 --- a/lib/blocktree/blocktree.go +++ b/lib/blocktree/blocktree.go @@ -55,7 +55,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() @@ -76,9 +76,12 @@ func (bt *BlockTree) AddBlock(header *types.Header, arrivalTime time.Time) error return errUnexpectedNumber } - isPrimary, err := types.IsPrimary(header) - if err != nil { - return fmt.Errorf("failed to check if block was primary: %w", err) + 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{ From 16bc46f8addc98ccf7e5a2fabc8b2d77cf4277a1 Mon Sep 17 00:00:00 2001 From: noot Date: Mon, 31 Jan 2022 11:01:14 -0500 Subject: [PATCH 07/13] fix sync tests --- dot/state/block_test.go | 17 ----------------- dot/state/test_helpers.go | 18 ++++++++++++++++++ dot/sync/chain_processor_test.go | 2 +- dot/sync/message_test.go | 8 +++++++- dot/types/babe.go | 2 +- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/dot/state/block_test.go b/dot/state/block_test.go index a4f1b5cd64..50e6513f5f 100644 --- a/dot/state/block_test.go +++ b/dot/state/block_test.go @@ -40,23 +40,6 @@ func newTestBlockState(t *testing.T, header *types.Header) *BlockState { return bs } -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 TestSetAndGetHeader(t *testing.T) { bs := newTestBlockState(t, nil) diff --git a/dot/state/test_helpers.go b/dot/state/test_helpers.go index d6be9a3362..0298b27ea0 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 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..952dba3775 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{}, } diff --git a/dot/types/babe.go b/dot/types/babe.go index 90f6e82fd1..6576acc018 100644 --- a/dot/types/babe.go +++ b/dot/types/babe.go @@ -123,7 +123,7 @@ func IsPrimary(header *Header) (bool, error) { preDigest, ok := header.Digest.Types[0].Value().(PreRuntimeDigest) if !ok { - return false, fmt.Errorf("first digest item is not pre-digest") + return false, fmt.Errorf("first digest item is not pre-digest: type=%T", header.Digest.Types[0].Value()) } digest, err := DecodeBabePreDigest(preDigest.Data) From bf26f046abd4f950b0c3af44245f6ba1ee6ea13a Mon Sep 17 00:00:00 2001 From: noot Date: Mon, 31 Jan 2022 11:47:50 -0500 Subject: [PATCH 08/13] fix grandpa unit tests --- dot/state/test_helpers.go | 9 +++++---- lib/grandpa/message_handler_test.go | 4 ++-- lib/grandpa/message_tracker_test.go | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/dot/state/test_helpers.go b/dot/state/test_helpers.go index 0298b27ea0..a5f80f4d92 100644 --- a/dot/state/test_helpers.go +++ b/dot/state/test_helpers.go @@ -208,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{ @@ -224,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) 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) From a9e2c9103a81181b9722fdec48643f0e8c5fc831 Mon Sep 17 00:00:00 2001 From: noot Date: Mon, 31 Jan 2022 11:54:37 -0500 Subject: [PATCH 09/13] fix author rpc integration tests --- dot/rpc/modules/chain_integration_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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, From 787790f33bf0ced1cd8e765bde177b6fed286739 Mon Sep 17 00:00:00 2001 From: noot Date: Mon, 31 Jan 2022 11:57:51 -0500 Subject: [PATCH 10/13] address comments --- lib/blocktree/leaves.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/blocktree/leaves.go b/lib/blocktree/leaves.go index 88e6ef1c78..86dbe366c6 100644 --- a/lib/blocktree/leaves.go +++ b/lib/blocktree/leaves.go @@ -129,10 +129,15 @@ func (lm *leafMap) bestBlock() *node { // 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} @@ -143,14 +148,6 @@ func (lm *leafMap) bestBlock() *node { return true }) - // get highest count - highest := 0 - for count := range counts { - if count > highest { - highest = count - } - } - // there's just one node with the highest amount of primary ancestors, // so let's return it if len(counts[highest]) == 1 { From a79d5df6477e3e8a3df960d011876d08b5aa36d5 Mon Sep 17 00:00:00 2001 From: noot Date: Mon, 31 Jan 2022 12:50:37 -0500 Subject: [PATCH 11/13] fix integration tests --- dot/rpc/modules/childstate_integration_test.go | 7 +++++++ dot/rpc/modules/state_integration_test.go | 7 +++++++ dot/types/babe.go | 4 ++++ 3 files changed, 18 insertions(+) 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/types/babe.go b/dot/types/babe.go index 6576acc018..01b67d8cd8 100644 --- a/dot/types/babe.go +++ b/dot/types/babe.go @@ -117,6 +117,10 @@ func GetSlotFromHeader(header *Header) (uint64, error) { // IsPrimary returns true if the block was authored in a primary slot, false otherwise. func IsPrimary(header *Header) (bool, error) { + if header == nil || header.Digest == nil { + return false, fmt.Errorf("cannot have nil header or digest") + } + if len(header.Digest.Types) == 0 { return false, fmt.Errorf("chain head missing digest") } From 0ef9ea3b4c0b5f52ab6baeaa379bed19504c2034 Mon Sep 17 00:00:00 2001 From: noot Date: Mon, 31 Jan 2022 12:54:42 -0500 Subject: [PATCH 12/13] fix --- dot/types/babe.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dot/types/babe.go b/dot/types/babe.go index 01b67d8cd8..7e47b52a93 100644 --- a/dot/types/babe.go +++ b/dot/types/babe.go @@ -117,8 +117,8 @@ func GetSlotFromHeader(header *Header) (uint64, error) { // IsPrimary returns true if the block was authored in a primary slot, false otherwise. func IsPrimary(header *Header) (bool, error) { - if header == nil || header.Digest == nil { - return false, fmt.Errorf("cannot have nil header or digest") + if header == nil { + return false, fmt.Errorf("cannot have nil header") } if len(header.Digest.Types) == 0 { From 6b841f40369ab8ff70b3797b61c4c190c636efdd Mon Sep 17 00:00:00 2001 From: noot Date: Mon, 31 Jan 2022 14:03:09 -0500 Subject: [PATCH 13/13] update AddBlocksToStateWithFixedBranches --- dot/core/service_integration_test.go | 2 +- dot/rpc/modules/system_integration_test.go | 8 ++++ dot/state/test_helpers.go | 2 +- dot/sync/message_test.go | 2 +- lib/grandpa/grandpa_test.go | 47 +++++++++++----------- lib/grandpa/round_test.go | 3 +- lib/grandpa/vote_message_test.go | 8 ++-- 7 files changed, 39 insertions(+), 33 deletions(-) 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/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/test_helpers.go b/dot/state/test_helpers.go index a5f80f4d92..62c8def253 100644 --- a/dot/state/test_helpers.go +++ b/dot/state/test_helpers.go @@ -152,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() diff --git a/dot/sync/message_test.go b/dot/sync/message_test.go index 952dba3775..c8878b05d0 100644 --- a/dot/sync/message_test.go +++ b/dot/sync/message_test.go @@ -368,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/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/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])