OSDN Git Service

Hulk did something
[bytom/vapor.git] / protocol / validation / block_test.go
1 package validation
2
3 import (
4         "math"
5         "testing"
6         "time"
7
8         "github.com/vapor/consensus"
9         "github.com/vapor/mining/tensority"
10         "github.com/vapor/protocol/bc"
11         "github.com/vapor/protocol/bc/types"
12         "github.com/vapor/protocol/state"
13         "github.com/vapor/protocol/vm"
14         "github.com/vapor/protocol/vm/vmutil"
15         "github.com/vapor/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 }