aboutsummaryrefslogblamecommitdiffstats
path: root/blockpool/blockpool_test.go
blob: b28c2abbf19d230db28cddb5bc0f12701addc55c (plain) (tree)
1
2
3
4
5
6
7
8
9






                                                        

 



                      


                                                  


































                                                                      







                                                            
                                                       


















                                                                      
                                                       


















                                                                      
                                                       




















                                                                      


                                                       




                                                                
 
                                 
                    







                                                                                                         














                                                                      

                                                       





                                                                                                                         
                                                

















                                                                                                                                                      

                                                       























                                                                                                                                                                                                 

                                                       
























                                                                                                                                                                                                 

                                                       

























                                                                                                             

                                                         




























                                                                                                                         



                                                        































                                                                                     



                                                        











                                                                          
                     






























                                                                                                                                              







                                                        



































                                                                                                                                                                




                                                        



                                          

                                                                                      






                                                                                                           
                                                   











                                                                      
package blockpool

import (
    "testing"
    "time"

    "github.com/ethereum/go-ethereum/blockpool/test"
)

func init() {
    test.LogInit()
}

// using the mock framework in blockpool_util_test
// we test various scenarios here

func TestPeerWithKnownBlock(t *testing.T) {
    test.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)
    blockPool.Stop()
    // no request on known block
    peer0.checkBlockHashesRequests()
}

func TestPeerWithKnownParentBlock(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.initRefBlockChain(1)
    blockPoolTester.blockChain[0] = nil
    blockPool.Start()

    peer0 := blockPoolTester.newPeer("0", 1, 1)
    peer0.AddPeer()
    peer0.serveBlocks(0, 1)

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    peer0.checkBlocksRequests([]int{1})
    peer0.checkBlockHashesRequests()
    blockPoolTester.refBlockChain[1] = []int{}
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestSimpleChain(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(2)

    blockPool.Start()

    peer1 := blockPoolTester.newPeer("peer1", 2, 2)
    peer1.AddPeer()
    peer1.serveBlocks(1, 2)
    go peer1.serveBlockHashes(2, 1, 0)
    peer1.serveBlocks(0, 1)

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    blockPoolTester.refBlockChain[2] = []int{}
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestChainConnectingWithParentHash(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(3)

    blockPool.Start()

    peer1 := blockPoolTester.newPeer("peer1", 3, 3)
    peer1.AddPeer()
    go peer1.serveBlocks(2, 3)
    go peer1.serveBlockHashes(3, 2, 1)
    peer1.serveBlocks(0, 1, 2)

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    blockPoolTester.refBlockChain[3] = []int{}
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestMultiSectionChain(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(5)

    blockPool.Start()

    peer1 := blockPoolTester.newPeer("peer1", 5, 5)

    peer1.AddPeer()
    go peer1.serveBlocks(4, 5)
    go peer1.serveBlockHashes(5, 4, 3)
    go peer1.serveBlocks(2, 3, 4)
    go peer1.serveBlockHashes(3, 2, 1, 0)
    peer1.serveBlocks(0, 1, 2)

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    blockPoolTester.refBlockChain[5] = []int{}
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestNewBlocksOnPartialChain(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(7)
    blockPool.Start()

    peer1 := blockPoolTester.newPeer("peer1", 5, 5)
    blockPoolTester.tds = make(map[int]int)
    blockPoolTester.tds[5] = 5

    peer1.AddPeer()
    go peer1.serveBlocks(4, 5) // partially complete section
    go peer1.serveBlockHashes(5, 4, 3)
    peer1.serveBlocks(3, 4) // partially complete section

    // peer1 found new blocks
    peer1.td = 7
    peer1.currentBlock = 7
    peer1.AddPeer()
    peer1.sendBlocks(6, 7)
    go peer1.serveBlockHashes(7, 6, 5)
    go peer1.serveBlocks(2, 3)
    go peer1.serveBlocks(5, 6)
    go peer1.serveBlockHashes(3, 2, 1) // tests that hash request from known chain root is remembered
    peer1.serveBlocks(0, 1, 2)

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    blockPoolTester.refBlockChain[7] = []int{}
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestPeerSwitchUp(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(7)

    blockPool.Start()

    peer1 := blockPoolTester.newPeer("peer1", 6, 6)
    peer2 := blockPoolTester.newPeer("peer2", 7, 7)

    peer1.AddPeer()
    go peer1.serveBlocks(5, 6)
    go peer1.serveBlockHashes(6, 5, 4, 3) //
    peer1.serveBlocks(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.serveBlocks(6, 7)            //
    go peer2.serveBlocks(4, 5)            // tests that block request for earlier section is remembered
    go peer1.serveBlocks(3, 4)            // tests that connecting section by demoted peer is remembered and blocks are accepted from demoted peer
    go peer2.serveBlockHashes(3, 2, 1, 0) // tests that known chain section is activated, hash requests from 3 is remembered
    peer2.serveBlocks(0, 1, 2)            // final blocks linking to blockchain sent

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    blockPoolTester.refBlockChain[7] = []int{}
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestPeerSwitchDownOverlapSectionWithoutRootBlock(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(6)
    blockPool.Start()

    peer1 := blockPoolTester.newPeer("peer1", 4, 4)
    peer2 := blockPoolTester.newPeer("peer2", 6, 6)

    peer2.AddPeer()
    peer2.serveBlocks(5, 6)                  // partially complete, section will be preserved
    peer2.serveBlockHashes(6, 5, 4)          // no go: make sure skeleton is created
    peer1.AddPeer()                          // inferior peer1 is promoted as best peer
    blockPool.RemovePeer("peer2")            // peer2 disconnects
    go peer1.serveBlockHashes(4, 3, 2, 1, 0) //
    go peer1.serveBlocks(3, 4)               //
    go peer1.serveBlocks(4, 5)               // tests that section set by demoted peer is remembered and blocks are accepted from new peer if they have it even if peers original TD is lower
    peer1.serveBlocks(0, 1, 2, 3)

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    blockPoolTester.refBlockChain[6] = []int{} // tests that idle sections are not inserted in blockchain
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestPeerSwitchDownOverlapSectionWithRootBlock(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(6)
    blockPool.Start()

    peer1 := blockPoolTester.newPeer("peer1", 4, 4)
    peer2 := blockPoolTester.newPeer("peer2", 6, 6)

    peer2.AddPeer()
    peer2.serveBlocks(5, 6)                  // partially complete, section will be preserved
    go peer2.serveBlockHashes(6, 5, 4)       //
    peer2.serveBlocks(3, 4)                  // !incomplete section
    time.Sleep(100 * time.Millisecond)       // make sure block 4 added
    peer1.AddPeer()                          // inferior peer1 is promoted as best peer
    blockPool.RemovePeer("peer2")            // peer2 disconnects
    go peer1.serveBlockHashes(4, 3, 2, 1, 0) // tests that hash request are directly connecting if the head block exists
    go peer1.serveBlocks(4, 5)               // tests that section set by demoted peer is remembered and blocks are accepted from new peer if they have it even if peers original TD is lower
    peer1.serveBlocks(0, 1, 2, 3)

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    blockPoolTester.refBlockChain[6] = []int{} // tests that idle sections are not inserted in blockchain
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestPeerSwitchDownDisjointSection(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(3)
    blockPool.Start()

    peer1 := blockPoolTester.newPeer("peer1", 3, 3)
    peer2 := blockPoolTester.newPeer("peer2", 6, 6)

    peer2.AddPeer()
    peer2.serveBlocks(5, 6)            // partially complete, section will be preserved
    go peer2.serveBlockHashes(6, 5, 4) //
    peer2.serveBlocks(3, 4, 5)         //
    time.Sleep(100 * time.Millisecond) // make sure blocks are received
    peer1.AddPeer()                    // inferior peer1 is promoted as best peer
    blockPool.RemovePeer("peer2")      // peer2 disconnects
    go peer1.serveBlocks(2, 3)         //
    go peer1.serveBlockHashes(3, 2, 1) //
    peer1.serveBlocks(0, 1, 2)         //

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    blockPoolTester.refBlockChain[3] = []int{} // tests that idle sections are not inserted in blockchain
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestPeerSwitchBack(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(8)

    blockPool.Start()

    peer1 := blockPoolTester.newPeer("peer1", 11, 11)
    peer2 := blockPoolTester.newPeer("peer2", 8, 8)

    peer2.AddPeer()
    go peer2.serveBlocks(7, 8)
    go peer2.serveBlockHashes(8, 7, 6)
    go peer2.serveBlockHashes(6, 5, 4)
    peer2.serveBlocks(4, 5)                  // section partially complete
    peer1.AddPeer()                          // peer1 is promoted as best peer
    go peer1.serveBlocks(10, 11)             //
    peer1.serveBlockHashes(11, 10)           // only gives useless results
    blockPool.RemovePeer("peer1")            // peer1 disconnects
    go peer2.serveBlockHashes(4, 3, 2, 1, 0) // tests that asking for hashes from 4 is remembered
    go peer2.serveBlocks(3, 4, 5, 6, 7, 8)   // tests that section 4, 5, 6 and 7, 8 are remembered for missing blocks
    peer2.serveBlocks(0, 1, 2, 3)

    blockPool.Wait(waitTimeout)
    blockPool.Stop()
    blockPoolTester.refBlockChain[8] = []int{}
    blockPoolTester.checkBlockChain(blockPoolTester.refBlockChain)
}

func TestForkSimple(t *testing.T) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(9)
    blockPoolTester.refBlockChain[3] = []int{4, 7}
    delete(blockPoolTester.refBlockChain, 6)

    blockPool.Start()
    blockPoolTester.tds = make(map[int]int)
    blockPoolTester.tds[6] = 10
    peer1 := blockPoolTester.newPeer("peer1", 9, 9)
    peer2 := blockPoolTester.newPeer("peer2", 10, 6)

    peer1.AddPeer()
    go peer1.serveBlocks(8, 9)
    go peer1.serveBlockHashes(9, 8, 7, 3, 2)
    peer1.serveBlocks(1, 2, 3, 7, 8)
    peer2.AddPeer()                          // peer2 is promoted as best peer
    go peer2.serveBlocks(5, 6)               //
    go peer2.serveBlockHashes(6, 5, 4, 3, 2) // fork on 3 -> 4 (earlier child: 7)
    go peer2.serveBlocks(1, 2, 3, 4, 5)
    go peer2.serveBlockHashes(2, 1, 0)
    peer2.serveBlocks(0, 1, 2)

    blockPool.Wait(waitTimeout)
    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) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(11)
    blockPoolTester.refBlockChain[3] = []int{4, 7}
    delete(blockPoolTester.refBlockChain, 6)

    blockPool.Start()
    blockPoolTester.tds = make(map[int]int)
    blockPoolTester.tds[6] = 10
    peer1 := blockPoolTester.newPeer("peer1", 9, 9)
    peer2 := blockPoolTester.newPeer("peer2", 10, 6)

    peer1.AddPeer()
    go peer1.serveBlocks(8, 9)               //
    go peer1.serveBlockHashes(9, 8, 7, 3, 2) //
    peer1.serveBlocks(7, 8)                  // partial section
    // time.Sleep(1 * time.Second)
    peer2.AddPeer()                          //
    go peer2.serveBlocks(5, 6)               //
    go peer2.serveBlockHashes(6, 5, 4, 3, 2) // peer2 forks on block 3
    peer2.serveBlocks(1, 2, 3, 4, 5)         //

    // peer1 finds new blocks
    peer1.td = 11
    peer1.currentBlock = 11
    peer1.AddPeer()
    go peer1.serveBlocks(10, 11)
    go peer1.serveBlockHashes(11, 10, 9)
    go peer1.serveBlocks(9, 10)
    // time.Sleep(1 * time.Second)
    go peer1.serveBlocks(3, 7)      // tests that block requests on earlier fork are remembered
    go peer1.serveBlockHashes(2, 1) // tests that hash request from root of connecting chain section (added by demoted peer) is remembered
    peer1.serveBlocks(0, 1)

    blockPool.Wait(waitTimeout)
    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) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(9)
    blockPoolTester.refBlockChain[3] = []int{4, 7}
    delete(blockPoolTester.refBlockChain, 6)

    blockPool.Start()

    blockPoolTester.tds = make(map[int]int)
    blockPoolTester.tds[6] = 10

    blockPoolTester.tds = make(map[int]int)
    blockPoolTester.tds[6] = 10

    peer1 := blockPoolTester.newPeer("peer1", 9, 9)
    peer2 := blockPoolTester.newPeer("peer2", 10, 6)

    peer1.AddPeer()
    go peer1.serveBlocks(8, 9)
    go peer1.serveBlockHashes(9, 8, 7, 3, 2)
    peer1.serveBlocks(7, 8)
    peer2.AddPeer()
    go peer2.serveBlocks(5, 6)               //
    go peer2.serveBlockHashes(6, 5, 4, 3, 2) // peer2 forks on block 3
    peer2.serveBlocks(2, 3, 4, 5)            //
    blockPool.RemovePeer("peer2")            // peer2 disconnects, peer1 is promoted again as best peer
    go peer1.serveBlocks(1, 2)               //
    go peer1.serveBlockHashes(2, 1, 0)       //
    go peer1.serveBlocks(3, 7)               // tests that block requests on earlier fork are remembered and orphan section relinks to existing parent block
    peer1.serveBlocks(0, 1)

    blockPool.Wait(waitTimeout)
    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) {
    test.LogInit()
    _, blockPool, blockPoolTester := newTestBlockPool(t)
    blockPoolTester.blockChain[0] = nil
    blockPoolTester.initRefBlockChain(9)
    blockPoolTester.refBlockChain[3] = []int{4, 7}
    delete(blockPoolTester.refBlockChain, 6)

    blockPool.Start()

    blockPoolTester.tds = make(map[int]int)
    blockPoolTester.tds[6] = 10

    peer1 := blockPoolTester.newPeer("peer1", 9, 9)
    peer2 := blockPoolTester.newPeer("peer2", 10, 6)

    peer1.AddPeer()
    go peer1.serveBlocks(8, 9)
    go peer1.serveBlockHashes(9, 8, 7)
    peer1.serveBlocks(3, 7, 8)               // make sure this section is complete
    time.Sleep(1 * time.Second)              //
    go peer1.serveBlockHashes(7, 3, 2)       // block 3/7 is section boundary
    peer1.serveBlocks(2, 3)                  // partially complete sections block 2 missing
    peer2.AddPeer()                          //
    go peer2.serveBlocks(5, 6)               //
    go peer2.serveBlockHashes(6, 5, 4, 3, 2) // peer2 forks on block 3
    peer2.serveBlocks(2, 3, 4, 5)            // block 2 still missing.
    blockPool.RemovePeer("peer2")            // peer2 disconnects, peer1 is promoted again as best peer
    go peer1.serveBlockHashes(2, 1, 0)       //
    peer1.serveBlocks(0, 1, 2)

    blockPool.Wait(waitTimeout)
    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)

}