OSDN Git Service

Merge pull request #201 from Bytom/v0.1
[bytom/vapor.git] / protocol / state / blockindex_test.go
diff --git a/protocol/state/blockindex_test.go b/protocol/state/blockindex_test.go
new file mode 100644 (file)
index 0000000..360c049
--- /dev/null
@@ -0,0 +1,181 @@
+package state
+
+import (
+       "testing"
+
+       "github.com/davecgh/go-spew/spew"
+
+       "github.com/vapor/protocol/bc"
+       "github.com/vapor/protocol/bc/types"
+)
+
+func TestCalcPastMedianTime(t *testing.T) {
+       cases := []struct {
+               Timestamps []uint64
+               MedianTime uint64
+       }{
+               {
+                       Timestamps: []uint64{1},
+                       MedianTime: 1,
+               },
+               {
+                       Timestamps: []uint64{1, 2},
+                       MedianTime: 2,
+               },
+               {
+                       Timestamps: []uint64{1, 3, 2},
+                       MedianTime: 2,
+               },
+               {
+                       Timestamps: []uint64{1, 3, 2, 3},
+                       MedianTime: 3,
+               },
+               {
+                       Timestamps: []uint64{1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9},
+                       MedianTime: 6,
+               },
+               {
+                       Timestamps: []uint64{1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9, 11, 11, 11, 14},
+                       MedianTime: 10,
+               },
+       }
+
+       for idx, c := range cases {
+               var parentNode *BlockNode
+               for i := range c.Timestamps {
+                       blockHeader := &types.BlockHeader{
+                               Height:    uint64(i),
+                               Timestamp: c.Timestamps[i],
+                       }
+
+                       blockNode, err := NewBlockNode(blockHeader, parentNode)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       parentNode = blockNode
+               }
+
+               medianTime := parentNode.CalcPastMedianTime()
+               if medianTime != c.MedianTime {
+                       t.Fatalf("calc median timestamp failed, index: %d, expected: %d, have: %d", idx, c.MedianTime, medianTime)
+               }
+       }
+}
+
+func TestSetMainChain(t *testing.T) {
+       blockIndex := NewBlockIndex()
+       var lastNode *BlockNode
+       for i := uint64(0); i < 4; i++ {
+               node := &BlockNode{
+                       Height: i,
+                       Hash:   bc.Hash{V0: i},
+                       Parent: lastNode,
+               }
+               blockIndex.AddNode(node)
+               lastNode = node
+       }
+
+       tailNode := lastNode
+       blockIndex.SetMainChain(lastNode)
+       for lastNode.Parent != nil {
+               if !blockIndex.InMainchain(lastNode.Hash) {
+                       t.Fatalf("block %d, hash %v is not in main chain", lastNode.Height, lastNode.Hash)
+               }
+               lastNode = lastNode.Parent
+       }
+
+       // fork and set main chain
+       forkHeight := uint64(1)
+       lastNode = blockIndex.nodeByHeight(forkHeight)
+       for i := uint64(1); i <= 3; i++ {
+               node := &BlockNode{
+                       Height: lastNode.Height + 1,
+                       Hash:   bc.Hash{V1: uint64(i)},
+                       Parent: lastNode,
+               }
+               blockIndex.AddNode(node)
+               lastNode = node
+       }
+
+       bestNode := lastNode
+       blockIndex.SetMainChain(lastNode)
+       for lastNode.Parent != nil {
+               if !blockIndex.InMainchain(lastNode.Hash) {
+                       t.Fatalf("after fork, block %d, hash %v is not in main chain", lastNode.Height, lastNode.Hash)
+               }
+               lastNode = lastNode.Parent
+       }
+
+       if bestNode != blockIndex.BestNode() {
+               t.Fatalf("check best node failed")
+       }
+
+       for tailNode.Parent != nil && tailNode.Height > forkHeight {
+               if blockIndex.InMainchain(tailNode.Hash) {
+                       t.Fatalf("old chain block %d, hash %v still in main chain", tailNode.Height, tailNode.Hash)
+               }
+               tailNode = tailNode.Parent
+       }
+}
+
+// MockBlockIndex will mock a empty BlockIndex
+func MockBlockIndex() *BlockIndex {
+       return &BlockIndex{
+               index:       make(map[bc.Hash]*BlockNode),
+               heightIndex: make(map[uint64][]*BlockNode),
+               mainChain:   make([]*BlockNode, 0, 2),
+       }
+}
+
+func TestSetMainChainExtendCap(t *testing.T) {
+       blockIndex := MockBlockIndex()
+       var lastNode *BlockNode
+
+       cases := []struct {
+               start   uint64
+               stop    uint64
+               wantLen int
+               wantCap int
+       }{
+               {
+                       start:   0,
+                       stop:    500,
+                       wantLen: 500,
+                       wantCap: 500 + approxNodesPerDay,
+               },
+               {
+                       start:   500,
+                       stop:    1000,
+                       wantLen: 1000,
+                       wantCap: 500 + approxNodesPerDay,
+               },
+               {
+                       start:   1000,
+                       stop:    2000,
+                       wantLen: 2000,
+                       wantCap: 2000 + approxNodesPerDay,
+               },
+       }
+
+       for num, c := range cases {
+               for i := c.start; i < c.stop; i++ {
+                       node := &BlockNode{
+                               Height: i,
+                               Hash:   bc.Hash{V0: i},
+                               Parent: lastNode,
+                       }
+                       blockIndex.AddNode(node)
+                       lastNode = node
+               }
+               blockIndex.SetMainChain(lastNode)
+               if c.wantLen != len(blockIndex.mainChain) || c.wantCap != cap(blockIndex.mainChain) {
+                       t.Fatalf("SetMainChain extended capacity error, index: %d, got len: %d, got cap: %d, want len: %d, want cap: %d", num, len(blockIndex.mainChain), cap(blockIndex.mainChain), c.wantLen, c.wantCap)
+               }
+       }
+
+       for i := 0; i < len(blockIndex.mainChain); i++ {
+               if blockIndex.mainChain[i] != blockIndex.index[blockIndex.mainChain[i].Hash] {
+                       t.Fatal("SetMainChain extended capacity error, index:", i, "want:", spew.Sdump(blockIndex.mainChain[i]), "got:", spew.Sdump(blockIndex.index[blockIndex.mainChain[i].Hash]))
+               }
+       }
+}