OSDN Git Service

Add consensus result test case
[bytom/vapor.git] / protocol / state / consensus_result_test.go
1 package state
2
3 import (
4         "encoding/hex"
5         "math"
6         "reflect"
7         "testing"
8
9         "github.com/davecgh/go-spew/spew"
10
11         "github.com/vapor/consensus"
12         "github.com/vapor/crypto/ed25519/chainkd"
13         "github.com/vapor/errors"
14         "github.com/vapor/math/checked"
15         "github.com/vapor/protocol/bc"
16         "github.com/vapor/protocol/bc/types"
17         "github.com/vapor/testutil"
18 )
19
20 func TestApplyTransaction(t *testing.T) {
21         testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
22
23         cases := []struct {
24                 desc                string
25                 tx                  *types.Tx
26                 prevConsensusResult *ConsensusResult
27                 postConsensusResult *ConsensusResult
28                 wantErr             error
29         }{
30                 {
31                         desc: "test num Of vote overflow",
32                         tx: &types.Tx{
33                                 TxData: types.TxData{
34                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
35                                         Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, math.MaxUint64-1000, []byte{0x51}, testXpub)},
36                                 },
37                         },
38                         prevConsensusResult: &ConsensusResult{
39                                 NumOfVote: map[string]uint64{
40                                         hex.EncodeToString(testXpub): 1000000,
41                                 },
42                         },
43                         postConsensusResult: &ConsensusResult{
44                                 NumOfVote: map[string]uint64{},
45                         },
46                         wantErr: checked.ErrOverflow,
47                 },
48                 {
49                         desc: "test num Of veto overflow",
50                         tx: &types.Tx{
51                                 TxData: types.TxData{
52                                         Inputs:  []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, []byte{0x51}, testXpub)},
53                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte{0x51})},
54                                 },
55                         },
56                         prevConsensusResult: &ConsensusResult{
57                                 NumOfVote: map[string]uint64{
58                                         hex.EncodeToString(testXpub): 1000000,
59                                 },
60                         },
61                         postConsensusResult: &ConsensusResult{
62                                 NumOfVote: map[string]uint64{},
63                         },
64                         wantErr: checked.ErrOverflow,
65                 },
66                 {
67                         desc: "test del pubkey from NumOfVote",
68                         tx: &types.Tx{
69                                 TxData: types.TxData{
70                                         Inputs:  []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 1000000, 0, []byte{0x51}, testXpub)},
71                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte{0x51})},
72                                 },
73                         },
74                         prevConsensusResult: &ConsensusResult{
75                                 NumOfVote: map[string]uint64{
76                                         hex.EncodeToString(testXpub): 1000000,
77                                 },
78                         },
79                         postConsensusResult: &ConsensusResult{
80                                 NumOfVote: map[string]uint64{},
81                         },
82                         wantErr: nil,
83                 },
84         }
85
86         for i, c := range cases {
87                 if err := c.prevConsensusResult.ApplyTransaction(c.tx); err != nil {
88                         if err != c.wantErr {
89                                 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
90                         }
91                         continue
92                 }
93
94                 if !testutil.DeepEqual(c.prevConsensusResult, c.postConsensusResult) {
95                         t.Errorf("test case #%d, want %v, got %v", i, c.postConsensusResult, c.prevConsensusResult)
96                 }
97         }
98 }
99
100 func TestAttachCoinbaseReward(t *testing.T) {
101         cases := []struct {
102                 desc                string
103                 block               *types.Block
104                 prevConsensusResult *ConsensusResult
105                 postConsensusResult *ConsensusResult
106                 wantErr             error
107         }{
108                 {
109                         desc: "normal test with block contain coinbase tx and other tx",
110                         block: &types.Block{
111                                 BlockHeader: types.BlockHeader{
112                                         Height: 1,
113                                 },
114                                 Transactions: []*types.Tx{
115                                         {
116                                                 TxData: types.TxData{
117                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
118                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
119                                                 },
120                                         },
121                                         {
122                                                 TxData: types.TxData{
123                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)},
124                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
125                                                 },
126                                         },
127                                 },
128                         },
129                         prevConsensusResult: &ConsensusResult{
130                                 CoinbaseReward: map[string]uint64{
131                                         hex.EncodeToString([]byte{0x51}): 50000000,
132                                         hex.EncodeToString([]byte{0x52}): 80000000,
133                                 },
134                         },
135                         postConsensusResult: &ConsensusResult{
136                                 CoinbaseReward: map[string]uint64{
137                                         hex.EncodeToString([]byte{0x51}): consensus.BlockSubsidy(1) + 50000000,
138                                 },
139                         },
140                         wantErr: nil,
141                 },
142                 {
143                         desc: "test cal coinbase reward overflow",
144                         block: &types.Block{
145                                 BlockHeader: types.BlockHeader{
146                                         Height: 100,
147                                 },
148                                 Transactions: []*types.Tx{
149                                         {
150                                                 TxData: types.TxData{
151                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
152                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
153                                                 },
154                                         },
155                                         {
156                                                 TxData: types.TxData{
157                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, math.MaxUint64, 0, nil)},
158                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x52})},
159                                                 },
160                                         },
161                                 },
162                         },
163                         prevConsensusResult: &ConsensusResult{
164                                 CoinbaseReward: map[string]uint64{
165                                         hex.EncodeToString([]byte{0x51}): 50000000,
166                                         hex.EncodeToString([]byte{0x52}): 80000000,
167                                 },
168                         },
169                         postConsensusResult: &ConsensusResult{
170                                 CoinbaseReward: map[string]uint64{
171                                         hex.EncodeToString([]byte{0x51}): consensus.BlockSubsidy(1) + 50000000,
172                                 },
173                         },
174                         wantErr: checked.ErrOverflow,
175                 },
176                 {
177                         desc: "test coinbase reward overflow",
178                         block: &types.Block{
179                                 BlockHeader: types.BlockHeader{
180                                         Height: 100,
181                                 },
182                                 Transactions: []*types.Tx{
183                                         {
184                                                 TxData: types.TxData{
185                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
186                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
187                                                 },
188                                         },
189                                         {
190                                                 TxData: types.TxData{
191                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, math.MaxUint64-80000000, 0, nil)},
192                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 0, []byte{0x52})},
193                                                 },
194                                         },
195                                 },
196                         },
197                         prevConsensusResult: &ConsensusResult{
198                                 CoinbaseReward: map[string]uint64{
199                                         hex.EncodeToString([]byte{0x51}): 80000000,
200                                         hex.EncodeToString([]byte{0x52}): 50000000,
201                                 },
202                         },
203                         postConsensusResult: &ConsensusResult{
204                                 CoinbaseReward: map[string]uint64{
205                                         hex.EncodeToString([]byte{0x51}): consensus.BlockSubsidy(1) + 50000000,
206                                 },
207                         },
208                         wantErr: checked.ErrOverflow,
209                 },
210         }
211
212         for i, c := range cases {
213                 if err := c.prevConsensusResult.AttachCoinbaseReward(c.block); err != nil {
214                         if err != c.wantErr {
215                                 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
216                         }
217                         continue
218                 }
219
220                 if !testutil.DeepEqual(c.prevConsensusResult, c.postConsensusResult) {
221                         t.Errorf("test case #%d, want %v, got %v", i, c.postConsensusResult, c.prevConsensusResult)
222                 }
223         }
224 }
225
226 func TestCalCoinbaseReward(t *testing.T) {
227         cases := []struct {
228                 desc       string
229                 block      *types.Block
230                 wantReward *CoinbaseReward
231                 wantErr    error
232         }{
233                 {
234                         desc: "normal test with block contain coinbase tx and other tx",
235                         block: &types.Block{
236                                 BlockHeader: types.BlockHeader{
237                                         Height: 1,
238                                 },
239                                 Transactions: []*types.Tx{
240                                         &types.Tx{
241                                                 TxData: types.TxData{
242                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
243                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
244                                                 },
245                                         },
246                                         &types.Tx{
247                                                 TxData: types.TxData{
248                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)},
249                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
250                                                 },
251                                         },
252                                 },
253                         },
254                         wantReward: &CoinbaseReward{
255                                 Amount:         consensus.BlockSubsidy(1) + 50000000,
256                                 ControlProgram: []byte{0x51},
257                         },
258                 },
259                 {
260                         desc: "normal test with block only contain coinbase tx",
261                         block: &types.Block{
262                                 BlockHeader: types.BlockHeader{
263                                         Height: 1200,
264                                 },
265                                 Transactions: []*types.Tx{
266                                         &types.Tx{
267                                                 TxData: types.TxData{
268                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
269                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 1000000000, []byte{0x51})},
270                                                 },
271                                         },
272                                 },
273                         },
274                         wantReward: &CoinbaseReward{
275                                 Amount:         consensus.BlockSubsidy(1),
276                                 ControlProgram: []byte{0x51},
277                         },
278                 },
279                 {
280                         desc: "abnormal test with block not contain coinbase tx",
281                         block: &types.Block{
282                                 BlockHeader: types.BlockHeader{
283                                         Height: 1,
284                                 },
285                                 Transactions: []*types.Tx{},
286                         },
287                         wantErr: errors.New("not found coinbase receiver"),
288                 },
289         }
290
291         for i, c := range cases {
292                 coinbaseReward, err := CalCoinbaseReward(c.block)
293                 if err != nil {
294                         if err.Error() != c.wantErr.Error() {
295                                 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
296                         }
297                         continue
298                 }
299
300                 if !testutil.DeepEqual(coinbaseReward, c.wantReward) {
301                         t.Errorf("test case #%d, want %v, got %v", i, c.wantReward, coinbaseReward)
302                 }
303         }
304 }
305
306 func TestConsensusApplyBlock(t *testing.T) {
307         testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
308         cases := []struct {
309                 desc            string
310                 block           *types.Block
311                 consensusResult *ConsensusResult
312                 wantResult      *ConsensusResult
313                 wantErr         error
314         }{
315                 {
316                         desc: "normal test with block height is equal to 1",
317                         block: &types.Block{
318                                 BlockHeader: types.BlockHeader{
319                                         Height:            1,
320                                         PreviousBlockHash: bc.Hash{V0: 1},
321                                 },
322                                 Transactions: []*types.Tx{
323                                         &types.Tx{
324                                                 TxData: types.TxData{
325                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
326                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
327                                                 },
328                                         },
329                                         &types.Tx{
330                                                 TxData: types.TxData{
331                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)},
332                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
333                                                 },
334                                         },
335                                 },
336                         },
337                         consensusResult: &ConsensusResult{
338                                 Seq:            0,
339                                 NumOfVote:      map[string]uint64{},
340                                 CoinbaseReward: map[string]uint64{},
341                                 BlockHash:      bc.Hash{V0: 1},
342                                 BlockHeight:    0,
343                         },
344                         wantResult: &ConsensusResult{
345                                 Seq:       1,
346                                 NumOfVote: map[string]uint64{},
347                                 CoinbaseReward: map[string]uint64{
348                                         "51": consensus.BlockSubsidy(1) + 50000000,
349                                 },
350                                 BlockHash:   testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
351                                 BlockHeight: 1,
352                         },
353                 },
354                 {
355                         desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
356                         block: &types.Block{
357                                 BlockHeader: types.BlockHeader{
358                                         Height:            consensus.MainNetParams.RoundVoteBlockNums - 1,
359                                         PreviousBlockHash: bc.Hash{V0: 1},
360                                 },
361                                 Transactions: []*types.Tx{
362                                         &types.Tx{
363                                                 TxData: types.TxData{
364                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
365                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
366                                                 },
367                                         },
368                                         &types.Tx{
369                                                 TxData: types.TxData{
370                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
371                                                         Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
372                                                 },
373                                         },
374                                 },
375                         },
376                         consensusResult: &ConsensusResult{
377                                 NumOfVote:      map[string]uint64{},
378                                 CoinbaseReward: map[string]uint64{},
379                                 BlockHash:      bc.Hash{V0: 1},
380                                 BlockHeight:    consensus.MainNetParams.RoundVoteBlockNums - 2,
381                         },
382                         wantResult: &ConsensusResult{
383                                 Seq: 1,
384                                 NumOfVote: map[string]uint64{
385                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
386                                 },
387                                 CoinbaseReward: map[string]uint64{
388                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
389                                 },
390                                 BlockHash:   testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
391                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
392                         },
393                 },
394                 {
395                         desc: "normal test with block height is equal to RoundVoteBlockNums",
396                         block: &types.Block{
397                                 BlockHeader: types.BlockHeader{
398                                         Height:            consensus.MainNetParams.RoundVoteBlockNums,
399                                         PreviousBlockHash: bc.Hash{V0: 1},
400                                 },
401                                 Transactions: []*types.Tx{
402                                         &types.Tx{
403                                                 TxData: types.TxData{
404                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
405                                                         Outputs: []*types.TxOutput{
406                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
407                                                         },
408                                                 },
409                                         },
410                                         &types.Tx{
411                                                 TxData: types.TxData{
412                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
413                                                         Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
414                                                 },
415                                         },
416                                         &types.Tx{
417                                                 TxData: types.TxData{
418                                                         Inputs:  []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, []byte{0x51}, testXpub)},
419                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte{0x51})},
420                                                 },
421                                         },
422                                 },
423                         },
424                         consensusResult: &ConsensusResult{
425                                 NumOfVote: map[string]uint64{},
426                                 CoinbaseReward: map[string]uint64{
427                                         "51": 10000000,
428                                         "52": 20000000,
429                                         "53": 30000000,
430                                 },
431                                 BlockHash:   bc.Hash{V0: 1},
432                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
433                         },
434                         wantResult: &ConsensusResult{
435                                 Seq: 1,
436                                 NumOfVote: map[string]uint64{
437                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
438                                 },
439                                 CoinbaseReward: map[string]uint64{
440                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
441                                         "52": 20000000,
442                                         "53": 30000000,
443                                 },
444                                 BlockHash:   testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
445                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
446                         },
447                 },
448                 {
449                         desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
450                         block: &types.Block{
451                                 BlockHeader: types.BlockHeader{
452                                         Height:            consensus.MainNetParams.RoundVoteBlockNums + 1,
453                                         PreviousBlockHash: bc.Hash{V0: 1},
454                                 },
455                                 Transactions: []*types.Tx{
456                                         &types.Tx{
457                                                 TxData: types.TxData{
458                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
459                                                         Outputs: []*types.TxOutput{
460                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
461                                                                 types.NewIntraChainOutput(bc.AssetID{}, consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums)+10000000, []byte{0x51}),
462                                                                 types.NewIntraChainOutput(bc.AssetID{}, 20000000, []byte{0x53}),
463                                                                 types.NewIntraChainOutput(bc.AssetID{}, 30000000, []byte{0x52}),
464                                                         },
465                                                 },
466                                         },
467                                 },
468                         },
469                         consensusResult: &ConsensusResult{
470                                 NumOfVote: map[string]uint64{},
471                                 CoinbaseReward: map[string]uint64{
472                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
473                                         "52": 20000000,
474                                         "53": 30000000,
475                                 },
476                                 BlockHash:   bc.Hash{V0: 1},
477                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
478                         },
479                         wantResult: &ConsensusResult{
480                                 Seq:       2,
481                                 NumOfVote: map[string]uint64{},
482                                 CoinbaseReward: map[string]uint64{
483                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
484                                 },
485                                 BlockHash:   testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
486                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
487                         },
488                 },
489                 {
490                         desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
491                         block: &types.Block{
492                                 BlockHeader: types.BlockHeader{
493                                         Height:            consensus.MainNetParams.RoundVoteBlockNums + 2,
494                                         PreviousBlockHash: bc.Hash{V0: 1},
495                                 },
496                                 Transactions: []*types.Tx{
497                                         &types.Tx{
498                                                 TxData: types.TxData{
499                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
500                                                         Outputs: []*types.TxOutput{
501                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
502                                                         },
503                                                 },
504                                         },
505                                 },
506                         },
507                         consensusResult: &ConsensusResult{
508                                 NumOfVote: map[string]uint64{},
509                                 CoinbaseReward: map[string]uint64{
510                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
511                                 },
512                                 BlockHash:   bc.Hash{V0: 1},
513                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
514                         },
515                         wantResult: &ConsensusResult{
516                                 Seq:       2,
517                                 NumOfVote: map[string]uint64{},
518                                 CoinbaseReward: map[string]uint64{
519                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+2),
520                                 },
521                                 BlockHash:   testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
522                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 2,
523                         },
524                 },
525                 {
526                         desc: "abnormal test with block parent hash is not equals last block hash of vote result",
527                         block: &types.Block{
528                                 BlockHeader: types.BlockHeader{
529                                         Height:            1,
530                                         PreviousBlockHash: bc.Hash{V0: 0},
531                                 },
532                                 Transactions: []*types.Tx{},
533                         },
534                         consensusResult: &ConsensusResult{
535                                 NumOfVote:      map[string]uint64{},
536                                 CoinbaseReward: map[string]uint64{},
537                                 BlockHash:      bc.Hash{V0: 1},
538                                 BlockHeight:    2,
539                         },
540                         wantErr: errors.New("block parent hash is not equals last block hash of vote result"),
541                 },
542                 {
543                         desc: "abnormal test with arithmetic overflow for calculate transaction fee",
544                         block: &types.Block{
545                                 BlockHeader: types.BlockHeader{
546                                         Height:            1,
547                                         PreviousBlockHash: bc.Hash{V0: 1},
548                                 },
549                                 Transactions: []*types.Tx{
550                                         &types.Tx{
551                                                 TxData: types.TxData{
552                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
553                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
554                                                 },
555                                         },
556                                         &types.Tx{
557                                                 TxData: types.TxData{
558                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, nil)},
559                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 200000000, []byte{0x51})},
560                                                 },
561                                         },
562                                 },
563                         },
564                         consensusResult: &ConsensusResult{
565                                 NumOfVote:      map[string]uint64{},
566                                 CoinbaseReward: map[string]uint64{},
567                                 BlockHash:      bc.Hash{V0: 1},
568                                 BlockHeight:    2,
569                         },
570                         wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
571                 },
572                 {
573                         desc: "abnormal test with not found coinbase receiver",
574                         block: &types.Block{
575                                 BlockHeader: types.BlockHeader{
576                                         Height:            1,
577                                         PreviousBlockHash: bc.Hash{V0: 1},
578                                 },
579                                 Transactions: []*types.Tx{},
580                         },
581                         consensusResult: &ConsensusResult{
582                                 NumOfVote:      map[string]uint64{},
583                                 CoinbaseReward: map[string]uint64{},
584                                 BlockHash:      bc.Hash{V0: 1},
585                                 BlockHeight:    2,
586                         },
587                         wantErr: errors.New("not found coinbase receiver"),
588                 },
589         }
590
591         for i, c := range cases {
592                 if err := c.consensusResult.ApplyBlock(c.block); err != nil {
593                         if err.Error() != c.wantErr.Error() {
594                                 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
595                         }
596                         continue
597                 }
598
599                 if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
600                         t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
601                 }
602         }
603 }
604
605 func TestConsensusDetachBlock(t *testing.T) {
606         testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
607         cases := []struct {
608                 desc            string
609                 block           *types.Block
610                 consensusResult *ConsensusResult
611                 wantResult      *ConsensusResult
612                 wantErr         error
613         }{
614                 {
615                         desc: "normal test with block height is equal to 1",
616                         block: &types.Block{
617                                 BlockHeader: types.BlockHeader{
618                                         Height:            1,
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, 300000000, 0, nil)},
631                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
632                                                 },
633                                         },
634                                 },
635                         },
636                         consensusResult: &ConsensusResult{
637                                 Seq:       1,
638                                 NumOfVote: map[string]uint64{},
639                                 CoinbaseReward: map[string]uint64{
640                                         "51": consensus.BlockSubsidy(1) + 50000000,
641                                 },
642                                 BlockHash:   testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
643                                 BlockHeight: 1,
644                         },
645                         wantResult: &ConsensusResult{
646                                 Seq:            0,
647                                 NumOfVote:      map[string]uint64{},
648                                 CoinbaseReward: map[string]uint64{},
649                                 BlockHash:      bc.Hash{V0: 1},
650                                 BlockHeight:    0,
651                         },
652                 },
653                 {
654                         desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
655                         block: &types.Block{
656                                 BlockHeader: types.BlockHeader{
657                                         Height:            consensus.MainNetParams.RoundVoteBlockNums - 1,
658                                         PreviousBlockHash: bc.Hash{V0: 1},
659                                 },
660                                 Transactions: []*types.Tx{
661                                         &types.Tx{
662                                                 TxData: types.TxData{
663                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
664                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
665                                                 },
666                                         },
667                                         &types.Tx{
668                                                 TxData: types.TxData{
669                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
670                                                         Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
671                                                 },
672                                         },
673                                 },
674                         },
675                         consensusResult: &ConsensusResult{
676                                 NumOfVote: map[string]uint64{
677                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
678                                 },
679                                 CoinbaseReward: map[string]uint64{
680                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
681                                 },
682                                 BlockHash:   testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
683                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
684                         },
685                         wantResult: &ConsensusResult{
686                                 Seq:            1,
687                                 NumOfVote:      map[string]uint64{},
688                                 CoinbaseReward: map[string]uint64{},
689                                 BlockHash:      bc.Hash{V0: 1},
690                                 BlockHeight:    consensus.MainNetParams.RoundVoteBlockNums - 2,
691                         },
692                 },
693                 {
694                         desc: "normal test with block height is equal to RoundVoteBlockNums",
695                         block: &types.Block{
696                                 BlockHeader: types.BlockHeader{
697                                         Height:            consensus.MainNetParams.RoundVoteBlockNums,
698                                         PreviousBlockHash: bc.Hash{V0: 1},
699                                 },
700                                 Transactions: []*types.Tx{
701                                         &types.Tx{
702                                                 TxData: types.TxData{
703                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
704                                                         Outputs: []*types.TxOutput{
705                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
706                                                         },
707                                                 },
708                                         },
709                                 },
710                         },
711                         consensusResult: &ConsensusResult{
712                                 NumOfVote: map[string]uint64{
713                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
714                                 },
715                                 CoinbaseReward: map[string]uint64{
716                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 100000000,
717                                 },
718                                 BlockHash:   testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
719                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
720                         },
721                         wantResult: &ConsensusResult{
722                                 Seq: 1,
723                                 NumOfVote: map[string]uint64{
724                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
725                                 },
726                                 CoinbaseReward: map[string]uint64{
727                                         "51": 100000000,
728                                 },
729                                 BlockHash:   bc.Hash{V0: 1},
730                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
731                         },
732                 },
733                 {
734                         desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
735                         block: &types.Block{
736                                 BlockHeader: types.BlockHeader{
737                                         Height:            consensus.MainNetParams.RoundVoteBlockNums + 1,
738                                         PreviousBlockHash: bc.Hash{V0: 1},
739                                 },
740                                 Transactions: []*types.Tx{
741                                         &types.Tx{
742                                                 TxData: types.TxData{
743                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
744                                                         Outputs: []*types.TxOutput{
745                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
746                                                                 types.NewIntraChainOutput(bc.AssetID{}, consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums)+10000000, []byte{0x51}),
747                                                                 types.NewIntraChainOutput(bc.AssetID{}, 20000000, []byte{0x52}),
748                                                         },
749                                                 },
750                                         },
751                                 },
752                         },
753                         consensusResult: &ConsensusResult{
754                                 NumOfVote: map[string]uint64{},
755                                 CoinbaseReward: map[string]uint64{
756                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
757                                 },
758                                 BlockHash:   testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
759                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
760                         },
761                         wantResult: &ConsensusResult{
762                                 Seq:       1,
763                                 NumOfVote: map[string]uint64{},
764                                 CoinbaseReward: map[string]uint64{
765                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
766                                         "52": 20000000,
767                                 },
768                                 BlockHash:   bc.Hash{V0: 1},
769                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
770                         },
771                 },
772                 {
773                         desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
774                         block: &types.Block{
775                                 BlockHeader: types.BlockHeader{
776                                         Height:            consensus.MainNetParams.RoundVoteBlockNums + 2,
777                                         PreviousBlockHash: bc.Hash{V0: 1},
778                                 },
779                                 Transactions: []*types.Tx{
780                                         &types.Tx{
781                                                 TxData: types.TxData{
782                                                         Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
783                                                         Outputs: []*types.TxOutput{
784                                                                 types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
785                                                         },
786                                                 },
787                                         },
788                                 },
789                         },
790                         consensusResult: &ConsensusResult{
791                                 NumOfVote: map[string]uint64{},
792                                 CoinbaseReward: map[string]uint64{
793                                         "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + 1000000,
794                                 },
795                                 BlockHash:   testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
796                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
797                         },
798                         wantResult: &ConsensusResult{
799                                 Seq:       2,
800                                 NumOfVote: map[string]uint64{},
801                                 CoinbaseReward: map[string]uint64{
802                                         "51": 1000000,
803                                 },
804                                 BlockHash:   bc.Hash{V0: 1},
805                                 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
806                         },
807                 },
808                 {
809                         desc: "abnormal test with block hash is not equals last block hash of vote result",
810                         block: &types.Block{
811                                 BlockHeader: types.BlockHeader{
812                                         Height:            2,
813                                         PreviousBlockHash: bc.Hash{V0: 0},
814                                 },
815                                 Transactions: []*types.Tx{},
816                         },
817                         consensusResult: &ConsensusResult{
818                                 NumOfVote:      map[string]uint64{},
819                                 CoinbaseReward: map[string]uint64{},
820                                 BlockHash:      bc.Hash{V0: 1},
821                                 BlockHeight:    1,
822                         },
823                         wantErr: errors.New("block hash is not equals last block hash of vote result"),
824                 },
825                 {
826                         desc: "abnormal test with arithmetic overflow for calculate transaction fee",
827                         block: &types.Block{
828                                 BlockHeader: types.BlockHeader{
829                                         Height:            2,
830                                         PreviousBlockHash: bc.Hash{V0: 1},
831                                 },
832                                 Transactions: []*types.Tx{
833                                         &types.Tx{
834                                                 TxData: types.TxData{
835                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
836                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
837                                                 },
838                                         },
839                                         &types.Tx{
840                                                 TxData: types.TxData{
841                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, nil)},
842                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 200000000, []byte{0x51})},
843                                                 },
844                                         },
845                                 },
846                         },
847                         consensusResult: &ConsensusResult{
848                                 NumOfVote:      map[string]uint64{},
849                                 CoinbaseReward: map[string]uint64{},
850                                 BlockHash:      testutil.MustDecodeHash("02b7fb48defc4f4a3e1ef8403f7c0be78c4414ee66aa81fd702caa1e41a906df"),
851                                 BlockHeight:    1,
852                         },
853                         wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
854                 },
855                 {
856                         desc: "abnormal test with not found coinbase receiver",
857                         block: &types.Block{
858                                 BlockHeader: types.BlockHeader{
859                                         Height:            1,
860                                         PreviousBlockHash: bc.Hash{V0: 1},
861                                 },
862                                 Transactions: []*types.Tx{},
863                         },
864                         consensusResult: &ConsensusResult{
865                                 NumOfVote:      map[string]uint64{},
866                                 CoinbaseReward: map[string]uint64{},
867                                 BlockHash:      testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
868                                 BlockHeight:    1,
869                         },
870                         wantErr: errors.New("not found coinbase receiver"),
871                 },
872                 {
873                         desc: "test number of vote overflow",
874                         block: &types.Block{
875                                 BlockHeader: types.BlockHeader{
876                                         Height:            consensus.MainNetParams.RoundVoteBlockNums - 1,
877                                         PreviousBlockHash: bc.Hash{V0: 1},
878                                 },
879                                 Transactions: []*types.Tx{
880                                         &types.Tx{
881                                                 TxData: types.TxData{
882                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
883                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
884                                                 },
885                                         },
886                                         &types.Tx{
887                                                 TxData: types.TxData{
888                                                         Inputs:  []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
889                                                         Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
890                                                 },
891                                         },
892                                 },
893                         },
894                         consensusResult: &ConsensusResult{
895                                 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
896                                 CoinbaseReward: map[string]uint64{
897                                         "51": 100000000,
898                                 },
899                                 NumOfVote: map[string]uint64{},
900                         },
901                         wantErr: checked.ErrOverflow,
902                 },
903                 {
904                         desc: "test number of veto overflow",
905                         block: &types.Block{
906                                 BlockHeader: types.BlockHeader{
907                                         Height:            consensus.MainNetParams.RoundVoteBlockNums - 1,
908                                         PreviousBlockHash: bc.Hash{V0: 1},
909                                 },
910                                 Transactions: []*types.Tx{
911                                         &types.Tx{
912                                                 TxData: types.TxData{
913                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
914                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
915                                                 },
916                                         },
917                                         &types.Tx{
918                                                 TxData: types.TxData{
919                                                         Inputs:  []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, math.MaxUint64, 0, []byte{0x51}, testXpub)},
920                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, []byte{0x51})},
921                                                 },
922                                         },
923                                 },
924                         },
925                         consensusResult: &ConsensusResult{
926                                 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
927                                 CoinbaseReward: map[string]uint64{
928                                         "51": 100000000,
929                                 },
930                                 NumOfVote: map[string]uint64{
931                                         "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 100,
932                                 },
933                         },
934                         wantErr: checked.ErrOverflow,
935                 },
936                 {
937                         desc: "test detch coinbase overflow",
938                         block: &types.Block{
939                                 BlockHeader: types.BlockHeader{
940                                         Height:            consensus.MainNetParams.RoundVoteBlockNums - 1,
941                                         PreviousBlockHash: bc.Hash{V0: 1},
942                                 },
943                                 Transactions: []*types.Tx{
944                                         &types.Tx{
945                                                 TxData: types.TxData{
946                                                         Inputs:  []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
947                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
948                                                 },
949                                         },
950                                         &types.Tx{
951                                                 TxData: types.TxData{
952                                                         Inputs:  []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, math.MaxUint64, 0, []byte{0x51}, testXpub)},
953                                                         Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, []byte{0x51})},
954                                                 },
955                                         },
956                                 },
957                         },
958                         consensusResult: &ConsensusResult{
959                                 BlockHash:      testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
960                                 CoinbaseReward: map[string]uint64{},
961                                 NumOfVote:      map[string]uint64{},
962                         },
963                         wantErr: checked.ErrOverflow,
964                 },
965         }
966         for i, c := range cases {
967                 if err := c.consensusResult.DetachBlock(c.block); err != nil {
968                         if err.Error() != c.wantErr.Error() {
969                                 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
970                         }
971                         continue
972                 }
973
974                 if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
975                         t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
976                 }
977         }
978 }
979
980 func TestGetCoinbaseRewards(t *testing.T) {
981         cases := []struct {
982                 desc            string
983                 blockHeight     uint64
984                 consensusResult *ConsensusResult
985                 wantRewards     []CoinbaseReward
986         }{
987                 {
988                         desc:        "the block height is RoundVoteBlockNums - 1",
989                         blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums - 1,
990                         consensusResult: &ConsensusResult{
991                                 CoinbaseReward: map[string]uint64{
992                                         "51": 10,
993                                 },
994                         },
995                         wantRewards: []CoinbaseReward{},
996                 },
997                 {
998                         desc:        "the block height is RoundVoteBlockNums",
999                         blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums,
1000                         consensusResult: &ConsensusResult{
1001                                 CoinbaseReward: map[string]uint64{
1002                                         "51": 10,
1003                                         "52": 20,
1004                                 },
1005                         },
1006                         wantRewards: []CoinbaseReward{
1007                                 CoinbaseReward{
1008                                         Amount:         20,
1009                                         ControlProgram: []byte{0x52},
1010                                 },
1011                                 CoinbaseReward{
1012                                         Amount:         10,
1013                                         ControlProgram: []byte{0x51},
1014                                 },
1015                         },
1016                 },
1017                 {
1018                         desc:        "the block height is RoundVoteBlockNums + 1",
1019                         blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums + 1,
1020                         consensusResult: &ConsensusResult{
1021                                 CoinbaseReward: map[string]uint64{
1022                                         "51": 10,
1023                                 },
1024                         },
1025                         wantRewards: []CoinbaseReward{},
1026                 },
1027                 {
1028                         desc:        "the block height is RoundVoteBlockNums * 2",
1029                         blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums * 2,
1030                         consensusResult: &ConsensusResult{
1031                                 CoinbaseReward: map[string]uint64{
1032                                         "50": 20,
1033                                         "51": 10,
1034                                         "52": 20,
1035                                         "53": 30,
1036                                 },
1037                         },
1038                         wantRewards: []CoinbaseReward{
1039                                 CoinbaseReward{
1040                                         Amount:         30,
1041                                         ControlProgram: []byte{0x53},
1042                                 },
1043                                 CoinbaseReward{
1044                                         Amount:         20,
1045                                         ControlProgram: []byte{0x52},
1046                                 },
1047                                 CoinbaseReward{
1048                                         Amount:         20,
1049                                         ControlProgram: []byte{0x50},
1050                                 },
1051                                 CoinbaseReward{
1052                                         Amount:         10,
1053                                         ControlProgram: []byte{0x51},
1054                                 },
1055                         },
1056                 },
1057                 {
1058                         desc:        "the block height is 2*RoundVoteBlockNums + 1",
1059                         blockHeight: 2*consensus.ActiveNetParams.RoundVoteBlockNums + 1,
1060                         consensusResult: &ConsensusResult{
1061                                 CoinbaseReward: map[string]uint64{},
1062                         },
1063                         wantRewards: []CoinbaseReward{},
1064                 },
1065         }
1066
1067         for i, c := range cases {
1068                 rewards, err := c.consensusResult.GetCoinbaseRewards(c.blockHeight)
1069                 if err != nil {
1070                         t.Fatal(err)
1071                 }
1072
1073                 if !testutil.DeepEqual(rewards, c.wantRewards) {
1074                         t.Errorf("test case #%d, want %v, got %v", i, c.wantRewards, rewards)
1075                 }
1076         }
1077 }
1078
1079 func TestConsensusNodes(t *testing.T) {
1080         var xpub1, xpub2, xpub3, xpub4, xpub5, xpub6, xpub7 chainkd.XPub
1081         strPub1 := "0f8669abbd3cc0a167156188e428f940088d5b2f36bb3449df71d2bdc5e077814ea3f68628eef279ed435f51ee26cff00f8bd28fabfd500bedb2a9e369f5c825"
1082         strPub2 := "e7f458ee8d2ba19b0fdc7410d1fd57e9c2e1a79377c661d66c55effe49d7ffc920e40510442d4a10b7bea06c09fb0b41f52601135adaaa7136204db36106c093"
1083         strPub3 := "1bec3a35da038ec7a76c40986e80b5af2dcef60341970e3fc58b4db0797bd4ca9b2cbf3d7ab820832e22a80b5b86ae1427f7f706a7780089958b2862e7bc0842"
1084         strPub4 := "b7f463446a31b3792cd168d52b7a89b3657bca3e25d6854db1488c389ab6fc8d538155c25c1ee6975cc7def19710908c7d9b7463ca34a22058b456b45e498db9"
1085         strPub5 := "b928e46bb01e834fdf167185e31b15de7cc257af8bbdf17f9c7fefd5bb97b306d048b6bc0da2097152c1c2ff38333c756a543adbba7030a447dcc776b8ac64ef"
1086         strPub6 := "36695997983028c279c3360ca345a90e3af1f9e3df2506119fca31cdc844be31630f9a421f4d1658e15d67a15ce29c36332dd45020d2a0147fcce4949ccd9a67"
1087         strPub7 := "123"
1088
1089         xpub1.UnmarshalText([]byte(strPub1))
1090         xpub2.UnmarshalText([]byte(strPub2))
1091         xpub3.UnmarshalText([]byte(strPub3))
1092         xpub4.UnmarshalText([]byte(strPub4))
1093         xpub5.UnmarshalText([]byte(strPub5))
1094         xpub6.UnmarshalText([]byte(strPub6))
1095         xpub7.UnmarshalText([]byte(strPub7))
1096
1097         cases := []struct {
1098                 consensusResult *ConsensusResult
1099                 consensusNode   map[string]*ConsensusNode
1100                 wantErr         error
1101         }{
1102                 {
1103                         consensusResult: &ConsensusResult{
1104                                 NumOfVote: map[string]uint64{
1105                                         strPub1: 838063475500000,  //1
1106                                         strPub2: 474794800000000,  //3
1107                                         strPub3: 833812985000000,  //2
1108                                         strPub4: 285918061999999,  //4
1109                                         strPub5: 1228455289930297, //0
1110                                         strPub6: 274387690000000,  //5
1111                                         strPub7: 1028455289930297,
1112                                 },
1113                         },
1114                         consensusNode: map[string]*ConsensusNode{
1115                                 strPub1: &ConsensusNode{XPub: xpub1, VoteNum: 838063475500000, Order: 1},
1116                                 strPub2: &ConsensusNode{XPub: xpub2, VoteNum: 474794800000000, Order: 3},
1117                                 strPub3: &ConsensusNode{XPub: xpub3, VoteNum: 833812985000000, Order: 2},
1118                                 strPub4: &ConsensusNode{XPub: xpub4, VoteNum: 285918061999999, Order: 4},
1119                                 strPub5: &ConsensusNode{XPub: xpub5, VoteNum: 1228455289930297, Order: 0},
1120                                 strPub6: &ConsensusNode{XPub: xpub6, VoteNum: 274387690000000, Order: 5},
1121                         },
1122                 },
1123         }
1124
1125         for i, c := range cases {
1126                 consensusNode, err := c.consensusResult.ConsensusNodes()
1127                 if err != nil {
1128                         if err != c.wantErr {
1129                                 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
1130                         }
1131                         continue
1132                 }
1133
1134                 if !testutil.DeepEqual(consensusNode, c.consensusNode) {
1135                         t.Errorf("test case #%d, want %v, got %v", i, c.consensusNode, consensusNode)
1136                 }
1137         }
1138 }
1139
1140 func TestFork(t *testing.T) {
1141         consensusResult := &ConsensusResult{
1142                 Seq: 100,
1143                 NumOfVote: map[string]uint64{
1144                         "a": 100,
1145                         "b": 200,
1146                 },
1147                 CoinbaseReward: map[string]uint64{
1148                         "c": 300,
1149                         "d": 400,
1150                 },
1151                 BlockHash:   bc.NewHash([32]byte{0x1, 0x2}),
1152                 BlockHeight: 1024,
1153         }
1154         copy := consensusResult.Fork()
1155
1156         if !reflect.DeepEqual(consensusResult, copy) {
1157                 t.Fatalf("failed on test consensusResult got %s want %s", spew.Sdump(copy), spew.Sdump(consensusResult))
1158         }
1159 }