kaspad/blockdag/virtualblock_test.go
Ori Newman 62d14bf2bd [NOD-16] implement initial sync first version (#234)
* [NOD-58] Replace lastBlock with selected tip in version message (#210)

* [NOD-58] Replace lastBlock with selected tip in version message

* [NOD-58] Fix typo in comment

* [NOD-58] Add mutex to SelectedTipHash

* [NOD-58] Remove redundant comment

* [NOD-58] Remove wantStartingHeight from peerStats

* [NOD-58] Remove lock from SelectedTipHash

* Nod 53 change getheaders message to handle new block locator (#213)

* [NOD-53] Change getheaders message to handle the new block locator mechanism

* [NOD-53] Use heap in locateHeaders

* [NOD-53] Create a constructor for each heap direction

* [NOD-57] Check if a node is synced only by timestamps (#214)

* [NOD-60] implement isSyncCandidate (#218)

* [NOD-60] Implement isSyncCandidate

* [NOD-60] Fix typo

* [NOD-65] Fix netsync related tests and remove fields optionality from… (#220)

* [NOD-65] Fix netsync related tests and remove fields optionality from msgversion

* [NOD-65] gofmt rpcserver.go

* [NOD-65] add missing test for verRelayTxFalse

* [NOD-62] Change getblocks message to handle the new block locator mechanism (#219)

* [NOD-62] Change getblocks message to handle the new block locator mechanism

* [NOD-62] Add locateBlockNodes function

* [NOD-68] Adjust orphan parents requesting for a DAG (#222)

* [NOD-68] Adjust orphan parents requesting for a DAG

* [NOD-68] add sendInvsFromRequestedQueue and trigger it when requested blocks slice is empty, or immediatly if we're not in sync mode

* [NOD-68] Prevent duplicates from entering to state.requestQueue and add wrapping locks to addBlocksToRequestQueue

* [NOD-68] Fix Lock -> Unlock in sendInvsFromRequestedQueue

* [NOD-74] Starts syncing again when the current sync peer is done (#225)

* [NOD-74] Starts syncing again when the current sync peer is done

* [NOD-74] Unlock mtx before netsync is restarted

* [NOD-74] Fix name isSyncPeerFree -> isWaitingForBlocks

* [NOD-75] fixing netsync bugs (#227)

* [NOD-74] Starts syncing again when the current sync peer is done

* [NOD-74] Unlock mtx before netsync is restarted

* [NOD-75] Fixing netsync bugs

* [NOD-80] Request block data from block propagation just after you are… (#231)

* [NOD-80] Request block data from block propagation just after you are current

* [NOD-80] Fix adding to both queues in addInvToRequestQueue

* [NOD-81] Start to mine on top of genesis iff all peers selected tip is genesis (#232)

* [NOD-81] Start to mine on top of genesis only if all of your peers' selected tip is genesis

* [NOD-81] Explain forAllPeers/forAllOutboundPeers shouldContinue behaviour in comments

* [NOD-81] Add forAllInboundPeers and add return values for forAllPeers/forAllOutboundPeers/forAllInboundPeers functions

* [NOD-16] Add pushSet to the BlockHeap type

* [NOD-16] Fixed syntax error
2019-03-31 16:47:28 +03:00

161 lines
5.2 KiB
Go

// Copyright (c) 2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockdag
import (
"reflect"
"testing"
)
// TestVirtualBlock ensures that VirtualBlock works as expected.
func TestVirtualBlock(t *testing.T) {
phantomK := uint32(1)
buildNode := buildNodeGenerator(phantomK, false)
// Create a DAG as follows:
// 0 <- 1 <- 2
// \
// <- 3 <- 5
// \ X
// <- 4 <- 6
node0 := buildNode(setFromSlice())
node1 := buildNode(setFromSlice(node0))
node2 := buildNode(setFromSlice(node1))
node3 := buildNode(setFromSlice(node0))
node4 := buildNode(setFromSlice(node0))
node5 := buildNode(setFromSlice(node3, node4))
node6 := buildNode(setFromSlice(node3, node4))
// Given an empty VirtualBlock, each of the following test cases will:
// Set its tips to tipsToSet
// Add to it all the tips in tipsToAdd, one after the other
// Call .Tips() on it and compare the result to expectedTips
// Call .selectedTip() on it and compare the result to expectedSelectedParent
tests := []struct {
name string
tipsToSet []*blockNode
tipsToAdd []*blockNode
expectedTips blockSet
expectedSelectedParent *blockNode
}{
{
name: "empty virtual",
tipsToSet: []*blockNode{},
tipsToAdd: []*blockNode{},
expectedTips: newSet(),
expectedSelectedParent: nil,
},
{
name: "virtual with genesis tip",
tipsToSet: []*blockNode{node0},
tipsToAdd: []*blockNode{},
expectedTips: setFromSlice(node0),
expectedSelectedParent: node0,
},
{
name: "virtual with genesis tip, add child of genesis",
tipsToSet: []*blockNode{node0},
tipsToAdd: []*blockNode{node1},
expectedTips: setFromSlice(node1),
expectedSelectedParent: node1,
},
{
name: "empty virtual, add a full DAG",
tipsToSet: []*blockNode{},
tipsToAdd: []*blockNode{node0, node1, node2, node3, node4, node5, node6},
expectedTips: setFromSlice(node2, node5, node6),
expectedSelectedParent: node5,
},
}
for _, test := range tests {
// Create an empty VirtualBlock
virtual := newVirtualBlock(nil, phantomK)
// Set the tips. This will be the initial state
virtual.SetTips(setFromSlice(test.tipsToSet...))
// Add all blockNodes in tipsToAdd in order
for _, tipToAdd := range test.tipsToAdd {
addNodeAsChildToParents(tipToAdd)
virtual.AddTip(tipToAdd)
}
// Ensure that the virtual block's tips are now equal to expectedTips
resultTips := virtual.tips()
if !reflect.DeepEqual(resultTips, test.expectedTips) {
t.Errorf("unexpected tips in test \"%s\". "+
"Expected: %v, got: %v.", test.name, test.expectedTips, resultTips)
}
// Ensure that the virtual block's selectedParent is now equal to expectedSelectedParent
resultSelectedTip := virtual.selectedParent
if !reflect.DeepEqual(resultSelectedTip, test.expectedSelectedParent) {
t.Errorf("unexpected selected tip in test \"%s\". "+
"Expected: %v, got: %v.", test.name, test.expectedSelectedParent, resultSelectedTip)
}
}
}
func TestSelectedPath(t *testing.T) {
phantomK := uint32(1)
buildNode := buildNodeGenerator(phantomK, false)
// Create an empty VirtualBlock
virtual := newVirtualBlock(nil, phantomK)
tip := buildNode(setFromSlice())
virtual.AddTip(tip)
initialPath := setFromSlice(tip)
for i := 0; i < 5; i++ {
tip = buildNode(setFromSlice(tip))
initialPath.add(tip)
virtual.AddTip(tip)
}
initialTip := tip
firstPath := initialPath.clone()
for i := 0; i < 5; i++ {
tip = buildNode(setFromSlice(tip))
firstPath.add(tip)
virtual.AddTip(tip)
}
// For now we don't have any DAG, just chain, the selected path should include all the blocks on the chain.
if !reflect.DeepEqual(virtual.selectedPathChainSet, firstPath) {
t.Fatalf("TestSelectedPath: selectedPathSet doesn't include the expected values. got %v, want %v", virtual.selectedParent, firstPath)
}
secondPath := initialPath.clone()
tip = initialTip
for i := 0; i < 100; i++ {
tip = buildNode(setFromSlice(tip))
secondPath.add(tip)
virtual.AddTip(tip)
}
// Because we added a chain that is much longer than the previous chain, the selected path should be re-organized.
if !reflect.DeepEqual(virtual.selectedPathChainSet, secondPath) {
t.Fatalf("TestSelectedPath: selectedPathSet didn't handle the re-org as expected. got %v, want %v", virtual.selectedParent, firstPath)
}
tip = initialTip
for i := 0; i < 3; i++ {
tip = buildNode(setFromSlice(tip))
virtual.AddTip(tip)
}
// Because we added a very short chain, the selected path should not be affected.
if !reflect.DeepEqual(virtual.selectedPathChainSet, secondPath) {
t.Fatalf("TestSelectedPath: selectedPathSet did an unexpected re-org. got %v, want %v", virtual.selectedParent, firstPath)
}
// We call updateSelectedPathSet manually without updating the tips, to check if it panics
virtual2 := newVirtualBlock(nil, phantomK)
defer func() {
if r := recover(); r == nil {
t.Fatalf("updateSelectedPathSet didn't panic")
}
}()
virtual2.updateSelectedPathSet(buildNode(setFromSlice()))
}