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, 5000, []byte{0x51}),
99 rewards: []state.CoinbaseReward{
100 state.CoinbaseReward{
102 ControlProgram: []byte{0x51},
108 desc: "wrong coinbase transaction",
110 rewards: []state.CoinbaseReward{},
111 err: ErrWrongCoinbaseTransaction,
115 block := new(types.Block)
116 for i, c := range cases {
117 block.Transactions = c.txs
118 if err := checkCoinbaseTx(types.MapBlock(block), c.rewards); rootErr(err) != c.err {
119 t.Errorf("case %d got error %s, want %T", i, err, c.err)
124 func TestValidateBlockHeader(t *testing.T) {
125 parent := &types.BlockHeader{
128 Timestamp: 1523352600000,
130 parentHash := parent.Hash()
135 parent *types.BlockHeader
139 desc: "dismatch version",
140 block: &bc.Block{BlockHeader: &bc.BlockHeader{
143 parent: &types.BlockHeader{
146 err: errVersionRegression,
149 desc: "misordered block height",
150 block: &bc.Block{BlockHeader: &bc.BlockHeader{
154 parent: &types.BlockHeader{
158 err: errMisorderedBlockHeight,
161 desc: "the prev block hash not equals to the hash of parent",
162 block: &bc.Block{BlockHeader: &bc.BlockHeader{
165 PreviousBlockId: &bc.Hash{V0: 20},
167 parent: &types.BlockHeader{
170 PreviousBlockHash: bc.Hash{V0: 19},
172 err: errMismatchedBlock,
175 desc: "normal block",
178 BlockHeader: &bc.BlockHeader{
181 Timestamp: 1523352601000,
182 PreviousBlockId: &parentHash,
189 desc: "version greater than 1",
192 BlockHeader: &bc.BlockHeader{
196 parent: &types.BlockHeader{
199 err: errVersionRegression,
202 desc: "version equals 0",
205 BlockHeader: &bc.BlockHeader{
209 parent: &types.BlockHeader{
212 err: errVersionRegression,
215 desc: "version equals max uint64",
218 BlockHeader: &bc.BlockHeader{
219 Version: math.MaxUint64,
222 parent: &types.BlockHeader{
225 err: errVersionRegression,
229 for i, c := range cases {
230 if err := ValidateBlockHeader(c.block, c.parent); rootErr(err) != c.err {
231 t.Errorf("case %d (%s) got error %s, want %s", i, c.desc, err, c.err)
236 func TestValidateBlock(t *testing.T) {
237 cp, _ := vmutil.DefaultCoinbaseProgram()
238 parent := &types.BlockHeader{
241 Timestamp: 1523352600000,
242 PreviousBlockHash: bc.Hash{V0: 0},
244 parentHash := parent.Hash()
245 txsRoot := testutil.MustDecodeHash("001e21b9618c503d909c1e0b32bab9ccf80c538b35d49ac7fffcef98eb373b23")
246 txStatusHash := testutil.MustDecodeHash("6978a65b4ee5b6f4914fe5c05000459a803ecf59132604e5d334d64249c5e50a")
251 parent *types.BlockHeader
252 rewards []state.CoinbaseReward
256 desc: "The calculated transaction merkel root hash is not equals to the hash of the block header",
259 BlockHeader: &bc.BlockHeader{
262 Timestamp: 1523352601000,
263 PreviousBlockId: &parentHash,
264 TransactionsRoot: &bc.Hash{V0: 1},
266 Transactions: []*bc.Tx{
267 types.MapTx(&types.TxData{
270 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
271 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
276 err: errMismatchedMerkleRoot,
279 desc: "The calculated transaction status merkel root hash is not equals to the hash of the block header",
282 BlockHeader: &bc.BlockHeader{
285 Timestamp: 1523352601000,
286 PreviousBlockId: &parentHash,
287 TransactionsRoot: &bc.Hash{V0: 6294987741126419124, V1: 12520373106916389157, V2: 5040806596198303681, V3: 1151748423853876189},
288 TransactionStatusHash: &bc.Hash{V0: 1},
290 Transactions: []*bc.Tx{
291 types.MapTx(&types.TxData{
294 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
295 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
300 err: errMismatchedMerkleRoot,
303 desc: "the coinbase amount is not equal to the real coinbase amount",
306 BlockHeader: &bc.BlockHeader{
309 Timestamp: 1523352601000,
310 PreviousBlockId: &parentHash,
311 TransactionsRoot: &txsRoot,
312 TransactionStatusHash: &txStatusHash,
314 Transactions: []*bc.Tx{
315 types.MapTx(&types.TxData{
318 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
319 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 41250000000, cp)},
321 types.MapTx(&types.TxData{
324 Inputs: []*types.TxInput{types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp)},
325 Outputs: []*types.TxOutput{
326 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp),
327 types.NewIntraChainOutput(*consensus.BTMAssetID, 90000000, cp),
333 rewards: []state.CoinbaseReward{},
334 err: ErrWrongCoinbaseTransaction,
337 desc: "the coinbase amount is less than the real coinbase amount",
340 BlockHeader: &bc.BlockHeader{
343 Timestamp: 1523352601000,
344 PreviousBlockId: &parentHash,
346 Transactions: []*bc.Tx{
347 types.MapTx(&types.TxData{
350 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
351 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
353 types.MapTx(&types.TxData{
356 Inputs: []*types.TxInput{types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp)},
357 Outputs: []*types.TxOutput{
358 types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp),
359 types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, cp),
365 err: vm.ErrRunLimitExceeded,
369 for i, c := range cases {
370 err := ValidateBlock(c.block, c.parent, c.rewards)
371 if rootErr(err) != c.err {
372 t.Errorf("case #%d (%s) got error %s, want %s", i, c.desc, err, c.err)
377 func TestGasOverBlockLimit(t *testing.T) {
378 cp, _ := vmutil.DefaultCoinbaseProgram()
379 parent := &types.BlockHeader{
382 Timestamp: 1523352600000,
383 PreviousBlockHash: bc.Hash{V0: 0},
385 parentHash := parent.Hash()
389 BlockHeader: &bc.BlockHeader{
392 Timestamp: 1523352601000,
393 PreviousBlockId: &parentHash,
395 Transactions: []*bc.Tx{
396 types.MapTx(&types.TxData{
399 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
400 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
405 for i := 0; i < 100; i++ {
406 block.Transactions = append(block.Transactions, types.MapTx(&types.TxData{
408 SerializedSize: 100000,
409 Inputs: []*types.TxInput{
410 types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 10000000000, 0, cp),
412 Outputs: []*types.TxOutput{
413 types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, cp),
418 if err := ValidateBlock(block, parent, []state.CoinbaseReward{}); err != errOverBlockLimit {
419 t.Errorf("got error %s, want %s", err, errOverBlockLimit)
423 // TestSetTransactionStatus verify the transaction status is set correctly (blocktest#1010)
424 func TestSetTransactionStatus(t *testing.T) {
425 cp, _ := vmutil.DefaultCoinbaseProgram()
426 parent := &types.BlockHeader{
429 Timestamp: 1523352600000,
430 PreviousBlockHash: bc.Hash{V0: 0},
432 parentHash := parent.Hash()
436 BlockHeader: &bc.BlockHeader{
439 Timestamp: 1523352601000,
440 PreviousBlockId: &parentHash,
441 TransactionsRoot: &bc.Hash{V0: 8176741810667217458, V1: 14830712230021600370, V2: 8921661778795432162, V3: 3391855546006364086},
442 TransactionStatusHash: &bc.Hash{V0: 8682965660674182538, V1: 8424137560837623409, V2: 6979974817894224946, V3: 4673809519342015041},
444 Transactions: []*bc.Tx{
445 types.MapTx(&types.TxData{
448 Inputs: []*types.TxInput{types.NewCoinbaseInput(nil)},
449 Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, cp)},
451 types.MapTx(&types.TxData{
454 Inputs: []*types.TxInput{
455 types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
456 types.NewSpendInput([][]byte{}, *newHash(8), bc.AssetID{V0: 1}, 1000, 0, []byte{byte(vm.OP_FALSE)}),
458 Outputs: []*types.TxOutput{
459 types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp),
460 types.NewIntraChainOutput(bc.AssetID{V0: 1}, 1000, cp),
463 types.MapTx(&types.TxData{
466 Inputs: []*types.TxInput{
467 types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
469 Outputs: []*types.TxOutput{
470 types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp),
476 if err := ValidateBlock(block, parent, []state.CoinbaseReward{}); err != nil {
480 expectTxStatuses := []bool{false, true, false}
481 txStatuses := block.GetTransactionStatus().VerifyStatus
482 if len(expectTxStatuses) != len(txStatuses) {
483 t.Error("the size of expect tx status is not equals to size of got tx status")
486 for i, status := range txStatuses {
487 if expectTxStatuses[i] != status.StatusFail {
488 t.Errorf("got tx status: %v, expect tx status: %v\n", status.StatusFail, expectTxStatuses[i])