9 "github.com/davecgh/go-spew/spew"
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"
20 func TestApplyTransaction(t *testing.T) {
21 testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
26 prevConsensusResult *ConsensusResult
27 postConsensusResult *ConsensusResult
31 desc: "test num Of vote overflow",
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)},
38 prevConsensusResult: &ConsensusResult{
39 NumOfVote: map[string]uint64{
40 hex.EncodeToString(testXpub): 1000000,
43 postConsensusResult: &ConsensusResult{
44 NumOfVote: map[string]uint64{},
46 wantErr: checked.ErrOverflow,
49 desc: "test num Of veto overflow",
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})},
56 prevConsensusResult: &ConsensusResult{
57 NumOfVote: map[string]uint64{
58 hex.EncodeToString(testXpub): 1000000,
61 postConsensusResult: &ConsensusResult{
62 NumOfVote: map[string]uint64{},
64 wantErr: checked.ErrOverflow,
67 desc: "test del pubkey from NumOfVote",
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})},
74 prevConsensusResult: &ConsensusResult{
75 NumOfVote: map[string]uint64{
76 hex.EncodeToString(testXpub): 1000000,
79 postConsensusResult: &ConsensusResult{
80 NumOfVote: map[string]uint64{},
86 for i, c := range cases {
87 if err := c.prevConsensusResult.ApplyTransaction(c.tx); err != nil {
89 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
94 if !testutil.DeepEqual(c.prevConsensusResult, c.postConsensusResult) {
95 t.Errorf("test case #%d, want %v, got %v", i, c.postConsensusResult, c.prevConsensusResult)
100 func TestAttachCoinbaseReward(t *testing.T) {
104 prevConsensusResult *ConsensusResult
105 postConsensusResult *ConsensusResult
109 desc: "normal test with block contain coinbase tx and other tx",
111 BlockHeader: types.BlockHeader{
114 Transactions: []*types.Tx{
116 TxData: types.TxData{
117 Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
118 Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
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})},
129 prevConsensusResult: &ConsensusResult{
130 CoinbaseReward: map[string]uint64{
131 hex.EncodeToString([]byte{0x51}): 50000000,
132 hex.EncodeToString([]byte{0x52}): 80000000,
135 postConsensusResult: &ConsensusResult{
136 CoinbaseReward: map[string]uint64{
137 hex.EncodeToString([]byte{0x51}): consensus.BlockSubsidy(1) + 50000000,
143 desc: "test cal coinbase reward overflow",
145 BlockHeader: types.BlockHeader{
148 Transactions: []*types.Tx{
150 TxData: types.TxData{
151 Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
152 Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
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})},
163 prevConsensusResult: &ConsensusResult{
164 CoinbaseReward: map[string]uint64{
165 hex.EncodeToString([]byte{0x51}): 50000000,
166 hex.EncodeToString([]byte{0x52}): 80000000,
169 postConsensusResult: &ConsensusResult{
170 CoinbaseReward: map[string]uint64{
171 hex.EncodeToString([]byte{0x51}): consensus.BlockSubsidy(1) + 50000000,
174 wantErr: checked.ErrOverflow,
177 desc: "test coinbase reward overflow",
179 BlockHeader: types.BlockHeader{
182 Transactions: []*types.Tx{
184 TxData: types.TxData{
185 Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
186 Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
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})},
197 prevConsensusResult: &ConsensusResult{
198 CoinbaseReward: map[string]uint64{
199 hex.EncodeToString([]byte{0x51}): 80000000,
200 hex.EncodeToString([]byte{0x52}): 50000000,
203 postConsensusResult: &ConsensusResult{
204 CoinbaseReward: map[string]uint64{
205 hex.EncodeToString([]byte{0x51}): consensus.BlockSubsidy(1) + 50000000,
208 wantErr: checked.ErrOverflow,
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)
220 if !testutil.DeepEqual(c.prevConsensusResult, c.postConsensusResult) {
221 t.Errorf("test case #%d, want %v, got %v", i, c.postConsensusResult, c.prevConsensusResult)
226 func TestCalCoinbaseReward(t *testing.T) {
230 wantReward *CoinbaseReward
234 desc: "normal test with block contain coinbase tx and other tx",
236 BlockHeader: types.BlockHeader{
239 Transactions: []*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})},
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})},
254 wantReward: &CoinbaseReward{
255 Amount: consensus.BlockSubsidy(1) + 50000000,
256 ControlProgram: []byte{0x51},
260 desc: "normal test with block only contain coinbase tx",
262 BlockHeader: types.BlockHeader{
265 Transactions: []*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})},
274 wantReward: &CoinbaseReward{
275 Amount: consensus.BlockSubsidy(1),
276 ControlProgram: []byte{0x51},
280 desc: "abnormal test with block not contain coinbase tx",
282 BlockHeader: types.BlockHeader{
285 Transactions: []*types.Tx{},
287 wantErr: errors.New("not found coinbase receiver"),
291 for i, c := range cases {
292 coinbaseReward, err := CalCoinbaseReward(c.block)
294 if err.Error() != c.wantErr.Error() {
295 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
300 if !testutil.DeepEqual(coinbaseReward, c.wantReward) {
301 t.Errorf("test case #%d, want %v, got %v", i, c.wantReward, coinbaseReward)
306 func TestConsensusApplyBlock(t *testing.T) {
307 testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
311 consensusResult *ConsensusResult
312 wantResult *ConsensusResult
316 desc: "normal test with block height is equal to 1",
318 BlockHeader: types.BlockHeader{
320 PreviousBlockHash: bc.Hash{V0: 1},
322 Transactions: []*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})},
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})},
337 consensusResult: &ConsensusResult{
339 NumOfVote: map[string]uint64{},
340 CoinbaseReward: map[string]uint64{},
341 BlockHash: bc.Hash{V0: 1},
344 wantResult: &ConsensusResult{
346 NumOfVote: map[string]uint64{},
347 CoinbaseReward: map[string]uint64{
348 "51": consensus.BlockSubsidy(1) + 50000000,
350 BlockHash: testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
355 desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
357 BlockHeader: types.BlockHeader{
358 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
359 PreviousBlockHash: bc.Hash{V0: 1},
361 Transactions: []*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})},
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)},
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,
382 wantResult: &ConsensusResult{
384 NumOfVote: map[string]uint64{
385 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
387 CoinbaseReward: map[string]uint64{
388 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
390 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
391 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
395 desc: "normal test with block height is equal to RoundVoteBlockNums",
397 BlockHeader: types.BlockHeader{
398 Height: consensus.MainNetParams.RoundVoteBlockNums,
399 PreviousBlockHash: bc.Hash{V0: 1},
401 Transactions: []*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}),
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)},
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})},
424 consensusResult: &ConsensusResult{
425 NumOfVote: map[string]uint64{},
426 CoinbaseReward: map[string]uint64{
431 BlockHash: bc.Hash{V0: 1},
432 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
434 wantResult: &ConsensusResult{
436 NumOfVote: map[string]uint64{
437 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
439 CoinbaseReward: map[string]uint64{
440 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
444 BlockHash: testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
445 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
449 desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
451 BlockHeader: types.BlockHeader{
452 Height: consensus.MainNetParams.RoundVoteBlockNums + 1,
453 PreviousBlockHash: bc.Hash{V0: 1},
455 Transactions: []*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}),
469 consensusResult: &ConsensusResult{
470 NumOfVote: map[string]uint64{},
471 CoinbaseReward: map[string]uint64{
472 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
476 BlockHash: bc.Hash{V0: 1},
477 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
479 wantResult: &ConsensusResult{
481 NumOfVote: map[string]uint64{},
482 CoinbaseReward: map[string]uint64{
483 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
485 BlockHash: testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
486 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
490 desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
492 BlockHeader: types.BlockHeader{
493 Height: consensus.MainNetParams.RoundVoteBlockNums + 2,
494 PreviousBlockHash: bc.Hash{V0: 1},
496 Transactions: []*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}),
507 consensusResult: &ConsensusResult{
508 NumOfVote: map[string]uint64{},
509 CoinbaseReward: map[string]uint64{
510 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
512 BlockHash: bc.Hash{V0: 1},
513 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
515 wantResult: &ConsensusResult{
517 NumOfVote: map[string]uint64{},
518 CoinbaseReward: map[string]uint64{
519 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+2),
521 BlockHash: testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
522 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 2,
526 desc: "abnormal test with block parent hash is not equals last block hash of vote result",
528 BlockHeader: types.BlockHeader{
530 PreviousBlockHash: bc.Hash{V0: 0},
532 Transactions: []*types.Tx{},
534 consensusResult: &ConsensusResult{
535 NumOfVote: map[string]uint64{},
536 CoinbaseReward: map[string]uint64{},
537 BlockHash: bc.Hash{V0: 1},
540 wantErr: errors.New("block parent hash is not equals last block hash of vote result"),
543 desc: "abnormal test with arithmetic overflow for calculate transaction fee",
545 BlockHeader: types.BlockHeader{
547 PreviousBlockHash: bc.Hash{V0: 1},
549 Transactions: []*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})},
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})},
564 consensusResult: &ConsensusResult{
565 NumOfVote: map[string]uint64{},
566 CoinbaseReward: map[string]uint64{},
567 BlockHash: bc.Hash{V0: 1},
570 wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
573 desc: "abnormal test with not found coinbase receiver",
575 BlockHeader: types.BlockHeader{
577 PreviousBlockHash: bc.Hash{V0: 1},
579 Transactions: []*types.Tx{},
581 consensusResult: &ConsensusResult{
582 NumOfVote: map[string]uint64{},
583 CoinbaseReward: map[string]uint64{},
584 BlockHash: bc.Hash{V0: 1},
587 wantErr: errors.New("not found coinbase receiver"),
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)
599 if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
600 t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
605 func TestConsensusDetachBlock(t *testing.T) {
606 testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
610 consensusResult *ConsensusResult
611 wantResult *ConsensusResult
615 desc: "normal test with block height is equal to 1",
617 BlockHeader: types.BlockHeader{
619 PreviousBlockHash: bc.Hash{V0: 1},
621 Transactions: []*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})},
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})},
636 consensusResult: &ConsensusResult{
638 NumOfVote: map[string]uint64{},
639 CoinbaseReward: map[string]uint64{
640 "51": consensus.BlockSubsidy(1) + 50000000,
642 BlockHash: testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
645 wantResult: &ConsensusResult{
647 NumOfVote: map[string]uint64{},
648 CoinbaseReward: map[string]uint64{},
649 BlockHash: bc.Hash{V0: 1},
654 desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
656 BlockHeader: types.BlockHeader{
657 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
658 PreviousBlockHash: bc.Hash{V0: 1},
660 Transactions: []*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})},
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)},
675 consensusResult: &ConsensusResult{
676 NumOfVote: map[string]uint64{
677 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
679 CoinbaseReward: map[string]uint64{
680 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
682 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
683 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
685 wantResult: &ConsensusResult{
687 NumOfVote: map[string]uint64{},
688 CoinbaseReward: map[string]uint64{},
689 BlockHash: bc.Hash{V0: 1},
690 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 2,
694 desc: "normal test with block height is equal to RoundVoteBlockNums",
696 BlockHeader: types.BlockHeader{
697 Height: consensus.MainNetParams.RoundVoteBlockNums,
698 PreviousBlockHash: bc.Hash{V0: 1},
700 Transactions: []*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}),
711 consensusResult: &ConsensusResult{
712 NumOfVote: map[string]uint64{
713 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
715 CoinbaseReward: map[string]uint64{
716 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 100000000,
718 BlockHash: testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
719 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
721 wantResult: &ConsensusResult{
723 NumOfVote: map[string]uint64{
724 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
726 CoinbaseReward: map[string]uint64{
729 BlockHash: bc.Hash{V0: 1},
730 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
734 desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
736 BlockHeader: types.BlockHeader{
737 Height: consensus.MainNetParams.RoundVoteBlockNums + 1,
738 PreviousBlockHash: bc.Hash{V0: 1},
740 Transactions: []*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}),
753 consensusResult: &ConsensusResult{
754 NumOfVote: map[string]uint64{},
755 CoinbaseReward: map[string]uint64{
756 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
758 BlockHash: testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
759 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
761 wantResult: &ConsensusResult{
763 NumOfVote: map[string]uint64{},
764 CoinbaseReward: map[string]uint64{
765 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
768 BlockHash: bc.Hash{V0: 1},
769 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
773 desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
775 BlockHeader: types.BlockHeader{
776 Height: consensus.MainNetParams.RoundVoteBlockNums + 2,
777 PreviousBlockHash: bc.Hash{V0: 1},
779 Transactions: []*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}),
790 consensusResult: &ConsensusResult{
791 NumOfVote: map[string]uint64{},
792 CoinbaseReward: map[string]uint64{
793 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + 1000000,
795 BlockHash: testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
796 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
798 wantResult: &ConsensusResult{
800 NumOfVote: map[string]uint64{},
801 CoinbaseReward: map[string]uint64{
804 BlockHash: bc.Hash{V0: 1},
805 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
809 desc: "abnormal test with block hash is not equals last block hash of vote result",
811 BlockHeader: types.BlockHeader{
813 PreviousBlockHash: bc.Hash{V0: 0},
815 Transactions: []*types.Tx{},
817 consensusResult: &ConsensusResult{
818 NumOfVote: map[string]uint64{},
819 CoinbaseReward: map[string]uint64{},
820 BlockHash: bc.Hash{V0: 1},
823 wantErr: errors.New("block hash is not equals last block hash of vote result"),
826 desc: "abnormal test with arithmetic overflow for calculate transaction fee",
828 BlockHeader: types.BlockHeader{
830 PreviousBlockHash: bc.Hash{V0: 1},
832 Transactions: []*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})},
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})},
847 consensusResult: &ConsensusResult{
848 NumOfVote: map[string]uint64{},
849 CoinbaseReward: map[string]uint64{},
850 BlockHash: testutil.MustDecodeHash("02b7fb48defc4f4a3e1ef8403f7c0be78c4414ee66aa81fd702caa1e41a906df"),
853 wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
856 desc: "abnormal test with not found coinbase receiver",
858 BlockHeader: types.BlockHeader{
860 PreviousBlockHash: bc.Hash{V0: 1},
862 Transactions: []*types.Tx{},
864 consensusResult: &ConsensusResult{
865 NumOfVote: map[string]uint64{},
866 CoinbaseReward: map[string]uint64{},
867 BlockHash: testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
870 wantErr: errors.New("not found coinbase receiver"),
873 desc: "test number of vote overflow",
875 BlockHeader: types.BlockHeader{
876 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
877 PreviousBlockHash: bc.Hash{V0: 1},
879 Transactions: []*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})},
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)},
894 consensusResult: &ConsensusResult{
895 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
896 CoinbaseReward: map[string]uint64{
899 NumOfVote: map[string]uint64{},
901 wantErr: checked.ErrOverflow,
904 desc: "test number of veto overflow",
906 BlockHeader: types.BlockHeader{
907 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
908 PreviousBlockHash: bc.Hash{V0: 1},
910 Transactions: []*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})},
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})},
925 consensusResult: &ConsensusResult{
926 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
927 CoinbaseReward: map[string]uint64{
930 NumOfVote: map[string]uint64{
931 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 100,
934 wantErr: checked.ErrOverflow,
937 desc: "test detch coinbase overflow",
939 BlockHeader: types.BlockHeader{
940 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
941 PreviousBlockHash: bc.Hash{V0: 1},
943 Transactions: []*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})},
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})},
958 consensusResult: &ConsensusResult{
959 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
960 CoinbaseReward: map[string]uint64{},
961 NumOfVote: map[string]uint64{},
963 wantErr: checked.ErrOverflow,
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)
974 if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
975 t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
980 func TestGetCoinbaseRewards(t *testing.T) {
984 consensusResult *ConsensusResult
985 wantRewards []CoinbaseReward
988 desc: "the block height is RoundVoteBlockNums - 1",
989 blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums - 1,
990 consensusResult: &ConsensusResult{
991 CoinbaseReward: map[string]uint64{
995 wantRewards: []CoinbaseReward{},
998 desc: "the block height is RoundVoteBlockNums",
999 blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums,
1000 consensusResult: &ConsensusResult{
1001 CoinbaseReward: map[string]uint64{
1006 wantRewards: []CoinbaseReward{
1009 ControlProgram: []byte{0x52},
1013 ControlProgram: []byte{0x51},
1018 desc: "the block height is RoundVoteBlockNums + 1",
1019 blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums + 1,
1020 consensusResult: &ConsensusResult{
1021 CoinbaseReward: map[string]uint64{
1025 wantRewards: []CoinbaseReward{},
1028 desc: "the block height is RoundVoteBlockNums * 2",
1029 blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums * 2,
1030 consensusResult: &ConsensusResult{
1031 CoinbaseReward: map[string]uint64{
1038 wantRewards: []CoinbaseReward{
1041 ControlProgram: []byte{0x53},
1045 ControlProgram: []byte{0x52},
1049 ControlProgram: []byte{0x50},
1053 ControlProgram: []byte{0x51},
1058 desc: "the block height is 2*RoundVoteBlockNums + 1",
1059 blockHeight: 2*consensus.ActiveNetParams.RoundVoteBlockNums + 1,
1060 consensusResult: &ConsensusResult{
1061 CoinbaseReward: map[string]uint64{},
1063 wantRewards: []CoinbaseReward{},
1067 for i, c := range cases {
1068 rewards, err := c.consensusResult.GetCoinbaseRewards(c.blockHeight)
1073 if !testutil.DeepEqual(rewards, c.wantRewards) {
1074 t.Errorf("test case #%d, want %v, got %v", i, c.wantRewards, rewards)
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"
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))
1098 consensusResult *ConsensusResult
1099 consensusNode map[string]*ConsensusNode
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,
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},
1125 for i, c := range cases {
1126 consensusNode, err := c.consensusResult.ConsensusNodes()
1128 if err != c.wantErr {
1129 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
1134 if !testutil.DeepEqual(consensusNode, c.consensusNode) {
1135 t.Errorf("test case #%d, want %v, got %v", i, c.consensusNode, consensusNode)
1140 func TestFork(t *testing.T) {
1141 consensusResult := &ConsensusResult{
1143 NumOfVote: map[string]uint64{
1147 CoinbaseReward: map[string]uint64{
1151 BlockHash: bc.NewHash([32]byte{0x1, 0x2}),
1154 copy := consensusResult.Fork()
1156 if !reflect.DeepEqual(consensusResult, copy) {
1157 t.Fatalf("failed on test consensusResult got %s want %s", spew.Sdump(copy), spew.Sdump(consensusResult))