OSDN Git Service

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