8 "github.com/vapor/consensus"
9 "github.com/vapor/protocol/bc"
10 "github.com/vapor/protocol/bc/types"
11 "github.com/vapor/protocol/state"
12 "github.com/vapor/protocol/vm"
13 "github.com/vapor/protocol/vm/vmutil"
14 "github.com/vapor/testutil"
17 func TestCheckBlockTime(t *testing.T) {
25 blockTime: 1520000500,
26 parentTime: []uint64{1520000000},
30 desc: "timestamp less than past median time",
31 blockTime: 1520005500,
32 parentTime: []uint64{1520000000, 1520000500, 1520001000, 1520001500, 1520002000, 1520002500, 1520003000, 1520003500, 1520004000, 1520004500, 1520005000},
36 desc: "timestamp greater than max limit",
37 blockTime: 99999999990000,
38 parentTime: []uint64{15200000000000},
42 desc: "timestamp of the block and the parent block are both greater than max limit",
43 blockTime: uint64(time.Now().UnixNano()/int64(time.Millisecond)) + consensus.ActiveNetParams.MaxTimeOffsetMs + 2000,
44 parentTime: []uint64{uint64(time.Now().UnixNano()/int64(time.Millisecond)) + consensus.ActiveNetParams.MaxTimeOffsetMs + 1000},
49 parent := &types.BlockHeader{Version: 1}
51 BlockHeader: &bc.BlockHeader{Version: 1},
54 for i, c := range cases {
55 parent.Timestamp = c.parentTime[0]
56 parentSuccessor := parent
57 for i := 1; i < len(c.parentTime); i++ {
58 Previous := &types.BlockHeader{Version: 1, Timestamp: c.parentTime[i]}
59 parentSuccessor.PreviousBlockHash = Previous.Hash()
60 parentSuccessor = Previous
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)
70 func TestCheckCoinbaseTx(t *testing.T) {
74 rewards []state.CoinbaseReward
78 desc: "zero coinbase amount",
80 types.NewTx(types.TxData{
81 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
82 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x51})},
85 rewards: []state.CoinbaseReward{},
89 desc: "zero coinbase amount and aggregate rewards",
91 types.NewTx(types.TxData{
92 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
93 Outputs: []*types.TxOutput{
94 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x51}),
95 types.NewIntraChainOutput(*consensus.BTMAssetID, 20000, []byte{0x51}),
96 types.NewIntraChainOutput(*consensus.BTMAssetID, 10000, []byte{0x52}),
100 rewards: []state.CoinbaseReward{
101 state.CoinbaseReward{
103 ControlProgram: []byte{0x51},
105 state.CoinbaseReward{
107 ControlProgram: []byte{0x52},
113 desc: "wrong coinbase transaction with block is empty",
115 rewards: []state.CoinbaseReward{},
116 err: ErrWrongCoinbaseTransaction,
119 desc: "wrong coinbase transaction with dismatch number of outputs",
121 types.NewTx(types.TxData{
122 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
123 Outputs: []*types.TxOutput{
124 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x51}),
125 types.NewIntraChainOutput(*consensus.BTMAssetID, 20000, []byte{0x51}),
126 types.NewIntraChainOutput(*consensus.BTMAssetID, 10000, []byte{0x52}),
130 rewards: []state.CoinbaseReward{
131 state.CoinbaseReward{
133 ControlProgram: []byte{0x51},
136 err: ErrWrongCoinbaseTransaction,
139 desc: "wrong coinbase transaction with dismatch output amount",
141 types.NewTx(types.TxData{
142 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
143 Outputs: []*types.TxOutput{
144 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x51}),
145 types.NewIntraChainOutput(*consensus.BTMAssetID, 20000, []byte{0x51}),
146 types.NewIntraChainOutput(*consensus.BTMAssetID, 10000, []byte{0x52}),
150 rewards: []state.CoinbaseReward{
151 state.CoinbaseReward{
153 ControlProgram: []byte{0x51},
155 state.CoinbaseReward{
157 ControlProgram: []byte{0x52},
160 err: ErrWrongCoinbaseTransaction,
163 desc: "wrong coinbase transaction with dismatch output control_program",
165 types.NewTx(types.TxData{
166 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
167 Outputs: []*types.TxOutput{
168 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x51}),
169 types.NewIntraChainOutput(*consensus.BTMAssetID, 20000, []byte{0x51}),
170 types.NewIntraChainOutput(*consensus.BTMAssetID, 10000, []byte{0x52}),
174 rewards: []state.CoinbaseReward{
175 state.CoinbaseReward{
177 ControlProgram: []byte{0x51},
179 state.CoinbaseReward{
181 ControlProgram: []byte{0x53},
184 err: ErrWrongCoinbaseTransaction,
188 block := new(types.Block)
189 for i, c := range cases {
190 block.Transactions = c.txs
191 if err := checkCoinbaseTx(types.MapBlock(block), c.rewards); rootErr(err) != c.err {
192 t.Errorf("case %d got error %s, want %T", i, err, c.err)
197 func TestValidateBlockHeader(t *testing.T) {
198 parent := &types.BlockHeader{
201 Timestamp: 1523352600000,
203 parentHash := parent.Hash()
208 parent *types.BlockHeader
212 desc: "dismatch version",
213 block: &bc.Block{BlockHeader: &bc.BlockHeader{
216 parent: &types.BlockHeader{
219 err: errVersionRegression,
222 desc: "misordered block height",
223 block: &bc.Block{BlockHeader: &bc.BlockHeader{
227 parent: &types.BlockHeader{
231 err: errMisorderedBlockHeight,
234 desc: "the prev block hash not equals to the hash of parent",
235 block: &bc.Block{BlockHeader: &bc.BlockHeader{
238 PreviousBlockId: &bc.Hash{V0: 20},
240 parent: &types.BlockHeader{
243 PreviousBlockHash: bc.Hash{V0: 19},
245 err: errMismatchedBlock,
248 desc: "normal block",
251 BlockHeader: &bc.BlockHeader{
254 Timestamp: 1523352601000,
255 PreviousBlockId: &parentHash,
262 desc: "version greater than 1",
265 BlockHeader: &bc.BlockHeader{
269 parent: &types.BlockHeader{
272 err: errVersionRegression,
275 desc: "version equals 0",
278 BlockHeader: &bc.BlockHeader{
282 parent: &types.BlockHeader{
285 err: errVersionRegression,
288 desc: "version equals max uint64",
291 BlockHeader: &bc.BlockHeader{
292 Version: math.MaxUint64,
295 parent: &types.BlockHeader{
298 err: errVersionRegression,
302 for i, c := range cases {
303 if err := ValidateBlockHeader(c.block, c.parent); rootErr(err) != c.err {
304 t.Errorf("case %d (%s) got error %s, want %s", i, c.desc, err, c.err)
309 func TestValidateBlock(t *testing.T) {
310 cp, _ := vmutil.DefaultCoinbaseProgram()
311 parent := &types.BlockHeader{
314 Timestamp: 1523352600000,
315 PreviousBlockHash: bc.Hash{V0: 0},
317 parentHash := parent.Hash()
318 txsRoot := testutil.MustDecodeHash("001e21b9618c503d909c1e0b32bab9ccf80c538b35d49ac7fffcef98eb373b23")
319 txStatusHash := testutil.MustDecodeHash("6978a65b4ee5b6f4914fe5c05000459a803ecf59132604e5d334d64249c5e50a")
322 types.MapTx(&types.TxData{
325 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
326 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
330 for i := 1; i <= 100; i++ {
331 txs = append(txs, types.MapTx(&types.TxData{
333 SerializedSize: 100000,
334 Inputs: []*types.TxInput{types.NewSpendInput([][]byte{}, bc.Hash{V0: uint64(i)}, *consensus.BTMAssetID, 10000000000, 0, cp)},
335 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, cp)},
342 parent *types.BlockHeader
343 rewards []state.CoinbaseReward
347 desc: "validate transactions with output amount great than input amount",
350 BlockHeader: &bc.BlockHeader{
353 Timestamp: 1523352601000,
354 PreviousBlockId: &parentHash,
355 TransactionsRoot: &bc.Hash{V0: 16229071813194843118, V1: 7413717724217377663, V2: 10255217553502780716, V3: 17975900656333257644},
356 TransactionStatusHash: &txStatusHash,
358 Transactions: []*bc.Tx{
359 types.MapTx(&types.TxData{
362 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
363 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
365 types.MapTx(&types.TxData{
368 Inputs: []*types.TxInput{types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp)},
369 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, cp)},
371 types.MapTx(&types.TxData{
374 Inputs: []*types.TxInput{types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp)},
375 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 200000000, cp)},
380 err: ErrGasCalculate,
383 desc: "validate block with the total transations used gas is over than the limit",
386 BlockHeader: &bc.BlockHeader{
389 Timestamp: 1523352601000,
390 PreviousBlockId: &parentHash,
391 TransactionsRoot: &bc.Hash{V0: 11799591616144015196, V1: 10485585098288308103, V2: 9819002243760462505, V3: 10203115105872271656},
392 TransactionStatusHash: &txStatusHash,
397 err: errOverBlockLimit,
400 desc: "The calculated transaction merkel root hash is not equals to the hash of the block header",
403 BlockHeader: &bc.BlockHeader{
406 Timestamp: 1523352601000,
407 PreviousBlockId: &parentHash,
408 TransactionsRoot: &bc.Hash{V0: 1},
410 Transactions: []*bc.Tx{
411 types.MapTx(&types.TxData{
414 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
415 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
420 err: errMismatchedMerkleRoot,
423 desc: "The calculated transaction status merkel root hash is not equals to the hash of the block header",
426 BlockHeader: &bc.BlockHeader{
429 Timestamp: 1523352601000,
430 PreviousBlockId: &parentHash,
431 TransactionsRoot: &bc.Hash{V0: 6294987741126419124, V1: 12520373106916389157, V2: 5040806596198303681, V3: 1151748423853876189},
432 TransactionStatusHash: &bc.Hash{V0: 1},
434 Transactions: []*bc.Tx{
435 types.MapTx(&types.TxData{
438 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
439 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
444 err: errMismatchedMerkleRoot,
447 desc: "the coinbase amount is not equal to the real coinbase outputs",
450 BlockHeader: &bc.BlockHeader{
453 Timestamp: 1523352601000,
454 PreviousBlockId: &parentHash,
455 TransactionsRoot: &txsRoot,
456 TransactionStatusHash: &txStatusHash,
458 Transactions: []*bc.Tx{
459 types.MapTx(&types.TxData{
462 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
463 Outputs: []*types.TxOutput{
464 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp),
465 types.NewIntraChainOutput(*consensus.BTMAssetID, 20000, []byte{0x51}),
471 rewards: []state.CoinbaseReward{
472 state.CoinbaseReward{
474 ControlProgram: []byte{0x51},
476 state.CoinbaseReward{
478 ControlProgram: []byte{0x52},
481 err: ErrWrongCoinbaseTransaction,
484 desc: "the coinbase program is not equal to the real coinbase outputs",
487 BlockHeader: &bc.BlockHeader{
490 Timestamp: 1523352601000,
491 PreviousBlockId: &parentHash,
492 TransactionsRoot: &txsRoot,
493 TransactionStatusHash: &txStatusHash,
495 Transactions: []*bc.Tx{
496 types.MapTx(&types.TxData{
499 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
500 Outputs: []*types.TxOutput{
501 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp),
502 types.NewIntraChainOutput(*consensus.BTMAssetID, 20000, []byte{0x51}),
503 types.NewIntraChainOutput(*consensus.BTMAssetID, 10000, []byte{0x61}),
509 rewards: []state.CoinbaseReward{
510 state.CoinbaseReward{
512 ControlProgram: []byte{0x51},
514 state.CoinbaseReward{
516 ControlProgram: []byte{0x52},
519 err: ErrWrongCoinbaseTransaction,
522 desc: "the coinbase amount is equal to the real coinbase amount",
525 BlockHeader: &bc.BlockHeader{
528 Timestamp: 1523352601000,
529 PreviousBlockId: &parentHash,
530 TransactionsRoot: &bc.Hash{V0: 16229071813194843118, V1: 7413717724217377663, V2: 10255217553502780716, V3: 17975900656333257644},
531 TransactionStatusHash: &txStatusHash,
533 Transactions: []*bc.Tx{
534 types.MapTx(&types.TxData{
537 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
538 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
540 types.MapTx(&types.TxData{
543 Inputs: []*types.TxInput{types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp)},
544 Outputs: []*types.TxOutput{
545 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp),
546 types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, cp),
556 for i, c := range cases {
557 err := ValidateBlock(c.block, c.parent, c.rewards)
558 if rootErr(err) != c.err {
559 t.Errorf("case #%d (%s) got error %s, want %s", i, c.desc, err, c.err)
564 // TestSetTransactionStatus verify the transaction status is set correctly (blocktest#1010)
565 func TestSetTransactionStatus(t *testing.T) {
566 cp, _ := vmutil.DefaultCoinbaseProgram()
567 parent := &types.BlockHeader{
570 Timestamp: 1523352600000,
571 PreviousBlockHash: bc.Hash{V0: 0},
573 parentHash := parent.Hash()
577 BlockHeader: &bc.BlockHeader{
580 Timestamp: 1523352601000,
581 PreviousBlockId: &parentHash,
582 TransactionsRoot: &bc.Hash{V0: 8176741810667217458, V1: 14830712230021600370, V2: 8921661778795432162, V3: 3391855546006364086},
583 TransactionStatusHash: &bc.Hash{V0: 8682965660674182538, V1: 8424137560837623409, V2: 6979974817894224946, V3: 4673809519342015041},
585 Transactions: []*bc.Tx{
586 types.MapTx(&types.TxData{
589 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
590 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
592 types.MapTx(&types.TxData{
595 Inputs: []*types.TxInput{
596 types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
597 types.NewSpendInput([][]byte{}, *newHash(8), bc.AssetID{V0: 1}, 1000, 0, []byte{byte(vm.OP_FALSE)}),
599 Outputs: []*types.TxOutput{
600 types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp),
601 types.NewIntraChainOutput(bc.AssetID{V0: 1}, 1000, cp),
604 types.MapTx(&types.TxData{
607 Inputs: []*types.TxInput{
608 types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
610 Outputs: []*types.TxOutput{
611 types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp),
617 if err := ValidateBlock(block, parent, []state.CoinbaseReward{}); err != nil {
621 expectTxStatuses := []bool{false, true, false}
622 txStatuses := block.GetTransactionStatus().VerifyStatus
623 if len(expectTxStatuses) != len(txStatuses) {
624 t.Error("the size of expect tx status is not equals to size of got tx status")
627 for i, status := range txStatuses {
628 if expectTxStatuses[i] != status.StatusFail {
629 t.Errorf("got tx status: %v, expect tx status: %v\n", status.StatusFail, expectTxStatuses[i])