github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/state/blockindex_test.go (about) 1 package state 2 3 import ( 4 "math" 5 "math/big" 6 "reflect" 7 "testing" 8 9 "github.com/davecgh/go-spew/spew" 10 11 "github.com/bytom/bytom/consensus" 12 "github.com/bytom/bytom/consensus/difficulty" 13 "github.com/bytom/bytom/protocol/bc" 14 "github.com/bytom/bytom/protocol/bc/types" 15 "github.com/bytom/bytom/testutil" 16 ) 17 18 func stringToBigInt(s string, base int) *big.Int { 19 result, _ := new(big.Int).SetString(s, base) 20 return result 21 } 22 23 func TestNewBlockNode(t *testing.T) { 24 cases := []struct { 25 blockHeader *types.BlockHeader 26 parentNode *BlockNode 27 wantBlockNode *BlockNode 28 }{ 29 { 30 blockHeader: &types.BlockHeader{ 31 Height: uint64(0), 32 Timestamp: 0, 33 Bits: 1000, 34 }, 35 parentNode: &BlockNode{ 36 WorkSum: &big.Int{}, 37 }, 38 wantBlockNode: &BlockNode{ 39 Bits: 1000, 40 Hash: testutil.MustDecodeHash("f1a5a6ddebad7285928a07ce1534104a8d1cd435fc80e90bb9f0034bbe5f8109"), 41 Seed: consensus.InitialSeed, 42 WorkSum: new(big.Int).SetInt64(0), 43 Parent: &BlockNode{ 44 WorkSum: &big.Int{}, 45 }, 46 }, 47 }, 48 { 49 blockHeader: &types.BlockHeader{ 50 Height: uint64(100), 51 Timestamp: 0, 52 Bits: 10000000000, 53 }, 54 parentNode: &BlockNode{ 55 WorkSum: new(big.Int).SetInt64(100), 56 }, 57 wantBlockNode: &BlockNode{ 58 Bits: 10000000000, 59 Hash: testutil.MustDecodeHash("b14067726f09d74da89aeb97ca1b15a8b95760b47a0d71549b0aa5ab8c5e724f"), 60 Seed: consensus.InitialSeed, 61 Height: uint64(100), 62 WorkSum: stringToBigInt("193956598387464313942329958138505708296934647681139973265423088790474254103", 10), 63 Parent: &BlockNode{ 64 WorkSum: new(big.Int).SetInt64(100), 65 }, 66 }, 67 }, 68 { 69 blockHeader: &types.BlockHeader{ 70 Height: uint64(100), 71 Timestamp: 0, 72 Bits: 10000000000, 73 }, 74 parentNode: &BlockNode{ 75 WorkSum: new(big.Int).SetInt64(math.MaxInt64), 76 }, 77 wantBlockNode: &BlockNode{ 78 Bits: 10000000000, 79 Hash: testutil.MustDecodeHash("b14067726f09d74da89aeb97ca1b15a8b95760b47a0d71549b0aa5ab8c5e724f"), 80 Seed: consensus.InitialSeed, 81 Height: uint64(100), 82 WorkSum: stringToBigInt("193956598387464313942329958138505708296934647681139973274646460827329029810", 10), 83 Parent: &BlockNode{ 84 WorkSum: new(big.Int).SetInt64(math.MaxInt64), 85 }, 86 }, 87 }, 88 } 89 90 for i, c := range cases { 91 blockNode, err := NewBlockNode(c.blockHeader, c.parentNode) 92 if err != nil { 93 t.Fatal(err) 94 } 95 96 if !reflect.DeepEqual(blockNode, c.wantBlockNode) { 97 t.Fatal("NewBlockNode test error, index:", i, "want:", spew.Sdump(c.wantBlockNode), "got:", spew.Sdump(blockNode)) 98 } 99 } 100 } 101 102 func TestCalcPastMedianTime(t *testing.T) { 103 cases := []struct { 104 Timestamps []uint64 105 MedianTime uint64 106 }{ 107 { 108 Timestamps: []uint64{1}, 109 MedianTime: 1, 110 }, 111 { 112 Timestamps: []uint64{1, 2}, 113 MedianTime: 2, 114 }, 115 { 116 Timestamps: []uint64{1, 3, 2}, 117 MedianTime: 2, 118 }, 119 { 120 Timestamps: []uint64{1, 3, 2, 3}, 121 MedianTime: 3, 122 }, 123 { 124 Timestamps: []uint64{1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9}, 125 MedianTime: 6, 126 }, 127 { 128 Timestamps: []uint64{1, 2, 3, 4, 5, 6, 7, 8, 11, 10, 9, 11, 11, 11, 14}, 129 MedianTime: 10, 130 }, 131 } 132 133 for idx, c := range cases { 134 var parentNode *BlockNode 135 for i := range c.Timestamps { 136 blockHeader := &types.BlockHeader{ 137 Height: uint64(i), 138 Timestamp: c.Timestamps[i], 139 } 140 141 blockNode, err := NewBlockNode(blockHeader, parentNode) 142 if err != nil { 143 t.Fatal(err) 144 } 145 parentNode = blockNode 146 } 147 148 medianTime := parentNode.CalcPastMedianTime() 149 if medianTime != c.MedianTime { 150 t.Fatalf("calc median timestamp failed, index: %d, expected: %d, have: %d", idx, c.MedianTime, medianTime) 151 } 152 } 153 } 154 155 func TestCalcNextBits(t *testing.T) { 156 targetTimeSpan := uint64(consensus.BlocksPerRetarget * consensus.TargetSecondsPerBlock) 157 cases := []struct { 158 parentNode *BlockNode 159 currentNode *BlockNode 160 bits uint64 161 }{ 162 { 163 currentNode: &BlockNode{ 164 Height: 0, 165 Bits: 1000, 166 }, 167 bits: 1000, 168 }, 169 { 170 currentNode: &BlockNode{ 171 Height: consensus.BlocksPerRetarget - 1, 172 Bits: 1000, 173 }, 174 bits: 1000, 175 }, 176 { 177 parentNode: &BlockNode{ 178 Height: 0, 179 Timestamp: 0, 180 }, 181 currentNode: &BlockNode{ 182 Height: consensus.BlocksPerRetarget, 183 Bits: difficulty.BigToCompact(big.NewInt(1000)), 184 Timestamp: targetTimeSpan, 185 }, 186 bits: difficulty.BigToCompact(big.NewInt(1000)), 187 }, 188 { 189 parentNode: &BlockNode{ 190 Height: 0, 191 Timestamp: 0, 192 }, 193 currentNode: &BlockNode{ 194 Height: consensus.BlocksPerRetarget, 195 Bits: difficulty.BigToCompact(big.NewInt(1000)), 196 Timestamp: targetTimeSpan * 2, 197 }, 198 bits: difficulty.BigToCompact(big.NewInt(2000)), 199 }, 200 } 201 202 for i, c := range cases { 203 c.currentNode.Parent = c.parentNode 204 bits := c.currentNode.CalcNextBits() 205 if bits != c.bits { 206 t.Fatalf("calc next bit failed, index: %d, expected: %d, have: %d", i, c.bits, bits) 207 } 208 } 209 } 210 211 func TestCalcNextSeed(t *testing.T) { 212 cases := []struct { 213 node *BlockNode 214 seed *bc.Hash 215 }{ 216 { 217 node: &BlockNode{ 218 Height: 0, 219 }, 220 seed: consensus.InitialSeed, 221 }, 222 { 223 node: &BlockNode{ 224 Height: consensus.SeedPerRetarget - 1, 225 Seed: &bc.Hash{V1: 100}, 226 }, 227 seed: &bc.Hash{V1: 100}, 228 }, 229 { 230 node: &BlockNode{ 231 Height: consensus.SeedPerRetarget, 232 Seed: &bc.Hash{V2: 200}, 233 Hash: bc.Hash{V3: 300}, 234 }, 235 seed: &bc.Hash{V3: 300}, 236 }, 237 } 238 239 for i, c := range cases { 240 seed := c.node.CalcNextSeed() 241 if *seed != *c.seed { 242 t.Fatalf("calc next seed failed, index: %d, expected: %v, have: %v", i, c.seed, seed) 243 } 244 } 245 } 246 247 func TestSetMainChain(t *testing.T) { 248 blockIndex := NewBlockIndex() 249 var lastNode *BlockNode 250 for i := uint64(0); i < 4; i++ { 251 node := &BlockNode{ 252 Height: i, 253 Hash: bc.Hash{V0: i}, 254 Parent: lastNode, 255 } 256 blockIndex.AddNode(node) 257 lastNode = node 258 } 259 260 tailNode := lastNode 261 blockIndex.SetMainChain(lastNode) 262 for lastNode.Parent != nil { 263 if !blockIndex.InMainchain(lastNode.Hash) { 264 t.Fatalf("block %d, hash %v is not in main chain", lastNode.Height, lastNode.Hash) 265 } 266 lastNode = lastNode.Parent 267 } 268 269 // fork and set main chain 270 forkHeight := uint64(1) 271 lastNode = blockIndex.nodeByHeight(forkHeight) 272 for i := uint64(1); i <= 3; i++ { 273 node := &BlockNode{ 274 Height: lastNode.Height + 1, 275 Hash: bc.Hash{V1: uint64(i)}, 276 Parent: lastNode, 277 } 278 blockIndex.AddNode(node) 279 lastNode = node 280 } 281 282 bestNode := lastNode 283 blockIndex.SetMainChain(lastNode) 284 for lastNode.Parent != nil { 285 if !blockIndex.InMainchain(lastNode.Hash) { 286 t.Fatalf("after fork, block %d, hash %v is not in main chain", lastNode.Height, lastNode.Hash) 287 } 288 lastNode = lastNode.Parent 289 } 290 291 if bestNode != blockIndex.BestNode() { 292 t.Fatalf("check best node failed") 293 } 294 295 for tailNode.Parent != nil && tailNode.Height > forkHeight { 296 if blockIndex.InMainchain(tailNode.Hash) { 297 t.Fatalf("old chain block %d, hash %v still in main chain", tailNode.Height, tailNode.Hash) 298 } 299 tailNode = tailNode.Parent 300 } 301 } 302 303 // MockBlockIndex will mock a empty BlockIndex 304 func MockBlockIndex() *BlockIndex { 305 return &BlockIndex{ 306 index: make(map[bc.Hash]*BlockNode), 307 mainChain: make([]*BlockNode, 0, 2), 308 } 309 } 310 311 func TestSetMainChainExtendCap(t *testing.T) { 312 blockIndex := MockBlockIndex() 313 var lastNode *BlockNode 314 315 cases := []struct { 316 start uint64 317 stop uint64 318 wantLen int 319 wantCap int 320 }{ 321 { 322 start: 0, 323 stop: 500, 324 wantLen: 500, 325 wantCap: 500 + approxNodesPerDay, 326 }, 327 { 328 start: 500, 329 stop: 1000, 330 wantLen: 1000, 331 wantCap: 500 + approxNodesPerDay, 332 }, 333 { 334 start: 1000, 335 stop: 2000, 336 wantLen: 2000, 337 wantCap: 2000 + approxNodesPerDay, 338 }, 339 } 340 341 for num, c := range cases { 342 for i := c.start; i < c.stop; i++ { 343 node := &BlockNode{ 344 Height: i, 345 Hash: bc.Hash{V0: i}, 346 Parent: lastNode, 347 } 348 blockIndex.AddNode(node) 349 lastNode = node 350 } 351 blockIndex.SetMainChain(lastNode) 352 if c.wantLen != len(blockIndex.mainChain) || c.wantCap != cap(blockIndex.mainChain) { 353 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) 354 } 355 } 356 357 for i := 0; i < len(blockIndex.mainChain); i++ { 358 if blockIndex.mainChain[i] != blockIndex.index[blockIndex.mainChain[i].Hash] { 359 t.Fatal("SetMainChain extended capacity error, index:", i, "want:", spew.Sdump(blockIndex.mainChain[i]), "got:", spew.Sdump(blockIndex.index[blockIndex.mainChain[i].Hash])) 360 } 361 } 362 }