• R/O
  • HTTP
  • SSH
  • HTTPS

vapor: Commit

Golang implemented sidechain for Bytom


Commit MetaInfo

Revisionaece9c02c1f342d7ec301981c2afa4b8d1fe0e6a (tree)
Time2019-07-19 19:13:53
Authoroysheng <33340252+oysheng@user...>
CommiterPaladz

Log Message

modify consensusResult for block (#324)

* modify consensusResult for block

* delete

* optimise

Change Summary

Incremental Difference

--- a/proposal/proposal.go
+++ b/proposal/proposal.go
@@ -24,7 +24,7 @@ const logModule = "mining"
2424 // createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
2525 // based on the passed block height to the provided address. When the address
2626 // is nil, the coinbase transaction will instead be redeemable by anyone.
27-func createCoinbaseTx(accountManager *account.Manager, blockHeight uint64) (tx *types.Tx, err error) {
27+func createCoinbaseTx(accountManager *account.Manager, blockHeight uint64, rewards []state.CoinbaseReward) (tx *types.Tx, err error) {
2828 arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(blockHeight, 10))...)
2929 var script []byte
3030 if accountManager == nil {
@@ -49,11 +49,23 @@ func createCoinbaseTx(accountManager *account.Manager, blockHeight uint64) (tx *
4949 return nil, err
5050 }
5151
52+ for _, r := range rewards {
53+ if err = builder.AddOutput(types.NewIntraChainOutput(*consensus.BTMAssetID, r.Amount, r.ControlProgram)); err != nil {
54+ return nil, err
55+ }
56+ }
57+
5258 _, txData, err := builder.Build()
5359 if err != nil {
5460 return nil, err
5561 }
5662
63+ byteData, err := txData.MarshalText()
64+ if err != nil {
65+ return nil, err
66+ }
67+
68+ txData.SerializedSize = uint64(len(byteData))
5769 tx = &types.Tx{
5870 TxData: *txData,
5971 Tx: types.MapTx(txData),
@@ -61,22 +73,6 @@ func createCoinbaseTx(accountManager *account.Manager, blockHeight uint64) (tx *
6173 return tx, nil
6274 }
6375
64-// restructCoinbaseTx build coinbase transaction with aggregate outputs when it achieved the specified block height
65-func restructCoinbaseTx(tx *types.Tx, rewards []state.CoinbaseReward) error {
66- for _, r := range rewards {
67- tx.Outputs = append(tx.Outputs, types.NewIntraChainOutput(*consensus.BTMAssetID, r.Amount, r.ControlProgram))
68- }
69-
70- byteData, err := tx.TxData.MarshalText()
71- if err != nil {
72- return err
73- }
74-
75- tx.TxData.SerializedSize = uint64(len(byteData))
76- tx.Tx = types.MapTx(&tx.TxData)
77- return nil
78-}
79-
8076 // NewBlockTemplate returns a new block template that is ready to be solved
8177 func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager *account.Manager, timestamp uint64) (b *types.Block, err error) {
8278 view := state.NewUtxoViewpoint()
@@ -155,28 +151,19 @@ func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager
155151
156152 }
157153
158- // create coinbase transaction
159- b.Transactions[0], err = createCoinbaseTx(accountManager, nextBlockHeight)
160- if err != nil {
161- return nil, errors.Wrap(err, "fail on createCoinbaseTx")
162- }
163-
164154 consensusResult, err := c.GetConsensusResultByHash(&preBlockHash)
165155 if err != nil {
166156 return nil, err
167157 }
168158
169- if err := consensusResult.AttachCoinbaseReward(b); err != nil {
170- return nil, err
171- }
172-
173- rewards, err := consensusResult.GetCoinbaseRewards(nextBlockHeight)
159+ rewards, err := consensusResult.GetCoinbaseRewards(preBlockHeader.Height)
174160 if err != nil {
175161 return nil, err
176162 }
177163
178- // restruct coinbase transaction
179- if err = restructCoinbaseTx(b.Transactions[0], rewards); err != nil {
164+ // create coinbase transaction
165+ b.Transactions[0], err = createCoinbaseTx(accountManager, nextBlockHeight, rewards)
166+ if err != nil {
180167 return nil, errors.Wrap(err, "fail on createCoinbaseTx")
181168 }
182169
--- a/proposal/proposal_test.go
+++ b/proposal/proposal_test.go
@@ -1,13 +1,12 @@
11 package proposal
22
33 import (
4- "encoding/hex"
54 "testing"
65
76 "github.com/vapor/consensus"
7+ "github.com/vapor/protocol/bc"
88 "github.com/vapor/protocol/bc/types"
99 "github.com/vapor/protocol/state"
10- "github.com/vapor/protocol/vm/vmutil"
1110 "github.com/vapor/testutil"
1211 )
1312
@@ -21,10 +20,9 @@ func TestCalCoinbaseTxReward(t *testing.T) {
2120 reductionInterval := uint64(840000)
2221
2322 cases := []struct {
24- desc string
25- block *types.Block
26- consensusResult *state.ConsensusResult
27- wantReward state.CoinbaseReward
23+ desc string
24+ block *types.Block
25+ wantReward state.CoinbaseReward
2826 }{
2927 {
3028 desc: "the block height is reductionInterval - 1",
@@ -32,10 +30,14 @@ func TestCalCoinbaseTxReward(t *testing.T) {
3230 BlockHeader: types.BlockHeader{
3331 Height: reductionInterval - 1,
3432 },
35- Transactions: []*types.Tx{nil},
36- },
37- consensusResult: &state.ConsensusResult{
38- CoinbaseReward: map[string]uint64{},
33+ Transactions: []*types.Tx{
34+ &types.Tx{
35+ TxData: types.TxData{
36+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
37+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
38+ },
39+ },
40+ },
3941 },
4042 wantReward: state.CoinbaseReward{
4143 Amount: 24,
@@ -48,10 +50,14 @@ func TestCalCoinbaseTxReward(t *testing.T) {
4850 BlockHeader: types.BlockHeader{
4951 Height: reductionInterval,
5052 },
51- Transactions: []*types.Tx{nil},
52- },
53- consensusResult: &state.ConsensusResult{
54- CoinbaseReward: map[string]uint64{},
53+ Transactions: []*types.Tx{
54+ &types.Tx{
55+ TxData: types.TxData{
56+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
57+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
58+ },
59+ },
60+ },
5561 },
5662 wantReward: state.CoinbaseReward{
5763 Amount: 24,
@@ -64,10 +70,14 @@ func TestCalCoinbaseTxReward(t *testing.T) {
6470 BlockHeader: types.BlockHeader{
6571 Height: reductionInterval + 1,
6672 },
67- Transactions: []*types.Tx{nil},
68- },
69- consensusResult: &state.ConsensusResult{
70- CoinbaseReward: map[string]uint64{},
73+ Transactions: []*types.Tx{
74+ &types.Tx{
75+ TxData: types.TxData{
76+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
77+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
78+ },
79+ },
80+ },
7181 },
7282 wantReward: state.CoinbaseReward{
7383 Amount: 12,
@@ -80,10 +90,14 @@ func TestCalCoinbaseTxReward(t *testing.T) {
8090 BlockHeader: types.BlockHeader{
8191 Height: reductionInterval * 2,
8292 },
83- Transactions: []*types.Tx{nil},
84- },
85- consensusResult: &state.ConsensusResult{
86- CoinbaseReward: map[string]uint64{},
93+ Transactions: []*types.Tx{
94+ &types.Tx{
95+ TxData: types.TxData{
96+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
97+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
98+ },
99+ },
100+ },
87101 },
88102 wantReward: state.CoinbaseReward{
89103 Amount: 12,
@@ -96,10 +110,14 @@ func TestCalCoinbaseTxReward(t *testing.T) {
96110 BlockHeader: types.BlockHeader{
97111 Height: 2*reductionInterval + 1,
98112 },
99- Transactions: []*types.Tx{nil},
100- },
101- consensusResult: &state.ConsensusResult{
102- CoinbaseReward: map[string]uint64{},
113+ Transactions: []*types.Tx{
114+ &types.Tx{
115+ TxData: types.TxData{
116+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
117+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
118+ },
119+ },
120+ },
103121 },
104122 wantReward: state.CoinbaseReward{
105123 Amount: 6,
@@ -108,25 +126,14 @@ func TestCalCoinbaseTxReward(t *testing.T) {
108126 },
109127 }
110128
111- var err error
112129 for i, c := range cases {
113- c.block.Transactions[0], err = createCoinbaseTx(nil, c.block.Height)
130+ gotReward, err := state.CalCoinbaseReward(c.block)
114131 if err != nil {
115132 t.Fatal(err)
116133 }
117134
118- if err := c.consensusResult.AttachCoinbaseReward(c.block); err != nil {
119- t.Fatal(err)
120- }
121-
122- defaultProgram, _ := vmutil.DefaultCoinbaseProgram()
123- gotReward := state.CoinbaseReward{
124- Amount: c.consensusResult.CoinbaseReward[hex.EncodeToString(defaultProgram)],
125- ControlProgram: defaultProgram,
126- }
127-
128- if !testutil.DeepEqual(gotReward, c.wantReward) {
129- t.Fatalf("test case %d: %s, the coinbase reward got: %v, want: %v", i, c.desc, gotReward, c.wantReward)
135+ if !testutil.DeepEqual(*gotReward, c.wantReward) {
136+ t.Fatalf("test case %d: %s, the coinbase reward got: %v, want: %v", i, c.desc, *gotReward, c.wantReward)
130137 }
131138 }
132139 }
@@ -140,10 +147,11 @@ func TestCountCoinbaseTxRewards(t *testing.T) {
140147 }
141148
142149 cases := []struct {
143- desc string
144- block *types.Block
145- consensusResult *state.ConsensusResult
146- wantRewards []state.CoinbaseReward
150+ desc string
151+ block *types.Block
152+ consensusResult *state.ConsensusResult
153+ wantRewards []state.CoinbaseReward
154+ wantConsensusResult *state.ConsensusResult
147155 }{
148156 {
149157 desc: "the block height is RoundVoteBlockNums - 1",
@@ -159,6 +167,11 @@ func TestCountCoinbaseTxRewards(t *testing.T) {
159167 },
160168 },
161169 wantRewards: []state.CoinbaseReward{},
170+ wantConsensusResult: &state.ConsensusResult{
171+ CoinbaseReward: map[string]uint64{
172+ "51": 34,
173+ },
174+ },
162175 },
163176 {
164177 desc: "the block height is RoundVoteBlockNums",
@@ -174,14 +187,11 @@ func TestCountCoinbaseTxRewards(t *testing.T) {
174187 "52": 20,
175188 },
176189 },
177- wantRewards: []state.CoinbaseReward{
178- state.CoinbaseReward{
179- Amount: 34,
180- ControlProgram: []byte{0x51},
181- },
182- state.CoinbaseReward{
183- Amount: 20,
184- ControlProgram: []byte{0x52},
190+ wantRewards: []state.CoinbaseReward{},
191+ wantConsensusResult: &state.ConsensusResult{
192+ CoinbaseReward: map[string]uint64{
193+ "51": 34,
194+ "52": 20,
185195 },
186196 },
187197 },
@@ -198,7 +208,17 @@ func TestCountCoinbaseTxRewards(t *testing.T) {
198208 "51": 10,
199209 },
200210 },
201- wantRewards: []state.CoinbaseReward{},
211+ wantRewards: []state.CoinbaseReward{
212+ state.CoinbaseReward{
213+ Amount: 10,
214+ ControlProgram: []byte{0x51},
215+ },
216+ },
217+ wantConsensusResult: &state.ConsensusResult{
218+ CoinbaseReward: map[string]uint64{
219+ "51": 24,
220+ },
221+ },
202222 },
203223 {
204224 desc: "the block height is RoundVoteBlockNums * 2",
@@ -210,28 +230,13 @@ func TestCountCoinbaseTxRewards(t *testing.T) {
210230 },
211231 consensusResult: &state.ConsensusResult{
212232 CoinbaseReward: map[string]uint64{
213- "50": 20,
214233 "51": 10,
215- "52": 20,
216- "53": 30,
217234 },
218235 },
219- wantRewards: []state.CoinbaseReward{
220- state.CoinbaseReward{
221- Amount: 34,
222- ControlProgram: []byte{0x51},
223- },
224- state.CoinbaseReward{
225- Amount: 30,
226- ControlProgram: []byte{0x53},
227- },
228- state.CoinbaseReward{
229- Amount: 20,
230- ControlProgram: []byte{0x52},
231- },
232- state.CoinbaseReward{
233- Amount: 20,
234- ControlProgram: []byte{0x50},
236+ wantRewards: []state.CoinbaseReward{},
237+ wantConsensusResult: &state.ConsensusResult{
238+ CoinbaseReward: map[string]uint64{
239+ "51": 34,
235240 },
236241 },
237242 },
@@ -244,29 +249,51 @@ func TestCountCoinbaseTxRewards(t *testing.T) {
244249 Transactions: []*types.Tx{nil},
245250 },
246251 consensusResult: &state.ConsensusResult{
247- CoinbaseReward: map[string]uint64{},
252+ CoinbaseReward: map[string]uint64{
253+ "51": 10,
254+ "52": 20,
255+ },
256+ },
257+ wantRewards: []state.CoinbaseReward{
258+ state.CoinbaseReward{
259+ Amount: 20,
260+ ControlProgram: []byte{0x52},
261+ },
262+ state.CoinbaseReward{
263+ Amount: 10,
264+ ControlProgram: []byte{0x51},
265+ },
266+ },
267+ wantConsensusResult: &state.ConsensusResult{
268+ CoinbaseReward: map[string]uint64{
269+ "51": 24,
270+ },
248271 },
249- wantRewards: []state.CoinbaseReward{},
250272 },
251273 }
252274
253- var err error
254275 for i, c := range cases {
255- c.block.Transactions[0], err = createCoinbaseTx(nil, c.block.Height)
276+ rewards, err := c.consensusResult.GetCoinbaseRewards(c.block.Height - 1)
256277 if err != nil {
257278 t.Fatal(err)
258279 }
259280
260- if err := c.consensusResult.AttachCoinbaseReward(c.block); err != nil {
261- t.Fatal(err)
281+ if !testutil.DeepEqual(rewards, c.wantRewards) {
282+ t.Fatalf("test case %d: %s, the coinbase reward got: %v, want: %v", i, c.desc, rewards, c.wantRewards)
262283 }
263284
264- rewards, err := c.consensusResult.GetCoinbaseRewards(c.block.Height)
285+ // create coinbase transaction
286+ c.block.Transactions[0], err = createCoinbaseTx(nil, c.block.Height, rewards)
265287 if err != nil {
266288 t.Fatal(err)
267289 }
268- if !testutil.DeepEqual(rewards, c.wantRewards) {
269- t.Fatalf("test case %d: %s, the coinbase reward got: %v, want: %v", i, c.desc, rewards, c.wantRewards)
290+
291+ if err := c.consensusResult.AttachCoinbaseReward(c.block); err != nil {
292+ t.Fatal(err)
293+ }
294+
295+ if !testutil.DeepEqual(c.consensusResult, c.wantConsensusResult) {
296+ t.Fatalf("test case %d: %s, the consensusResult got: %v, want: %v", i, c.desc, c.consensusResult, c.wantConsensusResult)
270297 }
271298 }
272299 }
--- a/protocol/block.go
+++ b/protocol/block.go
@@ -265,11 +265,7 @@ func (c *Chain) saveBlock(block *types.Block) error {
265265 return err
266266 }
267267
268- if err := consensusResult.AttachCoinbaseReward(block); err != nil {
269- return err
270- }
271-
272- rewards, err := consensusResult.GetCoinbaseRewards(block.Height)
268+ rewards, err := consensusResult.GetCoinbaseRewards(parent.Height)
273269 if err != nil {
274270 return err
275271 }
--- a/protocol/state/consensus_result.go
+++ b/protocol/state/consensus_result.go
@@ -251,16 +251,6 @@ func (c *ConsensusResult) DetachBlock(block *types.Block) error {
251251
252252 // DetachCoinbaseReward detach coinbase reward
253253 func (c *ConsensusResult) DetachCoinbaseReward(block *types.Block) error {
254- if block.Height%consensus.ActiveNetParams.RoundVoteBlockNums == 0 {
255- for i, output := range block.Transactions[0].Outputs {
256- if i == 0 {
257- continue
258- }
259- program := output.ControlProgram()
260- c.CoinbaseReward[hex.EncodeToString(program)] = output.AssetAmount().Amount
261- }
262- }
263-
264254 reward, err := CalCoinbaseReward(block)
265255 if err != nil {
266256 return err
@@ -275,6 +265,17 @@ func (c *ConsensusResult) DetachCoinbaseReward(block *types.Block) error {
275265 if c.CoinbaseReward[program] == 0 {
276266 delete(c.CoinbaseReward, program)
277267 }
268+
269+ if block.Height%consensus.ActiveNetParams.RoundVoteBlockNums == 1 {
270+ c.CoinbaseReward = map[string]uint64{}
271+ for i, output := range block.Transactions[0].Outputs {
272+ if i == 0 {
273+ continue
274+ }
275+ program := output.ControlProgram()
276+ c.CoinbaseReward[hex.EncodeToString(program)] = output.AssetAmount().Amount
277+ }
278+ }
278279 return nil
279280 }
280281
--- /dev/null
+++ b/protocol/state/consensus_result_test.go
@@ -0,0 +1,774 @@
1+package state
2+
3+import (
4+ "encoding/hex"
5+ "testing"
6+
7+ "github.com/vapor/consensus"
8+ "github.com/vapor/errors"
9+ "github.com/vapor/math/checked"
10+ "github.com/vapor/protocol/bc"
11+ "github.com/vapor/protocol/bc/types"
12+ "github.com/vapor/testutil"
13+)
14+
15+func TestCalCoinbaseReward(t *testing.T) {
16+ cases := []struct {
17+ desc string
18+ block *types.Block
19+ wantReward *CoinbaseReward
20+ wantErr error
21+ }{
22+ {
23+ desc: "normal test with block contain coinbase tx and other tx",
24+ block: &types.Block{
25+ BlockHeader: types.BlockHeader{
26+ Height: 1,
27+ },
28+ Transactions: []*types.Tx{
29+ &types.Tx{
30+ TxData: types.TxData{
31+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
32+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
33+ },
34+ },
35+ &types.Tx{
36+ TxData: types.TxData{
37+ Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)},
38+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
39+ },
40+ },
41+ },
42+ },
43+ wantReward: &CoinbaseReward{
44+ Amount: consensus.BlockSubsidy(1) + 50000000,
45+ ControlProgram: []byte{0x51},
46+ },
47+ },
48+ {
49+ desc: "normal test with block only contain coinbase tx",
50+ block: &types.Block{
51+ BlockHeader: types.BlockHeader{
52+ Height: 1200,
53+ },
54+ Transactions: []*types.Tx{
55+ &types.Tx{
56+ TxData: types.TxData{
57+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
58+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 1000000000, []byte{0x51})},
59+ },
60+ },
61+ },
62+ },
63+ wantReward: &CoinbaseReward{
64+ Amount: consensus.BlockSubsidy(1),
65+ ControlProgram: []byte{0x51},
66+ },
67+ },
68+ {
69+ desc: "abnormal test with block not contain coinbase tx",
70+ block: &types.Block{
71+ BlockHeader: types.BlockHeader{
72+ Height: 1,
73+ },
74+ Transactions: []*types.Tx{},
75+ },
76+ wantErr: errors.New("not found coinbase receiver"),
77+ },
78+ }
79+
80+ for i, c := range cases {
81+ coinbaseReward, err := CalCoinbaseReward(c.block)
82+ if err != nil {
83+ if err.Error() != c.wantErr.Error() {
84+ t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
85+ }
86+ continue
87+ }
88+
89+ if !testutil.DeepEqual(coinbaseReward, c.wantReward) {
90+ t.Errorf("test case #%d, want %v, got %v", i, c.wantReward, coinbaseReward)
91+ }
92+ }
93+}
94+
95+func TestConsensusApplyBlock(t *testing.T) {
96+ testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
97+ cases := []struct {
98+ desc string
99+ block *types.Block
100+ consensusResult *ConsensusResult
101+ wantResult *ConsensusResult
102+ wantErr error
103+ }{
104+ {
105+ desc: "normal test with block height is equal to 1",
106+ block: &types.Block{
107+ BlockHeader: types.BlockHeader{
108+ Height: 1,
109+ PreviousBlockHash: bc.Hash{V0: 1},
110+ },
111+ Transactions: []*types.Tx{
112+ &types.Tx{
113+ TxData: types.TxData{
114+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
115+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
116+ },
117+ },
118+ &types.Tx{
119+ TxData: types.TxData{
120+ Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)},
121+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
122+ },
123+ },
124+ },
125+ },
126+ consensusResult: &ConsensusResult{
127+ Seq: 0,
128+ NumOfVote: map[string]uint64{},
129+ CoinbaseReward: map[string]uint64{},
130+ BlockHash: bc.Hash{V0: 1},
131+ BlockHeight: 0,
132+ },
133+ wantResult: &ConsensusResult{
134+ Seq: 1,
135+ NumOfVote: map[string]uint64{},
136+ CoinbaseReward: map[string]uint64{
137+ "51": consensus.BlockSubsidy(1) + 50000000,
138+ },
139+ BlockHash: testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
140+ BlockHeight: 1,
141+ },
142+ },
143+ {
144+ desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
145+ block: &types.Block{
146+ BlockHeader: types.BlockHeader{
147+ Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
148+ PreviousBlockHash: bc.Hash{V0: 1},
149+ },
150+ Transactions: []*types.Tx{
151+ &types.Tx{
152+ TxData: types.TxData{
153+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
154+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
155+ },
156+ },
157+ &types.Tx{
158+ TxData: types.TxData{
159+ Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
160+ Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
161+ },
162+ },
163+ },
164+ },
165+ consensusResult: &ConsensusResult{
166+ NumOfVote: map[string]uint64{},
167+ CoinbaseReward: map[string]uint64{},
168+ BlockHash: bc.Hash{V0: 1},
169+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 2,
170+ },
171+ wantResult: &ConsensusResult{
172+ Seq: 1,
173+ NumOfVote: map[string]uint64{
174+ "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
175+ },
176+ CoinbaseReward: map[string]uint64{
177+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
178+ },
179+ BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
180+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
181+ },
182+ },
183+ {
184+ desc: "normal test with block height is equal to RoundVoteBlockNums",
185+ block: &types.Block{
186+ BlockHeader: types.BlockHeader{
187+ Height: consensus.MainNetParams.RoundVoteBlockNums,
188+ PreviousBlockHash: bc.Hash{V0: 1},
189+ },
190+ Transactions: []*types.Tx{
191+ &types.Tx{
192+ TxData: types.TxData{
193+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
194+ Outputs: []*types.TxOutput{
195+ types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
196+ },
197+ },
198+ },
199+ &types.Tx{
200+ TxData: types.TxData{
201+ Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
202+ Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
203+ },
204+ },
205+ &types.Tx{
206+ TxData: types.TxData{
207+ Inputs: []*types.TxInput{types.NewVetoInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, []byte{0x51}, testXpub)},
208+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 100000000, []byte{0x51})},
209+ },
210+ },
211+ },
212+ },
213+ consensusResult: &ConsensusResult{
214+ NumOfVote: map[string]uint64{},
215+ CoinbaseReward: map[string]uint64{
216+ "51": 10000000,
217+ "52": 20000000,
218+ "53": 30000000,
219+ },
220+ BlockHash: bc.Hash{V0: 1},
221+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
222+ },
223+ wantResult: &ConsensusResult{
224+ Seq: 1,
225+ NumOfVote: map[string]uint64{
226+ "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
227+ },
228+ CoinbaseReward: map[string]uint64{
229+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
230+ "52": 20000000,
231+ "53": 30000000,
232+ },
233+ BlockHash: testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
234+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
235+ },
236+ },
237+ {
238+ desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
239+ block: &types.Block{
240+ BlockHeader: types.BlockHeader{
241+ Height: consensus.MainNetParams.RoundVoteBlockNums + 1,
242+ PreviousBlockHash: bc.Hash{V0: 1},
243+ },
244+ Transactions: []*types.Tx{
245+ &types.Tx{
246+ TxData: types.TxData{
247+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
248+ Outputs: []*types.TxOutput{
249+ types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
250+ types.NewIntraChainOutput(bc.AssetID{}, consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums)+10000000, []byte{0x51}),
251+ types.NewIntraChainOutput(bc.AssetID{}, 20000000, []byte{0x53}),
252+ types.NewIntraChainOutput(bc.AssetID{}, 30000000, []byte{0x52}),
253+ },
254+ },
255+ },
256+ },
257+ },
258+ consensusResult: &ConsensusResult{
259+ NumOfVote: map[string]uint64{},
260+ CoinbaseReward: map[string]uint64{
261+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
262+ "52": 20000000,
263+ "53": 30000000,
264+ },
265+ BlockHash: bc.Hash{V0: 1},
266+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
267+ },
268+ wantResult: &ConsensusResult{
269+ Seq: 2,
270+ NumOfVote: map[string]uint64{},
271+ CoinbaseReward: map[string]uint64{
272+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
273+ },
274+ BlockHash: testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
275+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
276+ },
277+ },
278+ {
279+ desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
280+ block: &types.Block{
281+ BlockHeader: types.BlockHeader{
282+ Height: consensus.MainNetParams.RoundVoteBlockNums + 2,
283+ PreviousBlockHash: bc.Hash{V0: 1},
284+ },
285+ Transactions: []*types.Tx{
286+ &types.Tx{
287+ TxData: types.TxData{
288+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
289+ Outputs: []*types.TxOutput{
290+ types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
291+ },
292+ },
293+ },
294+ },
295+ },
296+ consensusResult: &ConsensusResult{
297+ NumOfVote: map[string]uint64{},
298+ CoinbaseReward: map[string]uint64{
299+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
300+ },
301+ BlockHash: bc.Hash{V0: 1},
302+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
303+ },
304+ wantResult: &ConsensusResult{
305+ Seq: 2,
306+ NumOfVote: map[string]uint64{},
307+ CoinbaseReward: map[string]uint64{
308+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+2),
309+ },
310+ BlockHash: testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
311+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 2,
312+ },
313+ },
314+ {
315+ desc: "abnormal test with block parent hash is not equals last block hash of vote result",
316+ block: &types.Block{
317+ BlockHeader: types.BlockHeader{
318+ Height: 1,
319+ PreviousBlockHash: bc.Hash{V0: 0},
320+ },
321+ Transactions: []*types.Tx{},
322+ },
323+ consensusResult: &ConsensusResult{
324+ NumOfVote: map[string]uint64{},
325+ CoinbaseReward: map[string]uint64{},
326+ BlockHash: bc.Hash{V0: 1},
327+ BlockHeight: 2,
328+ },
329+ wantErr: errors.New("block parent hash is not equals last block hash of vote result"),
330+ },
331+ {
332+ desc: "abnormal test with arithmetic overflow for calculate transaction fee",
333+ block: &types.Block{
334+ BlockHeader: types.BlockHeader{
335+ Height: 1,
336+ PreviousBlockHash: bc.Hash{V0: 1},
337+ },
338+ Transactions: []*types.Tx{
339+ &types.Tx{
340+ TxData: types.TxData{
341+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
342+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
343+ },
344+ },
345+ &types.Tx{
346+ TxData: types.TxData{
347+ Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, nil)},
348+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 200000000, []byte{0x51})},
349+ },
350+ },
351+ },
352+ },
353+ consensusResult: &ConsensusResult{
354+ NumOfVote: map[string]uint64{},
355+ CoinbaseReward: map[string]uint64{},
356+ BlockHash: bc.Hash{V0: 1},
357+ BlockHeight: 2,
358+ },
359+ wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
360+ },
361+ {
362+ desc: "abnormal test with not found coinbase receiver",
363+ block: &types.Block{
364+ BlockHeader: types.BlockHeader{
365+ Height: 1,
366+ PreviousBlockHash: bc.Hash{V0: 1},
367+ },
368+ Transactions: []*types.Tx{},
369+ },
370+ consensusResult: &ConsensusResult{
371+ NumOfVote: map[string]uint64{},
372+ CoinbaseReward: map[string]uint64{},
373+ BlockHash: bc.Hash{V0: 1},
374+ BlockHeight: 2,
375+ },
376+ wantErr: errors.New("not found coinbase receiver"),
377+ },
378+ }
379+
380+ for i, c := range cases {
381+ if err := c.consensusResult.ApplyBlock(c.block); err != nil {
382+ if err.Error() != c.wantErr.Error() {
383+ t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
384+ }
385+ continue
386+ }
387+
388+ if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
389+ t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
390+ }
391+ }
392+}
393+
394+func TestConsensusDetachBlock(t *testing.T) {
395+ testXpub, _ := hex.DecodeString("a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d")
396+ cases := []struct {
397+ desc string
398+ block *types.Block
399+ consensusResult *ConsensusResult
400+ wantResult *ConsensusResult
401+ wantErr error
402+ }{
403+ {
404+ desc: "normal test with block height is equal to 1",
405+ block: &types.Block{
406+ BlockHeader: types.BlockHeader{
407+ Height: 1,
408+ PreviousBlockHash: bc.Hash{V0: 1},
409+ },
410+ Transactions: []*types.Tx{
411+ &types.Tx{
412+ TxData: types.TxData{
413+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
414+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
415+ },
416+ },
417+ &types.Tx{
418+ TxData: types.TxData{
419+ Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 300000000, 0, nil)},
420+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 250000000, []byte{0x51})},
421+ },
422+ },
423+ },
424+ },
425+ consensusResult: &ConsensusResult{
426+ Seq: 1,
427+ NumOfVote: map[string]uint64{},
428+ CoinbaseReward: map[string]uint64{
429+ "51": consensus.BlockSubsidy(1) + 50000000,
430+ },
431+ BlockHash: testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
432+ BlockHeight: 1,
433+ },
434+ wantResult: &ConsensusResult{
435+ Seq: 0,
436+ NumOfVote: map[string]uint64{},
437+ CoinbaseReward: map[string]uint64{},
438+ BlockHash: bc.Hash{V0: 1},
439+ BlockHeight: 0,
440+ },
441+ },
442+ {
443+ desc: "normal test with block height is equal to RoundVoteBlockNums - 1",
444+ block: &types.Block{
445+ BlockHeader: types.BlockHeader{
446+ Height: consensus.MainNetParams.RoundVoteBlockNums - 1,
447+ PreviousBlockHash: bc.Hash{V0: 1},
448+ },
449+ Transactions: []*types.Tx{
450+ &types.Tx{
451+ TxData: types.TxData{
452+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
453+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
454+ },
455+ },
456+ &types.Tx{
457+ TxData: types.TxData{
458+ Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 600000000, 0, nil)},
459+ Outputs: []*types.TxOutput{types.NewVoteOutput(*consensus.BTMAssetID, 600000000, []byte{0x51}, testXpub)},
460+ },
461+ },
462+ },
463+ },
464+ consensusResult: &ConsensusResult{
465+ NumOfVote: map[string]uint64{
466+ "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 600000000,
467+ },
468+ CoinbaseReward: map[string]uint64{
469+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums - 1),
470+ },
471+ BlockHash: testutil.MustDecodeHash("4ebd9e7c00d3e0370931689c6eb9e2131c6700fe66e6b9718028dd75d7a4e329"),
472+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
473+ },
474+ wantResult: &ConsensusResult{
475+ Seq: 1,
476+ NumOfVote: map[string]uint64{},
477+ CoinbaseReward: map[string]uint64{},
478+ BlockHash: bc.Hash{V0: 1},
479+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 2,
480+ },
481+ },
482+ {
483+ desc: "normal test with block height is equal to RoundVoteBlockNums",
484+ block: &types.Block{
485+ BlockHeader: types.BlockHeader{
486+ Height: consensus.MainNetParams.RoundVoteBlockNums,
487+ PreviousBlockHash: bc.Hash{V0: 1},
488+ },
489+ Transactions: []*types.Tx{
490+ &types.Tx{
491+ TxData: types.TxData{
492+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
493+ Outputs: []*types.TxOutput{
494+ types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
495+ },
496+ },
497+ },
498+ },
499+ },
500+ consensusResult: &ConsensusResult{
501+ NumOfVote: map[string]uint64{
502+ "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
503+ },
504+ CoinbaseReward: map[string]uint64{
505+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 100000000,
506+ },
507+ BlockHash: testutil.MustDecodeHash("1b449ba1f9b0ae41e31238b32943b95e9ab292d0b4a93d690ef9bc689c31d362"),
508+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
509+ },
510+ wantResult: &ConsensusResult{
511+ Seq: 1,
512+ NumOfVote: map[string]uint64{
513+ "a8018a1ba4d85fc7118bbd065612da78b2c503e61a1a093d9c659567c5d3a591b3752569fbcafa951b2304b8f576f3f220e03b957ca819840e7c29e4b7fb2c4d": 500000000,
514+ },
515+ CoinbaseReward: map[string]uint64{
516+ "51": 100000000,
517+ },
518+ BlockHash: bc.Hash{V0: 1},
519+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums - 1,
520+ },
521+ },
522+ {
523+ desc: "normal test with block height is equal to RoundVoteBlockNums + 1",
524+ block: &types.Block{
525+ BlockHeader: types.BlockHeader{
526+ Height: consensus.MainNetParams.RoundVoteBlockNums + 1,
527+ PreviousBlockHash: bc.Hash{V0: 1},
528+ },
529+ Transactions: []*types.Tx{
530+ &types.Tx{
531+ TxData: types.TxData{
532+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
533+ Outputs: []*types.TxOutput{
534+ types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
535+ types.NewIntraChainOutput(bc.AssetID{}, consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums)+10000000, []byte{0x51}),
536+ types.NewIntraChainOutput(bc.AssetID{}, 20000000, []byte{0x52}),
537+ },
538+ },
539+ },
540+ },
541+ },
542+ consensusResult: &ConsensusResult{
543+ NumOfVote: map[string]uint64{},
544+ CoinbaseReward: map[string]uint64{
545+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums + 1),
546+ },
547+ BlockHash: testutil.MustDecodeHash("52681d209ab811359f92daaf46a771ecd0f28505ae5e0ac2f0feb80f76fdda59"),
548+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
549+ },
550+ wantResult: &ConsensusResult{
551+ Seq: 1,
552+ NumOfVote: map[string]uint64{},
553+ CoinbaseReward: map[string]uint64{
554+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums) + 10000000,
555+ "52": 20000000,
556+ },
557+ BlockHash: bc.Hash{V0: 1},
558+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums,
559+ },
560+ },
561+ {
562+ desc: "normal test with block height is equal to RoundVoteBlockNums + 2",
563+ block: &types.Block{
564+ BlockHeader: types.BlockHeader{
565+ Height: consensus.MainNetParams.RoundVoteBlockNums + 2,
566+ PreviousBlockHash: bc.Hash{V0: 1},
567+ },
568+ Transactions: []*types.Tx{
569+ &types.Tx{
570+ TxData: types.TxData{
571+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
572+ Outputs: []*types.TxOutput{
573+ types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51}),
574+ },
575+ },
576+ },
577+ },
578+ },
579+ consensusResult: &ConsensusResult{
580+ NumOfVote: map[string]uint64{},
581+ CoinbaseReward: map[string]uint64{
582+ "51": consensus.BlockSubsidy(consensus.MainNetParams.RoundVoteBlockNums+1) + 1000000,
583+ },
584+ BlockHash: testutil.MustDecodeHash("3de69f8af48b77e81232c71d30b25dd4ac482be45402a0fd417a4a040c135b76"),
585+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
586+ },
587+ wantResult: &ConsensusResult{
588+ Seq: 2,
589+ NumOfVote: map[string]uint64{},
590+ CoinbaseReward: map[string]uint64{
591+ "51": 1000000,
592+ },
593+ BlockHash: bc.Hash{V0: 1},
594+ BlockHeight: consensus.MainNetParams.RoundVoteBlockNums + 1,
595+ },
596+ },
597+ {
598+ desc: "abnormal test with block hash is not equals last block hash of vote result",
599+ block: &types.Block{
600+ BlockHeader: types.BlockHeader{
601+ Height: 2,
602+ PreviousBlockHash: bc.Hash{V0: 0},
603+ },
604+ Transactions: []*types.Tx{},
605+ },
606+ consensusResult: &ConsensusResult{
607+ NumOfVote: map[string]uint64{},
608+ CoinbaseReward: map[string]uint64{},
609+ BlockHash: bc.Hash{V0: 1},
610+ BlockHeight: 1,
611+ },
612+ wantErr: errors.New("block hash is not equals last block hash of vote result"),
613+ },
614+ {
615+ desc: "abnormal test with arithmetic overflow for calculate transaction fee",
616+ block: &types.Block{
617+ BlockHeader: types.BlockHeader{
618+ Height: 2,
619+ PreviousBlockHash: bc.Hash{V0: 1},
620+ },
621+ Transactions: []*types.Tx{
622+ &types.Tx{
623+ TxData: types.TxData{
624+ Inputs: []*types.TxInput{types.NewCoinbaseInput([]byte{0x01})},
625+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(bc.AssetID{}, 0, []byte{0x51})},
626+ },
627+ },
628+ &types.Tx{
629+ TxData: types.TxData{
630+ Inputs: []*types.TxInput{types.NewSpendInput(nil, bc.NewHash([32]byte{0xff}), *consensus.BTMAssetID, 100000000, 0, nil)},
631+ Outputs: []*types.TxOutput{types.NewIntraChainOutput(*consensus.BTMAssetID, 200000000, []byte{0x51})},
632+ },
633+ },
634+ },
635+ },
636+ consensusResult: &ConsensusResult{
637+ NumOfVote: map[string]uint64{},
638+ CoinbaseReward: map[string]uint64{},
639+ BlockHash: testutil.MustDecodeHash("02b7fb48defc4f4a3e1ef8403f7c0be78c4414ee66aa81fd702caa1e41a906df"),
640+ BlockHeight: 1,
641+ },
642+ wantErr: errors.Wrap(checked.ErrOverflow, "calculate transaction fee"),
643+ },
644+ {
645+ desc: "abnormal test with not found coinbase receiver",
646+ block: &types.Block{
647+ BlockHeader: types.BlockHeader{
648+ Height: 1,
649+ PreviousBlockHash: bc.Hash{V0: 1},
650+ },
651+ Transactions: []*types.Tx{},
652+ },
653+ consensusResult: &ConsensusResult{
654+ NumOfVote: map[string]uint64{},
655+ CoinbaseReward: map[string]uint64{},
656+ BlockHash: testutil.MustDecodeHash("50da6990965a16e97b739accca7eb8a0fadd47c8a742f77d18fa51ab60dd8724"),
657+ BlockHeight: 1,
658+ },
659+ wantErr: errors.New("not found coinbase receiver"),
660+ },
661+ }
662+
663+ for i, c := range cases {
664+ if err := c.consensusResult.DetachBlock(c.block); err != nil {
665+ if err.Error() != c.wantErr.Error() {
666+ t.Errorf("test case #%d want err = %v, got err = %v", i, c.wantErr, err)
667+ }
668+ continue
669+ }
670+
671+ if !testutil.DeepEqual(c.consensusResult, c.wantResult) {
672+ t.Errorf("test case #%d, want %v, got %v", i, c.wantResult, c.consensusResult)
673+ }
674+ }
675+}
676+
677+func TestGetCoinbaseRewards(t *testing.T) {
678+ cases := []struct {
679+ desc string
680+ blockHeight uint64
681+ consensusResult *ConsensusResult
682+ wantRewards []CoinbaseReward
683+ }{
684+ {
685+ desc: "the block height is RoundVoteBlockNums - 1",
686+ blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums - 1,
687+ consensusResult: &ConsensusResult{
688+ CoinbaseReward: map[string]uint64{
689+ "51": 10,
690+ },
691+ },
692+ wantRewards: []CoinbaseReward{},
693+ },
694+ {
695+ desc: "the block height is RoundVoteBlockNums",
696+ blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums,
697+ consensusResult: &ConsensusResult{
698+ CoinbaseReward: map[string]uint64{
699+ "51": 10,
700+ "52": 20,
701+ },
702+ },
703+ wantRewards: []CoinbaseReward{
704+ CoinbaseReward{
705+ Amount: 20,
706+ ControlProgram: []byte{0x52},
707+ },
708+ CoinbaseReward{
709+ Amount: 10,
710+ ControlProgram: []byte{0x51},
711+ },
712+ },
713+ },
714+ {
715+ desc: "the block height is RoundVoteBlockNums + 1",
716+ blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums + 1,
717+ consensusResult: &ConsensusResult{
718+ CoinbaseReward: map[string]uint64{
719+ "51": 10,
720+ },
721+ },
722+ wantRewards: []CoinbaseReward{},
723+ },
724+ {
725+ desc: "the block height is RoundVoteBlockNums * 2",
726+ blockHeight: consensus.ActiveNetParams.RoundVoteBlockNums * 2,
727+ consensusResult: &ConsensusResult{
728+ CoinbaseReward: map[string]uint64{
729+ "50": 20,
730+ "51": 10,
731+ "52": 20,
732+ "53": 30,
733+ },
734+ },
735+ wantRewards: []CoinbaseReward{
736+ CoinbaseReward{
737+ Amount: 30,
738+ ControlProgram: []byte{0x53},
739+ },
740+ CoinbaseReward{
741+ Amount: 20,
742+ ControlProgram: []byte{0x52},
743+ },
744+ CoinbaseReward{
745+ Amount: 20,
746+ ControlProgram: []byte{0x50},
747+ },
748+ CoinbaseReward{
749+ Amount: 10,
750+ ControlProgram: []byte{0x51},
751+ },
752+ },
753+ },
754+ {
755+ desc: "the block height is 2*RoundVoteBlockNums + 1",
756+ blockHeight: 2*consensus.ActiveNetParams.RoundVoteBlockNums + 1,
757+ consensusResult: &ConsensusResult{
758+ CoinbaseReward: map[string]uint64{},
759+ },
760+ wantRewards: []CoinbaseReward{},
761+ },
762+ }
763+
764+ for i, c := range cases {
765+ rewards, err := c.consensusResult.GetCoinbaseRewards(c.blockHeight)
766+ if err != nil {
767+ t.Fatal(err)
768+ }
769+
770+ if !testutil.DeepEqual(rewards, c.wantRewards) {
771+ t.Errorf("test case #%d, want %v, got %v", i, c.wantRewards, rewards)
772+ }
773+ }
774+}
Show on old repository browser