OSDN Git Service

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