Skip to content

Commit

Permalink
Add tests and fix bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
qdm12 committed Feb 27, 2023
1 parent 1501d92 commit 5398c36
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 13 deletions.
3 changes: 3 additions & 0 deletions lib/blocktree/blocktree.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@ func (bt *BlockTree) Prune(finalised Hash) (pruned []Hash) {
// accessible through the storage as WASM blob.
previousFinalisedBlock := bt.root
newCanonicalChainBlocksCount := n.number - previousFinalisedBlock.number
if previousFinalisedBlock.number == 0 { // include the genesis block
newCanonicalChainBlocksCount++
}
canonicalChainBlock := n
newCanonicalChainBlockHashes := make([]Hash, newCanonicalChainBlocksCount)
for i := int(newCanonicalChainBlocksCount) - 1; i >= 0; i-- {
Expand Down
36 changes: 25 additions & 11 deletions lib/blocktree/blocktree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,10 @@ func Test_BlockTree_Prune(t *testing.T) {
{1}: rootRuntime,
{2}: rootRuntime,
},
finalisedRuntime: rootRuntime,
currentBlockHashes: []Hash{{1}, {2}},
}
assert.Equal(t, blockTree.runtimes, expectedHashToRuntime)
assert.Equal(t, expectedHashToRuntime, blockTree.runtimes)
})

t.Run("prune_canonical_runtimes", func(t *testing.T) {
Expand Down Expand Up @@ -486,10 +488,12 @@ func Test_BlockTree_Prune(t *testing.T) {

expectedHashToRuntime := &hashToRuntime{
mapping: map[common.Hash]Runtime{
{2}: rootRuntime,
{2}: leafRuntime,
},
finalisedRuntime: leafRuntime,
currentBlockHashes: []Hash{{2}},
}
assert.Equal(t, blockTree.runtimes, expectedHashToRuntime)
assert.Equal(t, expectedHashToRuntime, blockTree.runtimes)
})

t.Run("prune_fork", func(t *testing.T) {
Expand Down Expand Up @@ -539,8 +543,10 @@ func Test_BlockTree_Prune(t *testing.T) {
{1}: rootRuntime,
{2}: rootRuntime,
},
finalisedRuntime: rootRuntime,
currentBlockHashes: []Hash{{1}, {2}},
}
assert.Equal(t, blockTree.runtimes, expectedHashToRuntime)
assert.Equal(t, expectedHashToRuntime, blockTree.runtimes)
})

t.Run("complex_example", func(t *testing.T) {
Expand All @@ -552,13 +558,19 @@ func Test_BlockTree_Prune(t *testing.T) {
number: 100,
}
rootRuntime := NewMockRuntime(ctrl)

blockTree := &BlockTree{
root: rootNode,
leaves: newEmptyLeafMap(),
runtimes: newHashToRuntime(),
root: rootNode,
leaves: newEmptyLeafMap(),
runtimes: &hashToRuntime{
mapping: map[common.Hash]Runtime{
{1}: rootRuntime,
},
finalisedRuntime: rootRuntime,
currentBlockHashes: []Hash{{1}},
},
}
rootRuntime.EXPECT().Stop()
blockTree.runtimes.set(common.Hash{1}, rootRuntime)

// {1} -> {2}
parent := rootNode
Expand All @@ -569,8 +581,8 @@ func Test_BlockTree_Prune(t *testing.T) {
}
parent.addChild(newNode)
blockTree.leaves.replace(parent, newNode)
rootRuntime.EXPECT().Stop()
blockTree.runtimes.set(common.Hash{2}, rootRuntime)
rootRuntime.EXPECT().Stop()

// {1} -> {2} -> {3}
parent = newNode
Expand Down Expand Up @@ -605,8 +617,8 @@ func Test_BlockTree_Prune(t *testing.T) {
}
parent.addChild(newNode)
blockTree.leaves.replace(parent, newNode)
rootRuntime.EXPECT().Stop()
blockTree.runtimes.set(common.Hash{5}, rootRuntime)
rootRuntime.EXPECT().Stop()

// {1} -> {2} -> {3} -> {4}
// -> {5} -> {6}
Expand Down Expand Up @@ -643,8 +655,10 @@ func Test_BlockTree_Prune(t *testing.T) {
{3}: lastCanonicalRuntime,
{4}: lastCanonicalRuntime,
},
finalisedRuntime: lastCanonicalRuntime,
currentBlockHashes: []Hash{{3}, {4}},
}
assert.Equal(t, blockTree.runtimes, expectedHashToRuntime)
assert.Equal(t, expectedHashToRuntime, blockTree.runtimes)
})
}

Expand Down
4 changes: 2 additions & 2 deletions lib/blocktree/hashtoruntime.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func (h *hashToRuntime) delete(hash Hash) {

// onFinalisation handles pruning and recording on block finalisation.
// newCanonicalBlockHashes is the block hashes of the blocks newly finalised.
// The last element is the finalised block block hash.
// The last element is the finalised block hash.
func (h *hashToRuntime) onFinalisation(newCanonicalBlockHashes, prunedForkBlockHashes []Hash) {
h.mutex.Lock()
defer h.mutex.Unlock()
Expand Down Expand Up @@ -95,7 +95,7 @@ func (h *hashToRuntime) onFinalisation(newCanonicalBlockHashes, prunedForkBlockH
for i, blockHash := range newCanonicalBlockHashes {
runtime, ok := h.mapping[blockHash]
if !ok {
panic(fmt.Sprintf("runtime not found for canonical chain block block hash %s", blockHash))
panic(fmt.Sprintf("runtime not found for canonical chain block hash %s", blockHash))
}

if runtime == newFinalisedRuntime {
Expand Down
142 changes: 142 additions & 0 deletions lib/blocktree/hashtoruntime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/ChainSafe/gossamer/lib/common"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -158,6 +159,147 @@ func Test_hashToRuntime_delete(t *testing.T) {
}
}

func Test_hashToRuntime_onFinalisation(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
makeParameters func(ctrl *gomock.Controller) (initial, expected *hashToRuntime)
newCanonicalBlockHashes []Hash
prunedForkBlockHashes []Hash
panicString string
}{
"new_finalised_runtime_not_found": {
makeParameters: func(ctrl *gomock.Controller) (initial, expected *hashToRuntime) {
return &hashToRuntime{}, nil
},
newCanonicalBlockHashes: []Hash{{1}},
panicString: "runtime not found for finalised block hash " +
"0x0100000000000000000000000000000000000000000000000000000000000000",
},
"pruned_fork_runtime_not_found": {
makeParameters: func(ctrl *gomock.Controller) (initial, expected *hashToRuntime) {
finalisedRuntime := NewMockRuntime(ctrl)
return &hashToRuntime{
mapping: map[Hash]Runtime{
{1}: finalisedRuntime,
},
}, nil
},
newCanonicalBlockHashes: []Hash{{1}},
prunedForkBlockHashes: []Hash{{2}},
panicString: "runtime not found for pruned forked block hash " +
"0x0200000000000000000000000000000000000000000000000000000000000000",
},
"prune_fork_runtimes_only": {
makeParameters: func(ctrl *gomock.Controller) (initial, expected *hashToRuntime) {
finalisedRuntime := NewMockRuntime(ctrl)
prunedForkRuntime := NewMockRuntime(ctrl)
prunedForkRuntime.EXPECT().Stop().Times(2)
initial = &hashToRuntime{
finalisedRuntime: finalisedRuntime,
currentBlockHashes: []Hash{{0}},
mapping: map[Hash]Runtime{
{1}: finalisedRuntime,
{2}: finalisedRuntime,
{3}: prunedForkRuntime,
{4}: prunedForkRuntime,
},
}
expected = &hashToRuntime{
finalisedRuntime: finalisedRuntime,
currentBlockHashes: []Hash{{0}, {1}},
mapping: map[Hash]Runtime{
{1}: finalisedRuntime,
},
}
return initial, expected
},
newCanonicalBlockHashes: []Hash{{1}},
prunedForkBlockHashes: []Hash{{2}, {3}, {4}},
},
"new_canonical_block_hash_not_found": {
makeParameters: func(ctrl *gomock.Controller) (initial, expected *hashToRuntime) {
newFinalisedRuntime := NewMockRuntime(ctrl)
initial = &hashToRuntime{
mapping: map[Hash]Runtime{
// missing {1}
{2}: newFinalisedRuntime,
},
}
return initial, nil
},
newCanonicalBlockHashes: []Hash{{1}, {2}},
panicString: "runtime not found for canonical chain block hash " +
"0x0100000000000000000000000000000000000000000000000000000000000000",
},
"prune_fork_and_canonical_runtimes": {
makeParameters: func(ctrl *gomock.Controller) (initial, expected *hashToRuntime) {
finalisedRuntime := NewMockRuntime(ctrl)
unfinalisedRuntime := NewMockRuntime(ctrl)
newFinalisedRuntime := NewMockRuntime(ctrl)
prunedForkRuntime := NewMockRuntime(ctrl)

finalisedRuntime.EXPECT().Stop().Times(1 + 2)
unfinalisedRuntime.EXPECT().Stop().Times(2)
prunedForkRuntime.EXPECT().Stop().Times(2)

initial = &hashToRuntime{
finalisedRuntime: finalisedRuntime,
currentBlockHashes: []Hash{{0}, {1}},
mapping: map[Hash]Runtime{
// Previously finalised chain
{0}: finalisedRuntime,
{1}: finalisedRuntime,
// Newly finalised chain
{2}: finalisedRuntime,
{3}: unfinalisedRuntime,
{4}: unfinalisedRuntime,
{5}: newFinalisedRuntime,
{6}: newFinalisedRuntime,
// Runtimes from forks
{100}: prunedForkRuntime,
{101}: prunedForkRuntime,
{102}: finalisedRuntime,
{103}: newFinalisedRuntime,
},
}
expected = &hashToRuntime{
finalisedRuntime: newFinalisedRuntime,
currentBlockHashes: []Hash{{5}, {6}},
mapping: map[Hash]Runtime{
{5}: newFinalisedRuntime,
{6}: newFinalisedRuntime,
},
}
return initial, expected
},
newCanonicalBlockHashes: []Hash{{2}, {3}, {4}, {5}, {6}},
prunedForkBlockHashes: []Hash{{100}, {101}, {102}, {103}},
},
}

for name, testCase := range testCases {
testCase := testCase
t.Run(name, func(t *testing.T) {
t.Parallel()
ctrl := gomock.NewController(t)

htr, expectedHtr := testCase.makeParameters(ctrl)

if testCase.panicString != "" {
assert.PanicsWithValue(t, testCase.panicString, func() {
htr.onFinalisation(testCase.newCanonicalBlockHashes, testCase.prunedForkBlockHashes)
})
return
}

htr.onFinalisation(testCase.newCanonicalBlockHashes, testCase.prunedForkBlockHashes)

assert.Equal(t, expectedHtr, htr)
})
}
}

func Test_hashToRuntime_threadSafety(t *testing.T) {
// This test consists in checking for concurrent access
// using the -race detector.
Expand Down

0 comments on commit 5398c36

Please sign in to comment.