aboutsummaryrefslogtreecommitdiffstats
path: root/eth/block_pool_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'eth/block_pool_test.go')
-rw-r--r--eth/block_pool_test.go983
1 files changed, 0 insertions, 983 deletions
diff --git a/eth/block_pool_test.go b/eth/block_pool_test.go
deleted file mode 100644
index 331dbe504..000000000
--- a/eth/block_pool_test.go
+++ /dev/null
@@ -1,983 +0,0 @@
-package eth
-
-import (
- "fmt"
- "log"
- "math/big"
- "os"
- "sync"
- "testing"
- "time"
-
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/ethutil"
- ethlogger "github.com/ethereum/go-ethereum/logger"
- "github.com/ethereum/go-ethereum/pow"
-)
-
-const waitTimeout = 60 // seconds
-
-var logsys = ethlogger.NewStdLogSystem(os.Stdout, log.LstdFlags, ethlogger.LogLevel(ethlogger.DebugDetailLevel))
-
-var ini = false
-
-func logInit() {
- if !ini {
- ethlogger.AddLogSystem(logsys)
- ini = true
- }
-}
-
-// test helpers
-func arrayEq(a, b []int) bool {
- if len(a) != len(b) {
- return false
- }
- for i := range a {
- if a[i] != b[i] {
- return false
- }
- }
- return true
-}
-
-type intToHash map[int][]byte
-
-type hashToInt map[string]int
-
-// hashPool is a test helper, that allows random hashes to be referred to by integers
-type testHashPool struct {
- intToHash
- hashToInt
- lock sync.Mutex
-}
-
-func newHash(i int) []byte {
- return crypto.Sha3([]byte(string(i)))
-}
-
-func (self *testHashPool) indexesToHashes(indexes []int) (hashes [][]byte) {
- self.lock.Lock()
- defer self.lock.Unlock()
- for _, i := range indexes {
- hash, found := self.intToHash[i]
- if !found {
- hash = newHash(i)
- self.intToHash[i] = hash
- self.hashToInt[string(hash)] = i
- }
- hashes = append(hashes, hash)
- }
- return
-}
-
-func (self *testHashPool) hashesToIndexes(hashes [][]byte) (indexes []int) {
- self.lock.Lock()
- defer self.lock.Unlock()
- for _, hash := range hashes {
- i, found := self.hashToInt[string(hash)]
- if !found {
- i = -1
- }
- indexes = append(indexes, i)
- }
- return
-}
-
-// test blockChain is an integer trie
-type blockChain map[int][]int
-
-// blockPoolTester provides the interface between tests and a blockPool
-//
-// refBlockChain is used to guide which blocks will be accepted as valid
-// blockChain gives the current state of the blockchain and
-// accumulates inserts so that we can check the resulting chain
-type blockPoolTester struct {
- hashPool *testHashPool
- lock sync.RWMutex
- refBlockChain blockChain
- blockChain blockChain
- blockPool *BlockPool
- t *testing.T
-}
-
-func newTestBlockPool(t *testing.T) (hashPool *testHashPool, blockPool *BlockPool, b *blockPoolTester) {
- hashPool = &testHashPool{intToHash: make(intToHash), hashToInt: make(hashToInt)}
- b = &blockPoolTester{
- t: t,
- hashPool: hashPool,
- blockChain: make(blockChain),
- refBlockChain: make(blockChain),
- }
- b.blockPool = NewBlockPool(b.hasBlock, b.insertChain, b.verifyPoW)
- blockPool = b.blockPool
- return
-}
-
-func (self *blockPoolTester) Errorf(format string, params ...interface{}) {
- fmt.Printf(format+"\n", params...)
- self.t.Errorf(format, params...)
-}
-
-// blockPoolTester implements the 3 callbacks needed by the blockPool:
-// hasBlock, insetChain, verifyPoW
-func (self *blockPoolTester) hasBlock(block []byte) (ok bool) {
- self.lock.RLock()
- defer self.lock.RUnlock()
- indexes := self.hashPool.hashesToIndexes([][]byte{block})
- i := indexes[0]
- _, ok = self.blockChain[i]
- fmt.Printf("has block %v (%x...): %v\n", i, block[0:4], ok)
- return
-}
-
-func (self *blockPoolTester) insertChain(blocks types.Blocks) error {
- self.lock.RLock()
- defer self.lock.RUnlock()
- var parent, child int
- var children, refChildren []int
- var ok bool
- for _, block := range blocks {
- child = self.hashPool.hashesToIndexes([][]byte{block.Hash()})[0]
- _, ok = self.blockChain[child]
- if ok {
- fmt.Printf("block %v already in blockchain\n", child)
- continue // already in chain
- }
- parent = self.hashPool.hashesToIndexes([][]byte{block.ParentHeaderHash})[0]
- children, ok = self.blockChain[parent]
- if !ok {
- return fmt.Errorf("parent %v not in blockchain ", parent)
- }
- ok = false
- var found bool
- refChildren, found = self.refBlockChain[parent]
- if found {
- for _, c := range refChildren {
- if c == child {
- ok = true
- }
- }
- if !ok {
- return fmt.Errorf("invalid block %v", child)
- }
- } else {
- ok = true
- }
- if ok {
- // accept any blocks if parent not in refBlockChain
- fmt.Errorf("blockchain insert %v -> %v\n", parent, child)
- self.blockChain[parent] = append(children, child)
- self.blockChain[child] = nil
- }
- }
- return nil
-}
-
-func (self *blockPoolTester) verifyPoW(pblock pow.Block) bool {
- return true
-}
-
-// test helper that compares the resulting blockChain to the desired blockChain
-func (self *blockPoolTester) checkBlockChain(blockChain map[int][]int) {
- for k, v := range self.blockChain {
- fmt.Printf("got: %v -> %v\n", k, v)
- }
- for k, v := range blockChain {
- fmt.Printf("expected: %v -> %v\n", k, v)
- }
- if len(blockChain) != len(self.blockChain) {
- self.Errorf("blockchain incorrect (zlength differ)")
- }
- for k, v := range blockChain {
- vv, ok := self.blockChain[k]
- if !ok || !arrayEq(v, vv) {
- self.Errorf("blockchain incorrect on %v -> %v (!= %v)", k, vv, v)
- }
- }
-}
-
-//
-
-// peerTester provides the peer callbacks for the blockPool
-// it registers actual callbacks so that result can be compared to desired behaviour
-// provides helper functions to mock the protocol calls to the blockPool
-type peerTester struct {
- blockHashesRequests []int
- blocksRequests [][]int
- blocksRequestsMap map[int]bool
- peerErrors []int
- blockPool *BlockPool
- hashPool *testHashPool
- lock sync.RWMutex
- id string
- td int
- currentBlock int
- t *testing.T
-}
-
-// peerTester constructor takes hashPool and blockPool from the blockPoolTester
-func (self *blockPoolTester) newPeer(id string, td int, cb int) *peerTester {
- return &peerTester{
- id: id,
- td: td,
- currentBlock: cb,
- hashPool: self.hashPool,
- blockPool: self.blockPool,
- t: self.t,
- blocksRequestsMap: make(map[int]bool),
- }
-}
-
-func (self *peerTester) Errorf(format string, params ...interface{}) {
- fmt.Printf(format+"\n", params...)
- self.t.Errorf(format, params...)
-}
-
-// helper to compare actual and expected block requests
-func (self *peerTester) checkBlocksRequests(blocksRequests ...[]int) {
- if len(blocksRequests) > len(self.blocksRequests) {
- self.Errorf("blocks requests incorrect (length differ)\ngot %v\nexpected %v", self.blocksRequests, blocksRequests)
- } else {
- for i, rr := range blocksRequests {
- r := self.blocksRequests[i]
- if !arrayEq(r, rr) {
- self.Errorf("blocks requests incorrect\ngot %v\nexpected %v", self.blocksRequests, blocksRequests)
- }
- }
- }
-}
-
-// helper to compare actual and expected block hash requests
-func (self *peerTester) checkBlockHashesRequests(blocksHashesRequests ...int) {
- rr := blocksHashesRequests
- self.lock.RLock()
- r := self.blockHashesRequests
- self.lock.RUnlock()
- if len(r) != len(rr) {
- self.Errorf("block hashes requests incorrect (length differ)\ngot %v\nexpected %v", r, rr)
- } else {
- if !arrayEq(r, rr) {
- self.Errorf("block hashes requests incorrect\ngot %v\nexpected %v", r, rr)
- }
- }
-}
-
-// waiter function used by peer.AddBlocks
-// blocking until requests appear
-// since block requests are sent to any random peers
-// block request map is shared between peers
-// times out after a period
-func (self *peerTester) waitBlocksRequests(blocksRequest ...int) {
- timeout := time.After(waitTimeout * time.Second)
- rr := blocksRequest
- for {
- self.lock.RLock()
- r := self.blocksRequestsMap
- fmt.Printf("[%s] blocks request check %v (%v)\n", self.id, rr, r)
- i := 0
- for i = 0; i < len(rr); i++ {
- _, ok := r[rr[i]]
- if !ok {
- break
- }
- }
- self.lock.RUnlock()
-
- if i == len(rr) {
- return
- }
- time.Sleep(100 * time.Millisecond)
- select {
- case <-timeout:
- default:
- }
- }
-}
-
-// waiter function used by peer.AddBlockHashes
-// blocking until requests appear
-// times out after a period
-func (self *peerTester) waitBlockHashesRequests(blocksHashesRequest int) {
- timeout := time.After(waitTimeout * time.Second)
- rr := blocksHashesRequest
- for i := 0; ; {
- self.lock.RLock()
- r := self.blockHashesRequests
- self.lock.RUnlock()
- fmt.Printf("[%s] block hash request check %v (%v)\n", self.id, rr, r)
- for ; i < len(r); i++ {
- if rr == r[i] {
- return
- }
- }
- time.Sleep(100 * time.Millisecond)
- select {
- case <-timeout:
- default:
- }
- }
-}
-
-// mocks a simple blockchain 0 (genesis) ... n (head)
-func (self *blockPoolTester) initRefBlockChain(n int) {
- for i := 0; i < n; i++ {
- self.refBlockChain[i] = []int{i + 1}
- }
-}
-
-// peerTester functions that mimic protocol calls to the blockpool
-// registers the peer with the blockPool
-func (self *peerTester) AddPeer() bool {
- hash := self.hashPool.indexesToHashes([]int{self.currentBlock})[0]
- return self.blockPool.AddPeer(big.NewInt(int64(self.td)), hash, self.id, self.requestBlockHashes, self.requestBlocks, self.peerError)
-}
-
-// peer sends blockhashes if and when gets a request
-func (self *peerTester) AddBlockHashes(indexes ...int) {
- fmt.Printf("ready to add block hashes %v\n", indexes)
-
- self.waitBlockHashesRequests(indexes[0])
- fmt.Printf("adding block hashes %v\n", indexes)
- hashes := self.hashPool.indexesToHashes(indexes)
- i := 1
- next := func() (hash []byte, ok bool) {
- if i < len(hashes) {
- hash = hashes[i]
- ok = true
- i++
- }
- return
- }
- self.blockPool.AddBlockHashes(next, self.id)
-}
-
-// peer sends blocks if and when there is a request
-// (in the shared request store, not necessarily to a person)
-func (self *peerTester) AddBlocks(indexes ...int) {
- hashes := self.hashPool.indexesToHashes(indexes)
- fmt.Printf("ready to add blocks %v\n", indexes[1:])
- self.waitBlocksRequests(indexes[1:]...)
- fmt.Printf("adding blocks %v \n", indexes[1:])
- for i := 1; i < len(hashes); i++ {
- fmt.Printf("adding block %v %x\n", indexes[i], hashes[i][:4])
- self.blockPool.AddBlock(&types.Block{HeaderHash: ethutil.Bytes(hashes[i]), ParentHeaderHash: ethutil.Bytes(hashes[i-1])}, self.id)
- }
-}
-
-// peer callbacks
-// -1 is special: not found (a hash never seen)
-// records block hashes requests by the blockPool
-func (self *peerTester) requestBlockHashes(hash []byte) error {
- indexes := self.hashPool.hashesToIndexes([][]byte{hash})
- fmt.Printf("[%s] blocks hash request %v %x\n", self.id, indexes[0], hash[:4])
- self.lock.Lock()
- defer self.lock.Unlock()
- self.blockHashesRequests = append(self.blockHashesRequests, indexes[0])
- return nil
-}
-
-// records block requests by the blockPool
-func (self *peerTester) requestBlocks(hashes [][]byte) error {
- indexes := self.hashPool.hashesToIndexes(hashes)
- fmt.Printf("blocks request %v %x...\n", indexes, hashes[0][:4])
- self.lock.Lock()
- defer self.lock.Unlock()
- self.blocksRequests = append(self.blocksRequests, indexes)
- for _, i := range indexes {
- self.blocksRequestsMap[i] = true
- }
- return nil
-}
-
-// records the error codes of all the peerErrors found the blockPool
-func (self *peerTester) peerError(code int, format string, params ...interface{}) {
- self.peerErrors = append(self.peerErrors, code)
-}
-
-// the actual tests
-func TestAddPeer(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- peer0 := blockPoolTester.newPeer("peer0", 1, 0)
- peer1 := blockPoolTester.newPeer("peer1", 2, 1)
- peer2 := blockPoolTester.newPeer("peer2", 3, 2)
- var peer *peerInfo
-
- blockPool.Start()
-
- // pool
- best := peer0.AddPeer()
- if !best {
- t.Errorf("peer0 (TD=1) not accepted as best")
- }
- if blockPool.peer.id != "peer0" {
- t.Errorf("peer0 (TD=1) not set as best")
- }
- // peer0.checkBlockHashesRequests(0)
-
- best = peer2.AddPeer()
- if !best {
- t.Errorf("peer2 (TD=3) not accepted as best")
- }
- if blockPool.peer.id != "peer2" {
- t.Errorf("peer2 (TD=3) not set as best")
- }
- peer2.waitBlocksRequests(2)
-
- best = peer1.AddPeer()
- if best {
- t.Errorf("peer1 (TD=2) accepted as best")
- }
- if blockPool.peer.id != "peer2" {
- t.Errorf("peer2 (TD=3) not set any more as best")
- }
- if blockPool.peer.td.Cmp(big.NewInt(int64(3))) != 0 {
- t.Errorf("peer1 TD not set")
- }
-
- peer2.td = 4
- peer2.currentBlock = 3
- best = peer2.AddPeer()
- if !best {
- t.Errorf("peer2 (TD=4) not accepted as best")
- }
- if blockPool.peer.id != "peer2" {
- t.Errorf("peer2 (TD=4) not set as best")
- }
- if blockPool.peer.td.Cmp(big.NewInt(int64(4))) != 0 {
- t.Errorf("peer2 TD not updated")
- }
- peer2.waitBlocksRequests(3)
-
- peer1.td = 3
- peer1.currentBlock = 2
- best = peer1.AddPeer()
- if best {
- t.Errorf("peer1 (TD=3) should not be set as best")
- }
- if blockPool.peer.id == "peer1" {
- t.Errorf("peer1 (TD=3) should not be set as best")
- }
- peer, best = blockPool.getPeer("peer1")
- if peer.td.Cmp(big.NewInt(int64(3))) != 0 {
- t.Errorf("peer1 TD should be updated")
- }
-
- blockPool.RemovePeer("peer2")
- peer, best = blockPool.getPeer("peer2")
- if peer != nil {
- t.Errorf("peer2 not removed")
- }
-
- if blockPool.peer.id != "peer1" {
- t.Errorf("existing peer1 (TD=3) should be set as best peer")
- }
- peer1.waitBlocksRequests(2)
-
- blockPool.RemovePeer("peer1")
- peer, best = blockPool.getPeer("peer1")
- if peer != nil {
- t.Errorf("peer1 not removed")
- }
-
- if blockPool.peer.id != "peer0" {
- t.Errorf("existing peer0 (TD=1) should be set as best peer")
- }
- peer0.waitBlocksRequests(0)
-
- blockPool.RemovePeer("peer0")
- peer, best = blockPool.getPeer("peer0")
- if peer != nil {
- t.Errorf("peer1 not removed")
- }
-
- // adding back earlier peer ok
- peer0.currentBlock = 3
- best = peer0.AddPeer()
- if !best {
- t.Errorf("peer0 (TD=1) should be set as best")
- }
-
- if blockPool.peer.id != "peer0" {
- t.Errorf("peer0 (TD=1) should be set as best")
- }
- peer0.waitBlocksRequests(3)
-
- blockPool.Stop()
-
-}
-
-func TestPeerWithKnownBlock(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.refBlockChain[0] = nil
- blockPoolTester.blockChain[0] = nil
- blockPool.Start()
-
- peer0 := blockPoolTester.newPeer("0", 1, 0)
- peer0.AddPeer()
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- // no request on known block
- peer0.checkBlockHashesRequests()
-}
-
-func TestPeerWithKnownParentBlock(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.initRefBlockChain(1)
- blockPoolTester.blockChain[0] = nil
- blockPool.Start()
-
- peer0 := blockPoolTester.newPeer("0", 1, 1)
- peer0.AddPeer()
- peer0.AddBlocks(0, 1)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- peer0.checkBlocksRequests([]int{1})
- peer0.checkBlockHashesRequests()
- blockPoolTester.refBlockChain[1] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-}
-
-func TestSimpleChain(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(2)
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 2)
- peer1.AddPeer()
- peer1.AddBlocks(1, 2)
- go peer1.AddBlockHashes(2, 1, 0)
- peer1.AddBlocks(0, 1)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[2] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-}
-
-func TestChainConnectingWithParentHash(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(3)
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 3)
- peer1.AddPeer()
- go peer1.AddBlocks(2, 3)
- go peer1.AddBlockHashes(3, 2, 1)
- peer1.AddBlocks(0, 1, 2)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[3] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-}
-
-func TestInvalidBlock(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(2)
- blockPoolTester.refBlockChain[2] = []int{}
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 3)
- peer1.AddPeer()
- go peer1.AddBlocks(2, 3)
- go peer1.AddBlockHashes(3, 2, 1, 0)
- peer1.AddBlocks(0, 1, 2)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[2] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
- if len(peer1.peerErrors) == 1 {
- if peer1.peerErrors[0] != ErrInvalidBlock {
- t.Errorf("wrong error, got %v, expected %v", peer1.peerErrors[0], ErrInvalidBlock)
- }
- } else {
- t.Errorf("expected invalid block error, got nothing %v", peer1.peerErrors)
- }
-}
-
-func TestVerifyPoW(t *testing.T) {
- t.Skip("***FIX*** This test is broken")
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(3)
- first := false
- blockPoolTester.blockPool.verifyPoW = func(b pow.Block) bool {
- bb, _ := b.(*types.Block)
- indexes := blockPoolTester.hashPool.hashesToIndexes([][]byte{bb.Hash()})
- if indexes[0] == 2 && !first {
- first = true
- return false
- } else {
- return true
- }
-
- }
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 3)
- peer1.AddPeer()
- go peer1.AddBlocks(2, 3)
- go peer1.AddBlockHashes(3, 2, 1, 0)
- peer1.AddBlocks(0, 1, 2)
-
- // blockPool.Wait(waitTimeout * time.Second)
- time.Sleep(1 * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[1] = []int{}
- delete(blockPoolTester.refBlockChain, 2)
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
- if len(peer1.peerErrors) == 1 {
- if peer1.peerErrors[0] != ErrInvalidPoW {
- t.Errorf("wrong error, got %v, expected %v", peer1.peerErrors[0], ErrInvalidPoW)
- }
- } else {
- t.Errorf("expected invalid pow error, got nothing")
- }
-}
-
-func TestMultiSectionChain(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(5)
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 5)
-
- peer1.AddPeer()
- go peer1.AddBlocks(4, 5)
- go peer1.AddBlockHashes(5, 4, 3)
- go peer1.AddBlocks(2, 3, 4)
- go peer1.AddBlockHashes(3, 2, 1, 0)
- peer1.AddBlocks(0, 1, 2)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[5] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-}
-
-func TestNewBlocksOnPartialChain(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(7)
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 5)
-
- peer1.AddPeer()
- go peer1.AddBlocks(4, 5) // partially complete section
- go peer1.AddBlockHashes(5, 4, 3)
- peer1.AddBlocks(3, 4) // partially complete section
- // peer1 found new blocks
- peer1.td = 2
- peer1.currentBlock = 7
- peer1.AddPeer()
- go peer1.AddBlocks(6, 7)
- go peer1.AddBlockHashes(7, 6, 5)
- go peer1.AddBlocks(2, 3)
- go peer1.AddBlocks(5, 6)
- go peer1.AddBlockHashes(3, 2, 1, 0) // tests that hash request from known chain root is remembered
- peer1.AddBlocks(0, 1, 2)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[7] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-}
-
-func TestPeerSwitchUp(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(7)
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 6)
- peer2 := blockPoolTester.newPeer("peer2", 2, 7)
- peer2.blocksRequestsMap = peer1.blocksRequestsMap
-
- peer1.AddPeer()
- go peer1.AddBlocks(5, 6)
- go peer1.AddBlockHashes(6, 5, 4, 3) //
- peer1.AddBlocks(2, 3) // section partially complete, block 3 will be preserved after peer demoted
- peer2.AddPeer() // peer2 is promoted as best peer, peer1 is demoted
- go peer2.AddBlocks(6, 7)
- go peer2.AddBlockHashes(7, 6) //
- go peer2.AddBlocks(4, 5) // tests that block request for earlier section is remembered
- go peer1.AddBlocks(3, 4) // tests that connecting section by demoted peer is remembered and blocks are accepted from demoted peer
- go peer2.AddBlockHashes(3, 2, 1, 0) // tests that known chain section is activated, hash requests from 3 is remembered
- peer2.AddBlocks(0, 1, 2) // final blocks linking to blockchain sent
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[7] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-}
-
-func TestPeerSwitchDown(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(6)
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 4)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
- peer2.blocksRequestsMap = peer1.blocksRequestsMap
-
- peer2.AddPeer()
- peer2.AddBlocks(5, 6) // partially complete, section will be preserved
- go peer2.AddBlockHashes(6, 5, 4) //
- peer2.AddBlocks(4, 5) //
- blockPool.RemovePeer("peer2") // peer2 disconnects
- peer1.AddPeer() // inferior peer1 is promoted as best peer
- go peer1.AddBlockHashes(4, 3, 2, 1, 0) //
- go peer1.AddBlocks(3, 4) // tests that section set by demoted peer is remembered and blocks are accepted , this connects the chain sections together
- peer1.AddBlocks(0, 1, 2, 3)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[6] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-}
-
-func TestPeerCompleteSectionSwitchDown(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(6)
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 4)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
- peer2.blocksRequestsMap = peer1.blocksRequestsMap
-
- peer2.AddPeer()
- peer2.AddBlocks(5, 6) // partially complete, section will be preserved
- go peer2.AddBlockHashes(6, 5, 4) //
- peer2.AddBlocks(3, 4, 5) // complete section
- blockPool.RemovePeer("peer2") // peer2 disconnects
- peer1.AddPeer() // inferior peer1 is promoted as best peer
- peer1.AddBlockHashes(4, 3, 2, 1, 0) // tests that hash request are directly connecting if the head block exists
- peer1.AddBlocks(0, 1, 2, 3)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[6] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-}
-
-func TestPeerSwitchBack(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(8)
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 2, 11)
- peer2 := blockPoolTester.newPeer("peer2", 1, 8)
- peer2.blocksRequestsMap = peer1.blocksRequestsMap
-
- peer2.AddPeer()
- go peer2.AddBlocks(7, 8)
- go peer2.AddBlockHashes(8, 7, 6)
- go peer2.AddBlockHashes(6, 5, 4)
- peer2.AddBlocks(4, 5) // section partially complete
- peer1.AddPeer() // peer1 is promoted as best peer
- go peer1.AddBlocks(10, 11) //
- peer1.AddBlockHashes(11, 10) // only gives useless results
- blockPool.RemovePeer("peer1") // peer1 disconnects
- go peer2.AddBlockHashes(4, 3, 2, 1, 0) // tests that asking for hashes from 4 is remembered
- go peer2.AddBlocks(3, 4, 5, 6, 7, 8) // tests that section 4, 5, 6 and 7, 8 are remembered for missing blocks
- peer2.AddBlocks(0, 1, 2, 3)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[8] = []int{}
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-}
-
-func TestForkSimple(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(9)
- blockPoolTester.refBlockChain[3] = []int{4, 7}
- delete(blockPoolTester.refBlockChain, 6)
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 9)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
- peer2.blocksRequestsMap = peer1.blocksRequestsMap
-
- peer1.AddPeer()
- go peer1.AddBlocks(8, 9)
- go peer1.AddBlockHashes(9, 8, 7, 3, 2)
- peer1.AddBlocks(1, 2, 3, 7, 8)
- peer2.AddPeer() // peer2 is promoted as best peer
- go peer2.AddBlocks(5, 6) //
- go peer2.AddBlockHashes(6, 5, 4, 3, 2) // fork on 3 -> 4 (earlier child: 7)
- go peer2.AddBlocks(1, 2, 3, 4, 5)
- go peer2.AddBlockHashes(2, 1, 0)
- peer2.AddBlocks(0, 1, 2)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[6] = []int{}
- blockPoolTester.refBlockChain[3] = []int{4}
- delete(blockPoolTester.refBlockChain, 7)
- delete(blockPoolTester.refBlockChain, 8)
- delete(blockPoolTester.refBlockChain, 9)
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-
-}
-
-func TestForkSwitchBackByNewBlocks(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(11)
- blockPoolTester.refBlockChain[3] = []int{4, 7}
- delete(blockPoolTester.refBlockChain, 6)
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 9)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
- peer2.blocksRequestsMap = peer1.blocksRequestsMap
-
- peer1.AddPeer()
- peer1.AddBlocks(8, 9) //
- go peer1.AddBlockHashes(9, 8, 7, 3, 2) //
- peer1.AddBlocks(7, 8) // partial section
- peer2.AddPeer() //
- peer2.AddBlocks(5, 6) //
- go peer2.AddBlockHashes(6, 5, 4, 3, 2) // peer2 forks on block 3
- peer2.AddBlocks(1, 2, 3, 4, 5) //
-
- // peer1 finds new blocks
- peer1.td = 3
- peer1.currentBlock = 11
- peer1.AddPeer()
- go peer1.AddBlocks(10, 11)
- go peer1.AddBlockHashes(11, 10, 9)
- peer1.AddBlocks(9, 10)
- go peer1.AddBlocks(3, 7) // tests that block requests on earlier fork are remembered
- go peer1.AddBlockHashes(2, 1, 0) // tests that hash request from root of connecting chain section (added by demoted peer) is remembered
- peer1.AddBlocks(0, 1)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[11] = []int{}
- blockPoolTester.refBlockChain[3] = []int{7}
- delete(blockPoolTester.refBlockChain, 6)
- delete(blockPoolTester.refBlockChain, 5)
- delete(blockPoolTester.refBlockChain, 4)
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-
-}
-
-func TestForkSwitchBackByPeerSwitchBack(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(9)
- blockPoolTester.refBlockChain[3] = []int{4, 7}
- delete(blockPoolTester.refBlockChain, 6)
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 9)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
- peer2.blocksRequestsMap = peer1.blocksRequestsMap
-
- peer1.AddPeer()
- go peer1.AddBlocks(8, 9)
- go peer1.AddBlockHashes(9, 8, 7, 3, 2)
- peer1.AddBlocks(7, 8)
- peer2.AddPeer()
- go peer2.AddBlocks(5, 6) //
- go peer2.AddBlockHashes(6, 5, 4, 3, 2) // peer2 forks on block 3
- peer2.AddBlocks(2, 3, 4, 5) //
- blockPool.RemovePeer("peer2") // peer2 disconnects, peer1 is promoted again as best peer
- go peer1.AddBlocks(3, 7) // tests that block requests on earlier fork are remembered and orphan section relinks to existing parent block
- go peer1.AddBlocks(1, 2) //
- go peer1.AddBlockHashes(2, 1, 0) //
- peer1.AddBlocks(0, 1)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[9] = []int{}
- blockPoolTester.refBlockChain[3] = []int{7}
- delete(blockPoolTester.refBlockChain, 6)
- delete(blockPoolTester.refBlockChain, 5)
- delete(blockPoolTester.refBlockChain, 4)
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-
-}
-
-func TestForkCompleteSectionSwitchBackByPeerSwitchBack(t *testing.T) {
- logInit()
- _, blockPool, blockPoolTester := newTestBlockPool(t)
- blockPoolTester.blockChain[0] = nil
- blockPoolTester.initRefBlockChain(9)
- blockPoolTester.refBlockChain[3] = []int{4, 7}
- delete(blockPoolTester.refBlockChain, 6)
-
- blockPool.Start()
-
- peer1 := blockPoolTester.newPeer("peer1", 1, 9)
- peer2 := blockPoolTester.newPeer("peer2", 2, 6)
- peer2.blocksRequestsMap = peer1.blocksRequestsMap
-
- peer1.AddPeer()
- go peer1.AddBlocks(8, 9)
- go peer1.AddBlockHashes(9, 8, 7)
- peer1.AddBlocks(3, 7, 8) // make sure this section is complete
- time.Sleep(1 * time.Second)
- go peer1.AddBlockHashes(7, 3, 2) // block 3/7 is section boundary
- peer1.AddBlocks(2, 3) // partially complete sections block 2 missing
- peer2.AddPeer() //
- go peer2.AddBlocks(5, 6) //
- go peer2.AddBlockHashes(6, 5, 4, 3, 2) // peer2 forks on block 3
- peer2.AddBlocks(2, 3, 4, 5) // block 2 still missing.
- blockPool.RemovePeer("peer2") // peer2 disconnects, peer1 is promoted again as best peer
- // peer1.AddBlockHashes(7, 3) // tests that hash request from fork root is remembered even though section process completed
- go peer1.AddBlockHashes(2, 1, 0) //
- peer1.AddBlocks(0, 1, 2)
-
- blockPool.Wait(waitTimeout * time.Second)
- blockPool.Stop()
- blockPoolTester.refBlockChain[9] = []int{}
- blockPoolTester.refBlockChain[3] = []int{7}
- delete(blockPoolTester.refBlockChain, 6)
- delete(blockPoolTester.refBlockChain, 5)
- delete(blockPoolTester.refBlockChain, 4)
- blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
-
-}