OSDN Git Service

get BlockNode from database (#188)
[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/protocol/bc"
10         "github.com/vapor/protocol/bc/types"
11         "github.com/vapor/protocol/vm"
12         "github.com/vapor/protocol/vm/vmutil"
13 )
14
15 func TestCheckBlockTime(t *testing.T) {
16         cases := []struct {
17                 desc       string
18                 blockTime  uint64
19                 parentTime []uint64
20                 err        error
21         }{
22                 {
23                         blockTime:  1520000500,
24                         parentTime: []uint64{1520000000},
25                         err:        nil,
26                 },
27                 {
28                         desc:       "timestamp less than past median time (blocktest#1005)",
29                         blockTime:  1520005500,
30                         parentTime: []uint64{1520000000, 1520000500, 1520001000, 1520001500, 1520002000, 1520002500, 1520003000, 1520003500, 1520004000, 1520004500, 1520005000},
31                         err:        nil,
32                 },
33                 {
34                         desc:       "timestamp greater than max limit (blocktest#1006)",
35                         blockTime:  99999999990000,
36                         parentTime: []uint64{15200000000000},
37                         err:        errBadTimestamp,
38                 },
39                 {
40                         desc:       "timestamp of the block and the parent block are both greater than max limit (blocktest#1007)",
41                         blockTime:  uint64(time.Now().UnixNano()/int64(time.Millisecond)) + consensus.MaxTimeOffsetMs + 2000,
42                         parentTime: []uint64{uint64(time.Now().UnixNano()/int64(time.Millisecond)) + consensus.MaxTimeOffsetMs + 1000},
43                         err:        errBadTimestamp,
44                 },
45         }
46
47         parent := &types.BlockHeader{Version: 1}
48         block := &bc.Block{
49                 BlockHeader: &bc.BlockHeader{Version: 1},
50         }
51
52         for i, c := range cases {
53                 parent.Timestamp = c.parentTime[0]
54                 parentSuccessor := parent
55                 for i := 1; i < len(c.parentTime); i++ {
56                         Previous := &types.BlockHeader{Version: 1, Timestamp: c.parentTime[i]}
57                         parentSuccessor.PreviousBlockHash = Previous.Hash()
58                         parentSuccessor = Previous
59                 }
60
61                 block.Timestamp = c.blockTime
62                 if err := checkBlockTime(block, parent); rootErr(err) != c.err {
63                         t.Errorf("case %d got error %s, want %s", i, err, c.err)
64                 }
65         }
66 }
67
68 func TestCheckCoinbaseAmount(t *testing.T) {
69         cases := []struct {
70                 txs    []*types.Tx
71                 amount uint64
72                 err    error
73         }{
74                 {
75                         txs: []*types.Tx{
76                                 types.NewTx(types.TxData{
77                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput(nil)},
78                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 5000, nil)},
79                                 }),
80                         },
81                         amount: 5000,
82                         err:    nil,
83                 },
84                 {
85                         txs: []*types.Tx{
86                                 types.NewTx(types.TxData{
87                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput(nil)},
88                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 5000, nil)},
89                                 }),
90                         },
91                         amount: 6000,
92                         err:    ErrWrongCoinbaseTransaction,
93                 },
94                 {
95                         txs:    []*types.Tx{},
96                         amount: 5000,
97                         err:    ErrWrongCoinbaseTransaction,
98                 },
99         }
100
101         block := new(types.Block)
102         for i, c := range cases {
103                 block.Transactions = c.txs
104                 if err := checkCoinbaseAmount(types.MapBlock(block), c.amount); rootErr(err) != c.err {
105                         t.Errorf("case %d got error %s, want %s", i, err, c.err)
106                 }
107         }
108 }
109
110 func TestValidateBlockHeader(t *testing.T) {
111         parent := &types.BlockHeader{
112                 Version:   1,
113                 Height:    0,
114                 Timestamp: 1523352600000,
115         }
116         parentHash := parent.Hash()
117
118         cases := []struct {
119                 desc   string
120                 block  *bc.Block
121                 parent *types.BlockHeader
122                 err    error
123         }{
124                 {
125                         block: &bc.Block{BlockHeader: &bc.BlockHeader{
126                                 Version: 2,
127                         }},
128                         parent: &types.BlockHeader{
129                                 Version: 1,
130                         },
131                         err: errVersionRegression,
132                 },
133                 {
134                         block: &bc.Block{BlockHeader: &bc.BlockHeader{
135                                 Version: 1,
136                                 Height:  20,
137                         }},
138                         parent: &types.BlockHeader{
139                                 Version: 1,
140                                 Height:  18,
141                         },
142                         err: errMisorderedBlockHeight,
143                 },
144                 {
145                         desc: "the prev block hash not equals to the hash of parent (blocktest#1004)",
146                         block: &bc.Block{BlockHeader: &bc.BlockHeader{
147                                 Version:         1,
148                                 Height:          20,
149                                 PreviousBlockId: &bc.Hash{V0: 20},
150                         }},
151                         parent: &types.BlockHeader{
152                                 Version:           1,
153                                 Height:            19,
154                                 PreviousBlockHash: bc.Hash{V0: 19},
155                         },
156                         err: errMismatchedBlock,
157                 },
158                 {
159                         block: &bc.Block{
160                                 ID: bc.Hash{V0: 1},
161                                 BlockHeader: &bc.BlockHeader{
162                                         Version:         1,
163                                         Height:          1,
164                                         Timestamp:       1523352601000,
165                                         PreviousBlockId: &parentHash,
166                                 },
167                         },
168                         parent: parent,
169                         err:    nil,
170                 },
171                 {
172                         desc: "version greater than 1 (blocktest#1001)",
173                         block: &bc.Block{
174                                 ID: bc.Hash{V0: 1},
175                                 BlockHeader: &bc.BlockHeader{
176                                         Version: 2,
177                                 },
178                         },
179                         parent: &types.BlockHeader{
180                                 Version: 1,
181                         },
182                         err: errVersionRegression,
183                 },
184                 {
185                         desc: "version equals 0 (blocktest#1002)",
186                         block: &bc.Block{
187                                 ID: bc.Hash{V0: 1},
188                                 BlockHeader: &bc.BlockHeader{
189                                         Version: 0,
190                                 },
191                         },
192                         parent: &types.BlockHeader{
193                                 Version: 1,
194                         },
195                         err: errVersionRegression,
196                 },
197                 {
198                         desc: "version equals max uint64 (blocktest#1003)",
199                         block: &bc.Block{
200                                 ID: bc.Hash{V0: 1},
201                                 BlockHeader: &bc.BlockHeader{
202                                         Version: math.MaxUint64,
203                                 },
204                         },
205                         parent: &types.BlockHeader{
206                                 Version: 1,
207                         },
208                         err: errVersionRegression,
209                 },
210         }
211
212         for i, c := range cases {
213                 if err := ValidateBlockHeader(c.block, c.parent); rootErr(err) != c.err {
214                         t.Errorf("case %d (%s) got error %s, want %s", i, c.desc, err, c.err)
215                 }
216         }
217 }
218
219 // TestValidateBlock test the ValidateBlock function
220 func TestValidateBlock(t *testing.T) {
221         cp, _ := vmutil.DefaultCoinbaseProgram()
222         parent := &types.BlockHeader{
223                 Version:           1,
224                 Height:            0,
225                 Timestamp:         1523352600000,
226                 PreviousBlockHash: bc.Hash{V0: 0},
227         }
228         parentHash := parent.Hash()
229
230         cases := []struct {
231                 desc   string
232                 block  *bc.Block
233                 parent *types.BlockHeader
234                 err    error
235         }{
236                 {
237                         desc: "The calculated transaction merkel root hash is not equals to the hash of the block header (blocktest#1009)",
238                         block: &bc.Block{
239                                 ID: bc.Hash{V0: 1},
240                                 BlockHeader: &bc.BlockHeader{
241                                         Version:          1,
242                                         Height:           1,
243                                         Timestamp:        1523352601000,
244                                         PreviousBlockId:  &parentHash,
245                                         TransactionsRoot: &bc.Hash{V0: 1},
246                                 },
247                                 Transactions: []*bc.Tx{
248                                         types.MapTx(&types.TxData{
249                                                 Version:        1,
250                                                 SerializedSize: 1,
251                                                 Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
252                                                 Outputs:        []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, consensus.BlockSubsidy(0), cp)},
253                                         }),
254                                 },
255                         },
256                         parent: parent,
257                         err:    errMismatchedMerkleRoot,
258                 },
259                 {
260                         desc: "The calculated transaction status merkel root hash is not equals to the hash of the block header (blocktest#1009)",
261                         block: &bc.Block{
262                                 ID: bc.Hash{V0: 1},
263                                 BlockHeader: &bc.BlockHeader{
264                                         Version:               1,
265                                         Height:                1,
266                                         Timestamp:             1523352601000,
267                                         PreviousBlockId:       &parentHash,
268                                         TransactionsRoot:      &bc.Hash{V0: 6294987741126419124, V1: 12520373106916389157, V2: 5040806596198303681, V3: 1151748423853876189},
269                                         TransactionStatusHash: &bc.Hash{V0: 1},
270                                 },
271                                 Transactions: []*bc.Tx{
272                                         types.MapTx(&types.TxData{
273                                                 Version:        1,
274                                                 SerializedSize: 1,
275                                                 Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
276                                                 Outputs:        []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, consensus.BlockSubsidy(0), cp)},
277                                         }),
278                                 },
279                         },
280                         parent: parent,
281                         err:    errMismatchedMerkleRoot,
282                 },
283                 {
284                         desc: "the coinbase amount is less than the real coinbase amount (txtest#1014)",
285                         block: &bc.Block{
286                                 ID: bc.Hash{V0: 1},
287                                 BlockHeader: &bc.BlockHeader{
288                                         Version:         1,
289                                         Height:          1,
290                                         Timestamp:       1523352601000,
291                                         PreviousBlockId: &parentHash,
292                                 },
293                                 Transactions: []*bc.Tx{
294                                         types.MapTx(&types.TxData{
295                                                 Version:        1,
296                                                 SerializedSize: 1,
297                                                 Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
298                                                 Outputs:        []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 41250000000, cp)},
299                                         }),
300                                         types.MapTx(&types.TxData{
301                                                 Version:        1,
302                                                 SerializedSize: 1,
303                                                 Inputs:         []*types.TxInput{types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp)},
304                                                 Outputs:        []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 90000000, cp)},
305                                         }),
306                                 },
307                         },
308                         parent: parent,
309                         err:    ErrWrongCoinbaseTransaction,
310                 },
311         }
312
313         for i, c := range cases {
314                 err := ValidateBlock(c.block, c.parent)
315                 if rootErr(err) != c.err {
316                         t.Errorf("case #%d (%s) got error %s, want %s", i, c.desc, err, c.err)
317                 }
318         }
319 }
320
321 // TestGasOverBlockLimit check if the gas of the block has the max limit (blocktest#1012)
322 func TestGasOverBlockLimit(t *testing.T) {
323         cp, _ := vmutil.DefaultCoinbaseProgram()
324         parent := &types.BlockHeader{
325                 Version:           1,
326                 Height:            0,
327                 Timestamp:         1523352600000,
328                 PreviousBlockHash: bc.Hash{V0: 0},
329         }
330         parentHash := parent.Hash()
331
332         block := &bc.Block{
333                 ID: bc.Hash{V0: 1},
334                 BlockHeader: &bc.BlockHeader{
335                         Version:          1,
336                         Height:           1,
337                         Timestamp:        1523352601000,
338                         PreviousBlockId:  &parentHash,
339                         TransactionsRoot: &bc.Hash{V0: 1},
340                 },
341                 Transactions: []*bc.Tx{
342                         types.MapTx(&types.TxData{
343                                 Version:        1,
344                                 SerializedSize: 1,
345                                 Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
346                                 Outputs:        []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 41250000000, cp)},
347                         }),
348                 },
349         }
350
351         for i := 0; i < 100; i++ {
352                 block.Transactions = append(block.Transactions, types.MapTx(&types.TxData{
353                         Version:        1,
354                         SerializedSize: 100000,
355                         Inputs: []*types.TxInput{
356                                 types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 10000000000, 0, cp),
357                         },
358                         Outputs: []*types.TxOutput{
359                                 types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, cp),
360                         },
361                 }))
362         }
363
364         if err := ValidateBlock(block, parent); err != errOverBlockLimit {
365                 t.Errorf("got error %s, want %s", err, errOverBlockLimit)
366         }
367 }
368
369 // TestSetTransactionStatus verify the transaction status is set correctly (blocktest#1010)
370 func TestSetTransactionStatus(t *testing.T) {
371         cp, _ := vmutil.DefaultCoinbaseProgram()
372         parent := &types.BlockHeader{
373                 Version:           1,
374                 Height:            0,
375                 Timestamp:         1523352600000,
376                 PreviousBlockHash: bc.Hash{V0: 0},
377         }
378         parentHash := parent.Hash()
379
380         block := &bc.Block{
381                 ID: bc.Hash{V0: 1},
382                 BlockHeader: &bc.BlockHeader{
383                         Version:               1,
384                         Height:                1,
385                         Timestamp:             1523352601000,
386                         PreviousBlockId:       &parentHash,
387                         TransactionsRoot:      &bc.Hash{V0: 12212572290317752069, V1: 8979003395977198825, V2: 3978010681554327084, V3: 12322462500143540195},
388                         TransactionStatusHash: &bc.Hash{V0: 8682965660674182538, V1: 8424137560837623409, V2: 6979974817894224946, V3: 4673809519342015041},
389                 },
390                 Transactions: []*bc.Tx{
391                         types.MapTx(&types.TxData{
392                                 Version:        1,
393                                 SerializedSize: 1,
394                                 Inputs:         []*types.TxInput{types.NewCoinbaseInput(nil)},
395                                 Outputs:        []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 199998224, cp)},
396                         }),
397                         types.MapTx(&types.TxData{
398                                 Version:        1,
399                                 SerializedSize: 1,
400                                 Inputs: []*types.TxInput{
401                                         types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
402                                         types.NewSpendInput([][]byte{}, *newHash(8), bc.AssetID{V0: 1}, 1000, 0, []byte{byte(vm.OP_FALSE)}),
403                                 },
404                                 Outputs: []*types.TxOutput{
405                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp),
406                                         types.NewIntraChainOutput(bc.AssetID{V0: 1}, 1000, cp),
407                                 },
408                         }),
409                         types.MapTx(&types.TxData{
410                                 Version:        1,
411                                 SerializedSize: 1,
412                                 Inputs: []*types.TxInput{
413                                         types.NewSpendInput([][]byte{}, *newHash(8), *consensus.BTMAssetID, 100000000, 0, cp),
414                                 },
415                                 Outputs: []*types.TxOutput{
416                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 888, cp),
417                                 },
418                         }),
419                 },
420         }
421
422         if err := ValidateBlock(block, parent); err != nil {
423                 t.Fatal(err)
424         }
425
426         expectTxStatuses := []bool{false, true, false}
427         txStatuses := block.GetTransactionStatus().VerifyStatus
428         if len(expectTxStatuses) != len(txStatuses) {
429                 t.Error("the size of expect tx status is not equals to size of got tx status")
430         }
431
432         for i, status := range txStatuses {
433                 if expectTxStatuses[i] != status.StatusFail {
434                         t.Errorf("got tx status: %v, expect tx status: %v\n", status.StatusFail, expectTxStatuses[i])
435                 }
436         }
437 }