github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/validation/block_test.go (about) 1 package validation 2 3 import ( 4 "math" 5 "testing" 6 "time" 7 8 "github.com/bytom/bytom/consensus" 9 "github.com/bytom/bytom/mining/tensority" 10 "github.com/bytom/bytom/protocol/bc" 11 "github.com/bytom/bytom/protocol/bc/types" 12 "github.com/bytom/bytom/protocol/state" 13 "github.com/bytom/bytom/protocol/vm" 14 "github.com/bytom/bytom/protocol/vm/vmutil" 15 "github.com/bytom/bytom/testutil" 16 ) 17 18 func TestCheckBlockTime(t *testing.T) { 19 cases := []struct { 20 desc string 21 blockTime uint64 22 parentTime []uint64 23 err error 24 }{ 25 { 26 blockTime: 1520000001, 27 parentTime: []uint64{1520000000}, 28 err: nil, 29 }, 30 { 31 desc: "timestamp less than past median time (blocktest#1005)", 32 blockTime: 1510000094, 33 parentTime: []uint64{1520000000, 1510000099, 1510000098, 1510000097, 1510000096, 1510000095, 1510000094, 1510000093, 1510000092, 1510000091, 1510000090}, 34 err: errBadTimestamp, 35 }, 36 { 37 desc: "timestamp greater than max limit (blocktest#1006)", 38 blockTime: 9999999999, 39 parentTime: []uint64{1520000000}, 40 err: errBadTimestamp, 41 }, 42 { 43 desc: "timestamp of the block and the parent block are both greater than max limit (blocktest#1007)", 44 blockTime: uint64(time.Now().Unix()) + consensus.MaxTimeOffsetSeconds + 2, 45 parentTime: []uint64{uint64(time.Now().Unix()) + consensus.MaxTimeOffsetSeconds + 1}, 46 err: errBadTimestamp, 47 }, 48 } 49 50 parent := &state.BlockNode{Version: 1} 51 block := &bc.Block{ 52 BlockHeader: &bc.BlockHeader{Version: 1}, 53 } 54 55 for i, c := range cases { 56 parent.Timestamp = c.parentTime[0] 57 parentSuccessor := parent 58 for i := 1; i < len(c.parentTime); i++ { 59 parentSuccessor.Parent = &state.BlockNode{Version: 1, Timestamp: c.parentTime[i]} 60 parentSuccessor = parentSuccessor.Parent 61 } 62 63 block.Timestamp = c.blockTime 64 if err := checkBlockTime(block, parent); rootErr(err) != c.err { 65 t.Errorf("case %d got error %s, want %s", i, err, c.err) 66 } 67 } 68 } 69 70 func TestCheckCoinbaseAmount(t *testing.T) { 71 cases := []struct { 72 txs []*types.Tx 73 amount uint64 74 err error 75 }{ 76 { 77 txs: []*types.Tx{ 78 types.NewTx(types.TxData{ 79 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)}, 80 Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 5000, nil)}, 81 }), 82 }, 83 amount: 5000, 84 err: nil, 85 }, 86 { 87 txs: []*types.Tx{ 88 types.NewTx(types.TxData{ 89 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)}, 90 Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 5000, nil)}, 91 }), 92 }, 93 amount: 6000, 94 err: ErrWrongCoinbaseTransaction, 95 }, 96 { 97 txs: []*types.Tx{}, 98 amount: 5000, 99 err: ErrWrongCoinbaseTransaction, 100 }, 101 } 102 103 block := new(types.Block) 104 for i, c := range cases { 105 block.Transactions = c.txs 106 if err := checkCoinbaseAmount(types.MapBlock(block), c.amount); rootErr(err) != c.err { 107 t.Errorf("case %d got error %s, want %s", i, err, c.err) 108 } 109 } 110 } 111 112 func TestValidateBlockHeader(t *testing.T) { 113 iniTtensority() 114 115 cases := []struct { 116 desc string 117 block *bc.Block 118 parent *state.BlockNode 119 err error 120 }{ 121 { 122 block: &bc.Block{BlockHeader: &bc.BlockHeader{ 123 Version: 2, 124 }}, 125 parent: &state.BlockNode{ 126 Version: 1, 127 }, 128 err: errVersionRegression, 129 }, 130 { 131 block: &bc.Block{BlockHeader: &bc.BlockHeader{ 132 Version: 1, 133 Height: 20, 134 }}, 135 parent: &state.BlockNode{ 136 Version: 1, 137 Height: 18, 138 }, 139 err: errMisorderedBlockHeight, 140 }, 141 { 142 desc: "the difficulty of the block is not equals to the next difficulty of parent block (blocktest#1008)", 143 block: &bc.Block{BlockHeader: &bc.BlockHeader{ 144 Version: 1, 145 Height: 20, 146 Bits: 0, 147 }}, 148 parent: &state.BlockNode{ 149 Version: 1, 150 Height: 19, 151 Bits: 2305843009214532812, 152 }, 153 err: errBadBits, 154 }, 155 { 156 desc: "the prev block hash not equals to the hash of parent (blocktest#1004)", 157 block: &bc.Block{BlockHeader: &bc.BlockHeader{ 158 Version: 1, 159 Height: 20, 160 PreviousBlockId: &bc.Hash{V0: 18}, 161 }}, 162 parent: &state.BlockNode{ 163 Version: 1, 164 Height: 19, 165 Hash: bc.Hash{V0: 19}, 166 }, 167 err: errMismatchedBlock, 168 }, 169 { 170 desc: "check work proof fail (blocktest#1011)", 171 block: &bc.Block{ 172 ID: bc.Hash{V0: 0}, 173 BlockHeader: &bc.BlockHeader{ 174 Version: 1, 175 Height: 1, 176 Timestamp: 1523352601, 177 PreviousBlockId: &bc.Hash{V0: 0}, 178 Bits: 2305843009214532812, 179 }, 180 }, 181 parent: &state.BlockNode{ 182 Version: 1, 183 Height: 0, 184 Timestamp: 1523352600, 185 Hash: bc.Hash{V0: 0}, 186 Seed: &bc.Hash{V1: 1}, 187 Bits: 2305843009214532812, 188 }, 189 err: errWorkProof, 190 }, 191 { 192 block: &bc.Block{ 193 ID: bc.Hash{V0: 1}, 194 BlockHeader: &bc.BlockHeader{ 195 Version: 1, 196 Height: 1, 197 Timestamp: 1523352601, 198 PreviousBlockId: &bc.Hash{V0: 0}, 199 Bits: 2305843009214532812, 200 }, 201 }, 202 parent: &state.BlockNode{ 203 Version: 1, 204 Height: 0, 205 Timestamp: 1523352600, 206 Hash: bc.Hash{V0: 0}, 207 Seed: &bc.Hash{V1: 1}, 208 Bits: 2305843009214532812, 209 }, 210 err: nil, 211 }, 212 { 213 desc: "version greater than 1 (blocktest#1001)", 214 block: &bc.Block{ 215 ID: bc.Hash{V0: 1}, 216 BlockHeader: &bc.BlockHeader{ 217 Version: 2, 218 }, 219 }, 220 parent: &state.BlockNode{ 221 Version: 1, 222 }, 223 err: errVersionRegression, 224 }, 225 { 226 desc: "version equals 0 (blocktest#1002)", 227 block: &bc.Block{ 228 ID: bc.Hash{V0: 1}, 229 BlockHeader: &bc.BlockHeader{ 230 Version: 0, 231 }, 232 }, 233 parent: &state.BlockNode{ 234 Version: 1, 235 }, 236 err: errVersionRegression, 237 }, 238 { 239 desc: "version equals max uint64 (blocktest#1003)", 240 block: &bc.Block{ 241 ID: bc.Hash{V0: 1}, 242 BlockHeader: &bc.BlockHeader{ 243 Version: math.MaxUint64, 244 }, 245 }, 246 parent: &state.BlockNode{ 247 Version: 1, 248 }, 249 err: errVersionRegression, 250 }, 251 } 252 253 for i, c := range cases { 254 if err := ValidateBlockHeader(c.block, c.parent); rootErr(err) != c.err { 255 t.Errorf("case %d (%s) got error %s, want %s", i, c.desc, err, c.err) 256 } 257 } 258 } 259 260 // TestValidateBlock test the ValidateBlock function 261 func TestValidateBlock(t *testing.T) { 262 iniTtensority() 263 264 cp, _ := vmutil.DefaultCoinbaseProgram() 265 cases := []struct { 266 desc string 267 block *bc.Block 268 parent *state.BlockNode 269 err error 270 }{ 271 { 272 desc: "The calculated transaction merkel root hash is not equals to the hash of the block header (blocktest#1009)", 273 block: &bc.Block{ 274 ID: bc.Hash{V0: 1}, 275 BlockHeader: &bc.BlockHeader{ 276 Version: 1, 277 Height: 1, 278 Timestamp: 1523352601, 279 PreviousBlockId: &bc.Hash{V0: 0}, 280 Bits: 2305843009214532812, 281 TransactionsRoot: &bc.Hash{V0: 1}, 282 }, 283 Transactions: []*bc.Tx{ 284 types.MapTx(&types.TxData{ 285 Version: 1, 286 SerializedSize: 1, 287 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)}, 288 Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41250000000, cp)}, 289 }), 290 }, 291 }, 292 parent: &state.BlockNode{ 293 Version: 1, 294 Height: 0, 295 Timestamp: 1523352600, 296 Hash: bc.Hash{V0: 0}, 297 Seed: &bc.Hash{V1: 1}, 298 Bits: 2305843009214532812, 299 }, 300 err: errMismatchedMerkleRoot, 301 }, 302 { 303 desc: "The calculated transaction status merkel root hash is not equals to the hash of the block header (blocktest#1009)", 304 block: &bc.Block{ 305 ID: bc.Hash{V0: 1}, 306 BlockHeader: &bc.BlockHeader{ 307 Version: 1, 308 Height: 1, 309 Timestamp: 1523352601, 310 PreviousBlockId: &bc.Hash{V0: 0}, 311 Bits: 2305843009214532812, 312 TransactionsRoot: &bc.Hash{V0: 6294987741126419124, V1: 12520373106916389157, V2: 5040806596198303681, V3: 1151748423853876189}, 313 TransactionStatusHash: &bc.Hash{V0: 1}, 314 }, 315 Transactions: []*bc.Tx{ 316 types.MapTx(&types.TxData{ 317 Version: 1, 318 SerializedSize: 1, 319 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)}, 320 Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41250000000, cp)}, 321 }), 322 }, 323 }, 324 parent: &state.BlockNode{ 325 Version: 1, 326 Height: 0, 327 Timestamp: 1523352600, 328 Hash: bc.Hash{V0: 0}, 329 Seed: &bc.Hash{V1: 1}, 330 Bits: 2305843009214532812, 331 }, 332 err: errMismatchedMerkleRoot, 333 }, 334 { 335 desc: "the coinbase amount is less than the real coinbase amount (txtest#1014)", 336 block: &bc.Block{ 337 ID: bc.Hash{V0: 1}, 338 BlockHeader: &bc.BlockHeader{ 339 Version: 1, 340 Height: 1, 341 Timestamp: 1523352601, 342 PreviousBlockId: &bc.Hash{V0: 0}, 343 Bits: 2305843009214532812, 344 }, 345 Transactions: []*bc.Tx{ 346 types.MapTx(&types.TxData{ 347 Version: 1, 348 SerializedSize: 1, 349 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)}, 350 Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41250000000, cp)}, 351 }), 352 types.MapTx(&types.TxData{ 353 Version: 1, 354 SerializedSize: 1, 355 Inputs: []*types.TxInput{types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp)}, 356 Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 90000000, cp)}, 357 }), 358 }, 359 }, 360 parent: &state.BlockNode{ 361 Version: 1, 362 Height: 0, 363 Timestamp: 1523352600, 364 Hash: bc.Hash{V0: 0}, 365 Seed: &bc.Hash{V1: 1}, 366 Bits: 2305843009214532812, 367 }, 368 err: ErrWrongCoinbaseTransaction, 369 }, 370 } 371 372 for i, c := range cases { 373 err := ValidateBlock(c.block, c.parent) 374 if rootErr(err) != c.err { 375 t.Errorf("case #%d (%s) got error %s, want %s", i, c.desc, err, c.err) 376 } 377 } 378 } 379 380 // TestGasOverBlockLimit check if the gas of the block has the max limit (blocktest#1012) 381 func TestGasOverBlockLimit(t *testing.T) { 382 iniTtensority() 383 384 cp, _ := vmutil.DefaultCoinbaseProgram() 385 parent := &state.BlockNode{ 386 Version: 1, 387 Height: 0, 388 Timestamp: 1523352600, 389 Hash: bc.Hash{V0: 0}, 390 Seed: &bc.Hash{V1: 1}, 391 Bits: 2305843009214532812, 392 } 393 block := &bc.Block{ 394 ID: bc.Hash{V0: 1}, 395 BlockHeader: &bc.BlockHeader{ 396 Version: 1, 397 Height: 1, 398 Timestamp: 1523352601, 399 PreviousBlockId: &bc.Hash{V0: 0}, 400 Bits: 2305843009214532812, 401 TransactionsRoot: &bc.Hash{V0: 1}, 402 }, 403 Transactions: []*bc.Tx{ 404 types.MapTx(&types.TxData{ 405 Version: 1, 406 SerializedSize: 1, 407 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)}, 408 Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41250000000, cp)}, 409 }), 410 }, 411 } 412 413 for i := 0; i < 100; i++ { 414 block.Transactions = append(block.Transactions, types.MapTx(&types.TxData{ 415 Version: 1, 416 SerializedSize: 100000, 417 Inputs: []*types.TxInput{ 418 types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 10000000000, 0, cp), 419 }, 420 Outputs: []*types.TxOutput{ 421 types.NewTxOutput(*consensus.BTMAssetID, 9000000000, cp), 422 }, 423 })) 424 } 425 426 if err := ValidateBlock(block, parent); err != errOverBlockLimit { 427 t.Errorf("got error %s, want %s", err, errOverBlockLimit) 428 } 429 } 430 431 // TestSetTransactionStatus verify the transaction status is set correctly (blocktest#1010) 432 func TestSetTransactionStatus(t *testing.T) { 433 iniTtensority() 434 435 cp, _ := vmutil.DefaultCoinbaseProgram() 436 parent := &state.BlockNode{ 437 Version: 1, 438 Height: 0, 439 Timestamp: 1523352600, 440 Hash: bc.Hash{V0: 0}, 441 Seed: &bc.Hash{V1: 1}, 442 Bits: 2305843009214532812, 443 } 444 block := &bc.Block{ 445 ID: bc.Hash{V0: 1}, 446 BlockHeader: &bc.BlockHeader{ 447 Version: 1, 448 Height: 1, 449 Timestamp: 1523352601, 450 PreviousBlockId: &bc.Hash{V0: 0}, 451 Bits: 2305843009214532812, 452 TransactionsRoot: &bc.Hash{V0: 3413931728524254295, V1: 300490676707850231, V2: 1886132055969225110, V3: 10216139531293906088}, 453 TransactionStatusHash: &bc.Hash{V0: 8682965660674182538, V1: 8424137560837623409, V2: 6979974817894224946, V3: 4673809519342015041}, 454 }, 455 Transactions: []*bc.Tx{ 456 types.MapTx(&types.TxData{ 457 Version: 1, 458 SerializedSize: 1, 459 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)}, 460 Outputs: []*types.TxOutput{types.NewTxOutput(*consensus.BTMAssetID, 41449998224, cp)}, 461 }), 462 types.MapTx(&types.TxData{ 463 Version: 1, 464 SerializedSize: 1, 465 Inputs: []*types.TxInput{ 466 types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp), 467 types.NewSpendInput([][]byte{}, *newHash(8), bc.AssetID{V0: 1}, 1000, 0, []byte{byte(vm.OP_FALSE)}), 468 }, 469 Outputs: []*types.TxOutput{ 470 types.NewTxOutput(*consensus.BTMAssetID, 888, cp), 471 types.NewTxOutput(bc.AssetID{V0: 1}, 1000, cp), 472 }, 473 }), 474 types.MapTx(&types.TxData{ 475 Version: 1, 476 SerializedSize: 1, 477 Inputs: []*types.TxInput{ 478 types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp), 479 }, 480 Outputs: []*types.TxOutput{ 481 types.NewTxOutput(*consensus.BTMAssetID, 888, cp), 482 }, 483 }), 484 }, 485 } 486 487 if err := ValidateBlock(block, parent); err != nil { 488 t.Fatal(err) 489 } 490 491 expectTxStatuses := []bool{false, true, false} 492 txStatuses := block.GetTransactionStatus().VerifyStatus 493 if len(expectTxStatuses) != len(txStatuses) { 494 t.Error("the size of expect tx status is not equals to size of got tx status") 495 } 496 497 for i, status := range txStatuses { 498 if expectTxStatuses[i] != status.StatusFail { 499 t.Errorf("got tx status: %v, expect tx status: %v\n", status.StatusFail, expectTxStatuses[i]) 500 } 501 } 502 } 503 504 func iniTtensority() { 505 // add (hash, seed) --> (tensority hash) to the tensority cache for avoid 506 // real matrix calculate cost. 507 tensority.AIHash.AddCache(&bc.Hash{V0: 0}, &bc.Hash{}, testutil.MaxHash) 508 tensority.AIHash.AddCache(&bc.Hash{V0: 1}, &bc.Hash{}, testutil.MinHash) 509 tensority.AIHash.AddCache(&bc.Hash{V0: 1}, consensus.InitialSeed, testutil.MinHash) 510 }