OSDN Git Service

fix the bug (#372)
[bytom/vapor.git] / protocol / state / consensus_result_test.go
1 package state
2
3 import (
4         "encoding/hex"
5         "testing"
6
7         "github.com/vapor/consensus"
8         "github.com/vapor/errors"
9         "github.com/vapor/math/checked"
10         "github.com/vapor/protocol/bc"
11         "github.com/vapor/protocol/bc/types"
12         "github.com/vapor/testutil"
13 )
14
15 func TestCalCoinbaseReward(t *testing.T) {
16         cases := []struct {
17                 desc       string
18                 block      *types.Block
19                 wantReward *CoinbaseReward
20                 wantErr    error
21         }{
22                 {
23                         desc: "normal test with block contain coinbase tx and other tx",
24                         block: &types.Block{
25                                 BlockHeader: types.BlockHeader{
26                                         Height: 1,
27                                 },
28                                 Transactions: []*types.Tx{
29                                         &types.Tx{
30                                                 TxData: types.TxData{
31                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
32                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
33                                                 },
34                                         },
35                                         &types.Tx{
36                                                 TxData: types.TxData{
37                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)},
38                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
39                                                 },
40                                         },
41                                 },
42                         },
43                         wantReward: &CoinbaseReward{
44                                 Amount:         consensus.BlockSubsidy(1) + 50000000,
45                                 ControlProgram: []byte{0x51},
46                         },
47                 },
48                 {
49                         desc: "normal test with block only contain coinbase tx",
50                         block: &types.Block{
51                                 BlockHeader: types.BlockHeader{
52                                         Height: 1200,
53                                 },
54                                 Transactions: []*types.Tx{
55                                         &types.Tx{
56                                                 TxData: types.TxData{
57                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
58                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 1000000000, []byte{0x51})},
59                                                 },
60                                         },
61                                 },
62                         },
63                         wantReward: &CoinbaseReward{
64                                 Amount:         consensus.BlockSubsidy(1),
65                                 ControlProgram: []byte{0x51},
66                         },
67                 },
68                 {
69                         desc: "abnormal test with block not contain coinbase tx",
70                         block: &types.Block{
71                                 BlockHeader: types.BlockHeader{
72                                         Height: 1,
73                                 },
74                                 Transactions: []*types.Tx{},
75                         },
76                         wantErr: errors.New("not found coinbase receiver"),
77                 },
78         }
79
80         for i, c := range cases {
81                 coinbaseReward, err := CalCoinbaseReward(c.block)
82                 if err != nil {
83                         if err.Error() != c.wantErr.Error() {
84                                 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
85                         }
86                         continue
87                 }
88
89                 if !testutil.DeepEqual(coinbaseReward, c.wantReward) {
90                         t.Errorf("test case #%d, want %v, got %v", i, c.wantReward, coinbaseReward)
91                 }
92         }
93 }
94
95 func TestConsensusApplyBlock(t *testing.T) {
96         testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
97         cases := []struct {
98                 desc            string
99                 block           *types.Block
100                 consensusResult *ConsensusResult
101                 wantResult      *ConsensusResult
102                 wantErr         error
103         }{
104                 {
105                         desc: "normal test with block height is equal to 1",
106                         block: &types.Block{
107                                 BlockHeader: types.BlockHeader{
108                                         Height:            1,
109                                         PreviousBlockHash: bc.Hash{V0: 1},
110                                 },
111                                 Transactions: []*types.Tx{
112                                         &types.Tx{
113                                                 TxData: types.TxData{
114                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
115                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
116                                                 },
117                                         },
118                                         &types.Tx{
119                                                 TxData: types.TxData{
120                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)},
121                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
122                                                 },
123                                         },
124                                 },
125                         },
126                         consensusResult: &ConsensusResult{
127                                 Seq:            0,
128                                 NumOfVote:      map[string]uint64{},
129                                 CoinbaseReward: map[string]uint64{},
130                                 BlockHash:      bc.Hash{V0: 1},
131                                 BlockHeight:    0,
132                         },
133                         wantResult: &ConsensusResult{
134                                 Seq:       1,
135                                 NumOfVote: map[string]uint64{},
136                                 CoinbaseReward: map[string]uint64{
137                                         "51": consensus.BlockSubsidy(1) + 50000000,
138                                 },
139                                 BlockHash:   testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
140                                 BlockHeight: 1,
141                         },
142                 },
143                 {
144                         desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
145                         block: &types.Block{
146                                 BlockHeader: types.BlockHeader{
147                                         Height:            consensus.MainNetParams.RoundVoteBlockNums - 1,
148                                         PreviousBlockHash: bc.Hash{V0: 1},
149                                 },
150                                 Transactions: []*types.Tx{
151                                         &types.Tx{
152                                                 TxData: types.TxData{
153                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
154                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
155                                                 },
156                                         },
157                                         &types.Tx{
158                                                 TxData: types.TxData{
159                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
160                                                         Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
161                                                 },
162                                         },
163                                 },
164                         },
165                         consensusResult: &ConsensusResult{
166                                 NumOfVote:      map[string]uint64{},
167                                 CoinbaseReward: map[string]uint64{},
168                                 BlockHash:      bc.Hash{V0: 1},
169                                 BlockHeight:    consensus.MainNetParams.RoundVoteBlockNums - 2,
170                         },
171                         wantResult: &ConsensusResult{
172                                 Seq: 1,
173                                 NumOfVote: map[string]uint64{
174                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
175                                 },
176                                 CoinbaseReward: map[string]uint64{
177                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
178                                 },
179                                 BlockHash:   testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
180                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
181                         },
182                 },
183                 {
184                         desc: "normal test with block height is equal to RoundVoteBlockNums",
185                         block: &types.Block{
186                                 BlockHeader: types.BlockHeader{
187                                         Height:            consensus.MainNetParams.RoundVoteBlockNums,
188                                         PreviousBlockHash: bc.Hash{V0: 1},
189                                 },
190                                 Transactions: []*types.Tx{
191                                         &types.Tx{
192                                                 TxData: types.TxData{
193                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
194                                                         Outputs: []*types.TxOutput{
195                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
196                                                         },
197                                                 },
198                                         },
199                                         &types.Tx{
200                                                 TxData: types.TxData{
201                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
202                                                         Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
203                                                 },
204                                         },
205                                         &types.Tx{
206                                                 TxData: types.TxData{
207                                                         Inputs:  []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, []byte{0x51}, testXpub)},
208                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte{0x51})},
209                                                 },
210                                         },
211                                 },
212                         },
213                         consensusResult: &ConsensusResult{
214                                 NumOfVote: map[string]uint64{},
215                                 CoinbaseReward: map[string]uint64{
216                                         "51": 10000000,
217                                         "52": 20000000,
218                                         "53": 30000000,
219                                 },
220                                 BlockHash:   bc.Hash{V0: 1},
221                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
222                         },
223                         wantResult: &ConsensusResult{
224                                 Seq: 1,
225                                 NumOfVote: map[string]uint64{
226                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
227                                 },
228                                 CoinbaseReward: map[string]uint64{
229                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
230                                         "52": 20000000,
231                                         "53": 30000000,
232                                 },
233                                 BlockHash:   testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
234                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
235                         },
236                 },
237                 {
238                         desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
239                         block: &types.Block{
240                                 BlockHeader: types.BlockHeader{
241                                         Height:            consensus.MainNetParams.RoundVoteBlockNums + 1,
242                                         PreviousBlockHash: bc.Hash{V0: 1},
243                                 },
244                                 Transactions: []*types.Tx{
245                                         &types.Tx{
246                                                 TxData: types.TxData{
247                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
248                                                         Outputs: []*types.TxOutput{
249                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
250                                                                 types.NewIntraChainOutput(bc.AssetID{}, consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums)+10000000, []byte{0x51}),
251                                                                 types.NewIntraChainOutput(bc.AssetID{}, 20000000, []byte{0x53}),
252                                                                 types.NewIntraChainOutput(bc.AssetID{}, 30000000, []byte{0x52}),
253                                                         },
254                                                 },
255                                         },
256                                 },
257                         },
258                         consensusResult: &ConsensusResult{
259                                 NumOfVote: map[string]uint64{},
260                                 CoinbaseReward: map[string]uint64{
261                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
262                                         "52": 20000000,
263                                         "53": 30000000,
264                                 },
265                                 BlockHash:   bc.Hash{V0: 1},
266                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
267                         },
268                         wantResult: &ConsensusResult{
269                                 Seq:       2,
270                                 NumOfVote: map[string]uint64{},
271                                 CoinbaseReward: map[string]uint64{
272                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
273                                 },
274                                 BlockHash:   testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
275                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
276                         },
277                 },
278                 {
279                         desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
280                         block: &types.Block{
281                                 BlockHeader: types.BlockHeader{
282                                         Height:            consensus.MainNetParams.RoundVoteBlockNums + 2,
283                                         PreviousBlockHash: bc.Hash{V0: 1},
284                                 },
285                                 Transactions: []*types.Tx{
286                                         &types.Tx{
287                                                 TxData: types.TxData{
288                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
289                                                         Outputs: []*types.TxOutput{
290                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
291                                                         },
292                                                 },
293                                         },
294                                 },
295                         },
296                         consensusResult: &ConsensusResult{
297                                 NumOfVote: map[string]uint64{},
298                                 CoinbaseReward: map[string]uint64{
299                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
300                                 },
301                                 BlockHash:   bc.Hash{V0: 1},
302                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
303                         },
304                         wantResult: &ConsensusResult{
305                                 Seq:       2,
306                                 NumOfVote: map[string]uint64{},
307                                 CoinbaseReward: map[string]uint64{
308                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+2),
309                                 },
310                                 BlockHash:   testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
311                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 2,
312                         },
313                 },
314                 {
315                         desc: "abnormal test with block parent hash is not equals last block hash of vote result",
316                         block: &types.Block{
317                                 BlockHeader: types.BlockHeader{
318                                         Height:            1,
319                                         PreviousBlockHash: bc.Hash{V0: 0},
320                                 },
321                                 Transactions: []*types.Tx{},
322                         },
323                         consensusResult: &ConsensusResult{
324                                 NumOfVote:      map[string]uint64{},
325                                 CoinbaseReward: map[string]uint64{},
326                                 BlockHash:      bc.Hash{V0: 1},
327                                 BlockHeight:    2,
328                         },
329                         wantErr: errors.New("block parent hash is not equals last block hash of vote result"),
330                 },
331                 {
332                         desc: "abnormal test with arithmetic overflow for calculate transaction fee",
333                         block: &types.Block{
334                                 BlockHeader: types.BlockHeader{
335                                         Height:            1,
336                                         PreviousBlockHash: bc.Hash{V0: 1},
337                                 },
338                                 Transactions: []*types.Tx{
339                                         &types.Tx{
340                                                 TxData: types.TxData{
341                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
342                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
343                                                 },
344                                         },
345                                         &types.Tx{
346                                                 TxData: types.TxData{
347                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, nil)},
348                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 200000000, []byte{0x51})},
349                                                 },
350                                         },
351                                 },
352                         },
353                         consensusResult: &ConsensusResult{
354                                 NumOfVote:      map[string]uint64{},
355                                 CoinbaseReward: map[string]uint64{},
356                                 BlockHash:      bc.Hash{V0: 1},
357                                 BlockHeight:    2,
358                         },
359                         wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
360                 },
361                 {
362                         desc: "abnormal test with not found coinbase receiver",
363                         block: &types.Block{
364                                 BlockHeader: types.BlockHeader{
365                                         Height:            1,
366                                         PreviousBlockHash: bc.Hash{V0: 1},
367                                 },
368                                 Transactions: []*types.Tx{},
369                         },
370                         consensusResult: &ConsensusResult{
371                                 NumOfVote:      map[string]uint64{},
372                                 CoinbaseReward: map[string]uint64{},
373                                 BlockHash:      bc.Hash{V0: 1},
374                                 BlockHeight:    2,
375                         },
376                         wantErr: errors.New("not found coinbase receiver"),
377                 },
378         }
379
380         for i, c := range cases {
381                 if err := c.consensusResult.ApplyBlock(c.block); err != nil {
382                         if err.Error() != c.wantErr.Error() {
383                                 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
384                         }
385                         continue
386                 }
387
388                 if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
389                         t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
390                 }
391         }
392 }
393
394 func TestConsensusDetachBlock(t *testing.T) {
395         testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
396         cases := []struct {
397                 desc            string
398                 block           *types.Block
399                 consensusResult *ConsensusResult
400                 wantResult      *ConsensusResult
401                 wantErr         error
402         }{
403                 {
404                         desc: "normal test with block height is equal to 1",
405                         block: &types.Block{
406                                 BlockHeader: types.BlockHeader{
407                                         Height:            1,
408                                         PreviousBlockHash: bc.Hash{V0: 1},
409                                 },
410                                 Transactions: []*types.Tx{
411                                         &types.Tx{
412                                                 TxData: types.TxData{
413                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
414                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
415                                                 },
416                                         },
417                                         &types.Tx{
418                                                 TxData: types.TxData{
419                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)},
420                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
421                                                 },
422                                         },
423                                 },
424                         },
425                         consensusResult: &ConsensusResult{
426                                 Seq:       1,
427                                 NumOfVote: map[string]uint64{},
428                                 CoinbaseReward: map[string]uint64{
429                                         "51": consensus.BlockSubsidy(1) + 50000000,
430                                 },
431                                 BlockHash:   testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
432                                 BlockHeight: 1,
433                         },
434                         wantResult: &ConsensusResult{
435                                 Seq:            0,
436                                 NumOfVote:      map[string]uint64{},
437                                 CoinbaseReward: map[string]uint64{},
438                                 BlockHash:      bc.Hash{V0: 1},
439                                 BlockHeight:    0,
440                         },
441                 },
442                 {
443                         desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
444                         block: &types.Block{
445                                 BlockHeader: types.BlockHeader{
446                                         Height:            consensus.MainNetParams.RoundVoteBlockNums - 1,
447                                         PreviousBlockHash: bc.Hash{V0: 1},
448                                 },
449                                 Transactions: []*types.Tx{
450                                         &types.Tx{
451                                                 TxData: types.TxData{
452                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
453                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
454                                                 },
455                                         },
456                                         &types.Tx{
457                                                 TxData: types.TxData{
458                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
459                                                         Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
460                                                 },
461                                         },
462                                 },
463                         },
464                         consensusResult: &ConsensusResult{
465                                 NumOfVote: map[string]uint64{
466                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
467                                 },
468                                 CoinbaseReward: map[string]uint64{
469                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
470                                 },
471                                 BlockHash:   testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
472                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
473                         },
474                         wantResult: &ConsensusResult{
475                                 Seq:            1,
476                                 NumOfVote:      map[string]uint64{},
477                                 CoinbaseReward: map[string]uint64{},
478                                 BlockHash:      bc.Hash{V0: 1},
479                                 BlockHeight:    consensus.MainNetParams.RoundVoteBlockNums - 2,
480                         },
481                 },
482                 {
483                         desc: "normal test with block height is equal to RoundVoteBlockNums",
484                         block: &types.Block{
485                                 BlockHeader: types.BlockHeader{
486                                         Height:            consensus.MainNetParams.RoundVoteBlockNums,
487                                         PreviousBlockHash: bc.Hash{V0: 1},
488                                 },
489                                 Transactions: []*types.Tx{
490                                         &types.Tx{
491                                                 TxData: types.TxData{
492                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
493                                                         Outputs: []*types.TxOutput{
494                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
495                                                         },
496                                                 },
497                                         },
498                                 },
499                         },
500                         consensusResult: &ConsensusResult{
501                                 NumOfVote: map[string]uint64{
502                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
503                                 },
504                                 CoinbaseReward: map[string]uint64{
505                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 100000000,
506                                 },
507                                 BlockHash:   testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
508                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
509                         },
510                         wantResult: &ConsensusResult{
511                                 Seq: 1,
512                                 NumOfVote: map[string]uint64{
513                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
514                                 },
515                                 CoinbaseReward: map[string]uint64{
516                                         "51": 100000000,
517                                 },
518                                 BlockHash:   bc.Hash{V0: 1},
519                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
520                         },
521                 },
522                 {
523                         desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
524                         block: &types.Block{
525                                 BlockHeader: types.BlockHeader{
526                                         Height:            consensus.MainNetParams.RoundVoteBlockNums + 1,
527                                         PreviousBlockHash: bc.Hash{V0: 1},
528                                 },
529                                 Transactions: []*types.Tx{
530                                         &types.Tx{
531                                                 TxData: types.TxData{
532                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
533                                                         Outputs: []*types.TxOutput{
534                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
535                                                                 types.NewIntraChainOutput(bc.AssetID{}, consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums)+10000000, []byte{0x51}),
536                                                                 types.NewIntraChainOutput(bc.AssetID{}, 20000000, []byte{0x52}),
537                                                         },
538                                                 },
539                                         },
540                                 },
541                         },
542                         consensusResult: &ConsensusResult{
543                                 NumOfVote: map[string]uint64{},
544                                 CoinbaseReward: map[string]uint64{
545                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
546                                 },
547                                 BlockHash:   testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
548                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
549                         },
550                         wantResult: &ConsensusResult{
551                                 Seq:       1,
552                                 NumOfVote: map[string]uint64{},
553                                 CoinbaseReward: map[string]uint64{
554                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
555                                         "52": 20000000,
556                                 },
557                                 BlockHash:   bc.Hash{V0: 1},
558                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
559                         },
560                 },
561                 {
562                         desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
563                         block: &types.Block{
564                                 BlockHeader: types.BlockHeader{
565                                         Height:            consensus.MainNetParams.RoundVoteBlockNums + 2,
566                                         PreviousBlockHash: bc.Hash{V0: 1},
567                                 },
568                                 Transactions: []*types.Tx{
569                                         &types.Tx{
570                                                 TxData: types.TxData{
571                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
572                                                         Outputs: []*types.TxOutput{
573                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
574                                                         },
575                                                 },
576                                         },
577                                 },
578                         },
579                         consensusResult: &ConsensusResult{
580                                 NumOfVote: map[string]uint64{},
581                                 CoinbaseReward: map[string]uint64{
582                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + 1000000,
583                                 },
584                                 BlockHash:   testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
585                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
586                         },
587                         wantResult: &ConsensusResult{
588                                 Seq:       2,
589                                 NumOfVote: map[string]uint64{},
590                                 CoinbaseReward: map[string]uint64{
591                                         "51": 1000000,
592                                 },
593                                 BlockHash:   bc.Hash{V0: 1},
594                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
595                         },
596                 },
597                 {
598                         desc: "abnormal test with block hash is not equals last block hash of vote result",
599                         block: &types.Block{
600                                 BlockHeader: types.BlockHeader{
601                                         Height:            2,
602                                         PreviousBlockHash: bc.Hash{V0: 0},
603                                 },
604                                 Transactions: []*types.Tx{},
605                         },
606                         consensusResult: &ConsensusResult{
607                                 NumOfVote:      map[string]uint64{},
608                                 CoinbaseReward: map[string]uint64{},
609                                 BlockHash:      bc.Hash{V0: 1},
610                                 BlockHeight:    1,
611                         },
612                         wantErr: errors.New("block hash is not equals last block hash of vote result"),
613                 },
614                 {
615                         desc: "abnormal test with arithmetic overflow for calculate transaction fee",
616                         block: &types.Block{
617                                 BlockHeader: types.BlockHeader{
618                                         Height:            2,
619                                         PreviousBlockHash: bc.Hash{V0: 1},
620                                 },
621                                 Transactions: []*types.Tx{
622                                         &types.Tx{
623                                                 TxData: types.TxData{
624                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
625                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
626                                                 },
627                                         },
628                                         &types.Tx{
629                                                 TxData: types.TxData{
630                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, nil)},
631                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 200000000, []byte{0x51})},
632                                                 },
633                                         },
634                                 },
635                         },
636                         consensusResult: &ConsensusResult{
637                                 NumOfVote:      map[string]uint64{},
638                                 CoinbaseReward: map[string]uint64{},
639                                 BlockHash:      testutil.MustDecodeHash("02b7fb48defc4f4a3e1ef8403f7c0be78c4414ee66aa81fd702caa1e41a906df"),
640                                 BlockHeight:    1,
641                         },
642                         wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
643                 },
644                 {
645                         desc: "abnormal test with not found coinbase receiver",
646                         block: &types.Block{
647                                 BlockHeader: types.BlockHeader{
648                                         Height:            1,
649                                         PreviousBlockHash: bc.Hash{V0: 1},
650                                 },
651                                 Transactions: []*types.Tx{},
652                         },
653                         consensusResult: &ConsensusResult{
654                                 NumOfVote:      map[string]uint64{},
655                                 CoinbaseReward: map[string]uint64{},
656                                 BlockHash:      testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
657                                 BlockHeight:    1,
658                         },
659                         wantErr: errors.New("not found coinbase receiver"),
660                 },
661         }
662
663         for i, c := range cases {
664                 if err := c.consensusResult.DetachBlock(c.block); err != nil {
665                         if err.Error() != c.wantErr.Error() {
666                                 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
667                         }
668                         continue
669                 }
670
671                 if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
672                         t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
673                 }
674         }
675 }
676
677 func TestGetCoinbaseRewards(t *testing.T) {
678         cases := []struct {
679                 desc            string
680                 blockHeight     uint64
681                 consensusResult *ConsensusResult
682                 wantRewards     []CoinbaseReward
683         }{
684                 {
685                         desc:        "the block height is RoundVoteBlockNums - 1",
686                         blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums - 1,
687                         consensusResult: &ConsensusResult{
688                                 CoinbaseReward: map[string]uint64{
689                                         "51": 10,
690                                 },
691                         },
692                         wantRewards: []CoinbaseReward{},
693                 },
694                 {
695                         desc:        "the block height is RoundVoteBlockNums",
696                         blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums,
697                         consensusResult: &ConsensusResult{
698                                 CoinbaseReward: map[string]uint64{
699                                         "51": 10,
700                                         "52": 20,
701                                 },
702                         },
703                         wantRewards: []CoinbaseReward{
704                                 CoinbaseReward{
705                                         Amount:         20,
706                                         ControlProgram: []byte{0x52},
707                                 },
708                                 CoinbaseReward{
709                                         Amount:         10,
710                                         ControlProgram: []byte{0x51},
711                                 },
712                         },
713                 },
714                 {
715                         desc:        "the block height is RoundVoteBlockNums + 1",
716                         blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums + 1,
717                         consensusResult: &ConsensusResult{
718                                 CoinbaseReward: map[string]uint64{
719                                         "51": 10,
720                                 },
721                         },
722                         wantRewards: []CoinbaseReward{},
723                 },
724                 {
725                         desc:        "the block height is RoundVoteBlockNums * 2",
726                         blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums * 2,
727                         consensusResult: &ConsensusResult{
728                                 CoinbaseReward: map[string]uint64{
729                                         "50": 20,
730                                         "51": 10,
731                                         "52": 20,
732                                         "53": 30,
733                                 },
734                         },
735                         wantRewards: []CoinbaseReward{
736                                 CoinbaseReward{
737                                         Amount:         30,
738                                         ControlProgram: []byte{0x53},
739                                 },
740                                 CoinbaseReward{
741                                         Amount:         20,
742                                         ControlProgram: []byte{0x52},
743                                 },
744                                 CoinbaseReward{
745                                         Amount:         20,
746                                         ControlProgram: []byte{0x50},
747                                 },
748                                 CoinbaseReward{
749                                         Amount:         10,
750                                         ControlProgram: []byte{0x51},
751                                 },
752                         },
753                 },
754                 {
755                         desc:        "the block height is 2*RoundVoteBlockNums + 1",
756                         blockHeight: 2*consensus.ActiveNetParams.RoundVoteBlockNums + 1,
757                         consensusResult: &ConsensusResult{
758                                 CoinbaseReward: map[string]uint64{},
759                         },
760                         wantRewards: []CoinbaseReward{},
761                 },
762         }
763
764         for i, c := range cases {
765                 rewards, err := c.consensusResult.GetCoinbaseRewards(c.blockHeight)
766                 if err != nil {
767                         t.Fatal(err)
768                 }
769
770                 if !testutil.DeepEqual(rewards, c.wantRewards) {
771                         t.Errorf("test case #%d, want %v, got %v", i, c.wantRewards, rewards)
772                 }
773         }
774 }