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 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-80000000, 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}): 80000000,
166 hex.EncodeToString([]byte{0x52}): 50000000,
169 postConsensusResult: &ConsensusResult{
170 CoinbaseReward: map[string]uint64{
171 hex.EncodeToString([]byte{0x51}): consensus.BlockSubsidy(1) + 50000000,
174 wantErr: checked.ErrOverflow,
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)
186 if !testutil.DeepEqual(c.prevConsensusResult, c.postConsensusResult) {
187 t.Errorf("test case #%d, want %v, got %v", i, c.postConsensusResult, c.prevConsensusResult)
192 func TestCalCoinbaseReward(t *testing.T) {
196 wantReward *CoinbaseReward
200 desc: "normal test with block contain coinbase tx and other tx",
202 BlockHeader: types.BlockHeader{
205 Transactions: []*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})},
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})},
220 wantReward: &CoinbaseReward{
221 Amount: consensus.BlockSubsidy(1) + 50000000,
222 ControlProgram: []byte{0x51},
226 desc: "normal test with block only contain coinbase tx",
228 BlockHeader: types.BlockHeader{
231 Transactions: []*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})},
240 wantReward: &CoinbaseReward{
241 Amount: consensus.BlockSubsidy(1),
242 ControlProgram: []byte{0x51},
246 desc: "abnormal test with block not contain coinbase tx",
248 BlockHeader: types.BlockHeader{
251 Transactions: []*types.Tx{},
253 wantErr: errors.New("not found coinbase receiver"),
257 for i, c := range cases {
258 coinbaseReward, err := CalCoinbaseReward(c.block)
260 if err.Error() != c.wantErr.Error() {
261 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
266 if !testutil.DeepEqual(coinbaseReward, c.wantReward) {
267 t.Errorf("test case #%d, want %v, got %v", i, c.wantReward, coinbaseReward)
272 func TestConsensusApplyBlock(t *testing.T) {
273 testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
277 consensusResult *ConsensusResult
278 wantResult *ConsensusResult
282 desc: "normal test with block height is equal to 1",
284 BlockHeader: types.BlockHeader{
286 PreviousBlockHash: bc.Hash{V0: 1},
288 Transactions: []*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})},
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})},
303 consensusResult: &ConsensusResult{
305 NumOfVote: map[string]uint64{},
306 CoinbaseReward: map[string]uint64{},
307 BlockHash: bc.Hash{V0: 1},
310 wantResult: &ConsensusResult{
312 NumOfVote: map[string]uint64{},
313 CoinbaseReward: map[string]uint64{
314 "51": consensus.BlockSubsidy(1) + 50000000,
316 BlockHash: testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
321 desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
323 BlockHeader: types.BlockHeader{
324 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
325 PreviousBlockHash: bc.Hash{V0: 1},
327 Transactions: []*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})},
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)},
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,
348 wantResult: &ConsensusResult{
350 NumOfVote: map[string]uint64{
351 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
353 CoinbaseReward: map[string]uint64{
354 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
356 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
357 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
361 desc: "normal test with block height is equal to RoundVoteBlockNums",
363 BlockHeader: types.BlockHeader{
364 Height: consensus.MainNetParams.RoundVoteBlockNums,
365 PreviousBlockHash: bc.Hash{V0: 1},
367 Transactions: []*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}),
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)},
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})},
390 consensusResult: &ConsensusResult{
391 NumOfVote: map[string]uint64{},
392 CoinbaseReward: map[string]uint64{
397 BlockHash: bc.Hash{V0: 1},
398 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
400 wantResult: &ConsensusResult{
402 NumOfVote: map[string]uint64{
403 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
405 CoinbaseReward: map[string]uint64{
406 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
410 BlockHash: testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
411 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
415 desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
417 BlockHeader: types.BlockHeader{
418 Height: consensus.MainNetParams.RoundVoteBlockNums + 1,
419 PreviousBlockHash: bc.Hash{V0: 1},
421 Transactions: []*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}),
435 consensusResult: &ConsensusResult{
436 NumOfVote: map[string]uint64{},
437 CoinbaseReward: map[string]uint64{
438 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
442 BlockHash: bc.Hash{V0: 1},
443 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
445 wantResult: &ConsensusResult{
447 NumOfVote: map[string]uint64{},
448 CoinbaseReward: map[string]uint64{
449 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
451 BlockHash: testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
452 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
456 desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
458 BlockHeader: types.BlockHeader{
459 Height: consensus.MainNetParams.RoundVoteBlockNums + 2,
460 PreviousBlockHash: bc.Hash{V0: 1},
462 Transactions: []*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}),
473 consensusResult: &ConsensusResult{
474 NumOfVote: map[string]uint64{},
475 CoinbaseReward: map[string]uint64{
476 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
478 BlockHash: bc.Hash{V0: 1},
479 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
481 wantResult: &ConsensusResult{
483 NumOfVote: map[string]uint64{},
484 CoinbaseReward: map[string]uint64{
485 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+2),
487 BlockHash: testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
488 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 2,
492 desc: "abnormal test with block parent hash is not equals last block hash of vote result",
494 BlockHeader: types.BlockHeader{
496 PreviousBlockHash: bc.Hash{V0: 0},
498 Transactions: []*types.Tx{},
500 consensusResult: &ConsensusResult{
501 NumOfVote: map[string]uint64{},
502 CoinbaseReward: map[string]uint64{},
503 BlockHash: bc.Hash{V0: 1},
506 wantErr: errors.New("block parent hash is not equals last block hash of vote result"),
509 desc: "abnormal test with arithmetic overflow for calculate transaction fee",
511 BlockHeader: types.BlockHeader{
513 PreviousBlockHash: bc.Hash{V0: 1},
515 Transactions: []*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})},
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})},
530 consensusResult: &ConsensusResult{
531 NumOfVote: map[string]uint64{},
532 CoinbaseReward: map[string]uint64{},
533 BlockHash: bc.Hash{V0: 1},
536 wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
539 desc: "abnormal test with not found coinbase receiver",
541 BlockHeader: types.BlockHeader{
543 PreviousBlockHash: bc.Hash{V0: 1},
545 Transactions: []*types.Tx{},
547 consensusResult: &ConsensusResult{
548 NumOfVote: map[string]uint64{},
549 CoinbaseReward: map[string]uint64{},
550 BlockHash: bc.Hash{V0: 1},
553 wantErr: errors.New("not found coinbase receiver"),
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)
565 if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
566 t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
571 func TestConsensusDetachBlock(t *testing.T) {
572 testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
576 consensusResult *ConsensusResult
577 wantResult *ConsensusResult
581 desc: "normal test with block height is equal to 1",
583 BlockHeader: types.BlockHeader{
585 PreviousBlockHash: bc.Hash{V0: 1},
587 Transactions: []*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})},
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})},
602 consensusResult: &ConsensusResult{
604 NumOfVote: map[string]uint64{},
605 CoinbaseReward: map[string]uint64{
606 "51": consensus.BlockSubsidy(1) + 50000000,
608 BlockHash: testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
611 wantResult: &ConsensusResult{
613 NumOfVote: map[string]uint64{},
614 CoinbaseReward: map[string]uint64{},
615 BlockHash: bc.Hash{V0: 1},
620 desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
622 BlockHeader: types.BlockHeader{
623 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
624 PreviousBlockHash: bc.Hash{V0: 1},
626 Transactions: []*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})},
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)},
641 consensusResult: &ConsensusResult{
642 NumOfVote: map[string]uint64{
643 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
645 CoinbaseReward: map[string]uint64{
646 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
648 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
649 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
651 wantResult: &ConsensusResult{
653 NumOfVote: map[string]uint64{},
654 CoinbaseReward: map[string]uint64{},
655 BlockHash: bc.Hash{V0: 1},
656 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 2,
660 desc: "normal test with block height is equal to RoundVoteBlockNums",
662 BlockHeader: types.BlockHeader{
663 Height: consensus.MainNetParams.RoundVoteBlockNums,
664 PreviousBlockHash: bc.Hash{V0: 1},
666 Transactions: []*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}),
677 consensusResult: &ConsensusResult{
678 NumOfVote: map[string]uint64{
679 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
681 CoinbaseReward: map[string]uint64{
682 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 100000000,
684 BlockHash: testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
685 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
687 wantResult: &ConsensusResult{
689 NumOfVote: map[string]uint64{
690 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
692 CoinbaseReward: map[string]uint64{
695 BlockHash: bc.Hash{V0: 1},
696 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
700 desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
702 BlockHeader: types.BlockHeader{
703 Height: consensus.MainNetParams.RoundVoteBlockNums + 1,
704 PreviousBlockHash: bc.Hash{V0: 1},
706 Transactions: []*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}),
719 consensusResult: &ConsensusResult{
720 NumOfVote: map[string]uint64{},
721 CoinbaseReward: map[string]uint64{
722 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
724 BlockHash: testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
725 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
727 wantResult: &ConsensusResult{
729 NumOfVote: map[string]uint64{},
730 CoinbaseReward: map[string]uint64{
731 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
734 BlockHash: bc.Hash{V0: 1},
735 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
739 desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
741 BlockHeader: types.BlockHeader{
742 Height: consensus.MainNetParams.RoundVoteBlockNums + 2,
743 PreviousBlockHash: bc.Hash{V0: 1},
745 Transactions: []*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}),
756 consensusResult: &ConsensusResult{
757 NumOfVote: map[string]uint64{},
758 CoinbaseReward: map[string]uint64{
759 "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + 1000000,
761 BlockHash: testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
762 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
764 wantResult: &ConsensusResult{
766 NumOfVote: map[string]uint64{},
767 CoinbaseReward: map[string]uint64{
770 BlockHash: bc.Hash{V0: 1},
771 BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
775 desc: "abnormal test with block hash is not equals last block hash of vote result",
777 BlockHeader: types.BlockHeader{
779 PreviousBlockHash: bc.Hash{V0: 0},
781 Transactions: []*types.Tx{},
783 consensusResult: &ConsensusResult{
784 NumOfVote: map[string]uint64{},
785 CoinbaseReward: map[string]uint64{},
786 BlockHash: bc.Hash{V0: 1},
789 wantErr: errors.New("block hash is not equals last block hash of vote result"),
792 desc: "abnormal test with arithmetic overflow for calculate transaction fee",
794 BlockHeader: types.BlockHeader{
796 PreviousBlockHash: bc.Hash{V0: 1},
798 Transactions: []*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})},
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})},
813 consensusResult: &ConsensusResult{
814 NumOfVote: map[string]uint64{},
815 CoinbaseReward: map[string]uint64{},
816 BlockHash: testutil.MustDecodeHash("02b7fb48defc4f4a3e1ef8403f7c0be78c4414ee66aa81fd702caa1e41a906df"),
819 wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
822 desc: "abnormal test with not found coinbase receiver",
824 BlockHeader: types.BlockHeader{
826 PreviousBlockHash: bc.Hash{V0: 1},
828 Transactions: []*types.Tx{},
830 consensusResult: &ConsensusResult{
831 NumOfVote: map[string]uint64{},
832 CoinbaseReward: map[string]uint64{},
833 BlockHash: testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
836 wantErr: errors.New("not found coinbase receiver"),
839 desc: "test number of vote overflow",
841 BlockHeader: types.BlockHeader{
842 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
843 PreviousBlockHash: bc.Hash{V0: 1},
845 Transactions: []*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})},
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)},
860 consensusResult: &ConsensusResult{
861 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
862 CoinbaseReward: map[string]uint64{
865 NumOfVote: map[string]uint64{},
867 wantErr: checked.ErrOverflow,
870 desc: "test number of veto overflow",
872 BlockHeader: types.BlockHeader{
873 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
874 PreviousBlockHash: bc.Hash{V0: 1},
876 Transactions: []*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})},
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})},
891 consensusResult: &ConsensusResult{
892 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
893 CoinbaseReward: map[string]uint64{
896 NumOfVote: map[string]uint64{
897 "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 100,
900 wantErr: checked.ErrOverflow,
903 desc: "test detch coinbase overflow",
905 BlockHeader: types.BlockHeader{
906 Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
907 PreviousBlockHash: bc.Hash{V0: 1},
909 Transactions: []*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})},
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})},
924 consensusResult: &ConsensusResult{
925 BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
926 CoinbaseReward: map[string]uint64{},
927 NumOfVote: map[string]uint64{},
929 wantErr: checked.ErrOverflow,
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)
940 if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
941 t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
946 func TestGetCoinbaseRewards(t *testing.T) {
950 consensusResult *ConsensusResult
951 wantRewards []CoinbaseReward
954 desc: "the block height is RoundVoteBlockNums - 1",
955 blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums - 1,
956 consensusResult: &ConsensusResult{
957 CoinbaseReward: map[string]uint64{
961 wantRewards: []CoinbaseReward{},
964 desc: "the block height is RoundVoteBlockNums",
965 blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums,
966 consensusResult: &ConsensusResult{
967 CoinbaseReward: map[string]uint64{
972 wantRewards: []CoinbaseReward{
975 ControlProgram: []byte{0x52},
979 ControlProgram: []byte{0x51},
984 desc: "the block height is RoundVoteBlockNums + 1",
985 blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums + 1,
986 consensusResult: &ConsensusResult{
987 CoinbaseReward: map[string]uint64{
991 wantRewards: []CoinbaseReward{},
994 desc: "the block height is RoundVoteBlockNums * 2",
995 blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums * 2,
996 consensusResult: &ConsensusResult{
997 CoinbaseReward: map[string]uint64{
1004 wantRewards: []CoinbaseReward{
1007 ControlProgram: []byte{0x53},
1011 ControlProgram: []byte{0x52},
1015 ControlProgram: []byte{0x50},
1019 ControlProgram: []byte{0x51},
1024 desc: "the block height is 2*RoundVoteBlockNums + 1",
1025 blockHeight: 2*consensus.ActiveNetParams.RoundVoteBlockNums + 1,
1026 consensusResult: &ConsensusResult{
1027 CoinbaseReward: map[string]uint64{},
1029 wantRewards: []CoinbaseReward{},
1033 for i, c := range cases {
1034 rewards, err := c.consensusResult.GetCoinbaseRewards(c.blockHeight)
1039 if !testutil.DeepEqual(rewards, c.wantRewards) {
1040 t.Errorf("test case #%d, want %v, got %v", i, c.wantRewards, rewards)
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"
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))
1064 consensusResult *ConsensusResult
1065 consensusNode map[string]*ConsensusNode
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,
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},
1088 wantErr: chainkd.ErrBadKeyStr,
1092 for i, c := range cases {
1093 consensusNode, err := c.consensusResult.ConsensusNodes()
1095 if err != c.wantErr {
1096 t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
1101 if !testutil.DeepEqual(consensusNode, c.consensusNode) {
1102 t.Errorf("test case #%d, want %v, got %v", i, c.consensusNode, consensusNode)
1107 func TestFork(t *testing.T) {
1108 consensusResult := &ConsensusResult{
1110 NumOfVote: map[string]uint64{
1114 CoinbaseReward: map[string]uint64{
1118 BlockHash: bc.NewHash([32]byte{0x1, 0x2}),
1121 copy := consensusResult.Fork()
1123 if !reflect.DeepEqual(consensusResult, copy) {
1124 t.Fatalf("failed on test consensusResult got %s want %s", spew.Sdump(copy), spew.Sdump(consensusResult))