OSDN Git Service

Txpool upgrade (#327)
[bytom/bytom.git] / mining / mining.go
1 // Copyright (c) 2014-2016 The btcsuite developers
2 // Use of this source code is governed by an ISC
3 // license that can be found in the LICENSE file.
4
5 package mining
6
7 import (
8         "sort"
9         "time"
10
11         log "github.com/sirupsen/logrus"
12
13         "github.com/bytom/blockchain/account"
14         "github.com/bytom/blockchain/txbuilder"
15         "github.com/bytom/consensus"
16         "github.com/bytom/consensus/algorithm"
17         "github.com/bytom/consensus/difficulty"
18         "github.com/bytom/errors"
19         "github.com/bytom/protocol"
20         "github.com/bytom/protocol/bc"
21         "github.com/bytom/protocol/bc/legacy"
22         "github.com/bytom/protocol/state"
23         "github.com/bytom/protocol/validation"
24         "github.com/bytom/protocol/vm/vmutil"
25 )
26
27 // createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
28 // based on the passed block height to the provided address.  When the address
29 // is nil, the coinbase transaction will instead be redeemable by anyone.
30 func createCoinbaseTx(accountManager *account.Manager, amount uint64, blockHeight uint64) (tx *legacy.Tx, err error) {
31         amount += consensus.BlockSubsidy(blockHeight)
32
33         var script []byte
34         if accountManager == nil {
35                 script, err = vmutil.DefaultCoinbaseProgram()
36         } else {
37                 script, err = accountManager.GetCoinbaseControlProgram()
38         }
39         if err != nil {
40                 return
41         }
42
43         builder := txbuilder.NewBuilder(time.Now())
44         if err = builder.AddInput(legacy.NewCoinbaseInput([]byte(string(blockHeight)), nil), &txbuilder.SigningInstruction{}); err != nil {
45                 return
46         }
47         if err = builder.AddOutput(legacy.NewTxOutput(*consensus.BTMAssetID, amount, script, nil)); err != nil {
48                 return
49         }
50         _, txData, err := builder.Build()
51         if err != nil {
52                 return
53         }
54
55         tx = &legacy.Tx{
56                 TxData: *txData,
57                 Tx:     legacy.MapTx(txData),
58         }
59         return
60 }
61
62 // NewBlockTemplate returns a new block template that is ready to be solved
63 func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager *account.Manager) (b *legacy.Block, err error) {
64         view := state.NewUtxoViewpoint()
65         txEntries := []*bc.Tx{nil}
66         blockWeight := uint64(0)
67         txFee := uint64(0)
68
69         // get preblock info for generate next block
70         preBlock := c.BestBlock()
71         preBcBlock := legacy.MapBlock(preBlock)
72         nextBlockHeight := preBlock.BlockHeader.Height + 1
73         nextBlockSeed := algorithm.CreateSeed(nextBlockHeight, preBcBlock.Seed, []*bc.Hash{&preBcBlock.ID})
74
75         var compareDiffBH *legacy.BlockHeader
76         if compareDiffBlock, err := c.GetBlockByHeight(nextBlockHeight - consensus.BlocksPerRetarget); err == nil {
77                 compareDiffBH = &compareDiffBlock.BlockHeader
78         }
79
80         b = &legacy.Block{
81                 BlockHeader: legacy.BlockHeader{
82                         Version:           1,
83                         Height:            nextBlockHeight,
84                         PreviousBlockHash: preBlock.Hash(),
85                         Seed:              *nextBlockSeed,
86                         Timestamp:         uint64(time.Now().Unix()),
87                         TransactionStatus: *bc.NewTransactionStatus(),
88                         BlockCommitment:   legacy.BlockCommitment{},
89                         Bits:              difficulty.CalcNextRequiredDifficulty(&preBlock.BlockHeader, compareDiffBH),
90                 },
91                 Transactions: []*legacy.Tx{nil},
92         }
93         bcBlock := &bc.Block{BlockHeader: &bc.BlockHeader{Height: nextBlockHeight}}
94
95         txs := txPool.GetTransactions()
96         sort.Sort(ByTime(txs))
97         for _, txDesc := range txs {
98                 tx := txDesc.Tx.Tx
99                 gasOnlyTx := false
100                 if blockWeight+txDesc.Weight > consensus.MaxBlockSzie-consensus.MaxTxSize {
101                         break
102                 }
103
104                 if err := c.GetTransactionsUtxo(view, []*bc.Tx{tx}); err != nil {
105                         log.WithField("error", err).Error("mining block generate skip tx due to")
106                         txPool.RemoveTransaction(&tx.ID)
107                         continue
108                 }
109
110                 if _, gasVaild, err := validation.ValidateTx(tx, preBcBlock); err != nil {
111                         if !gasVaild {
112                                 log.WithField("error", err).Error("mining block generate skip tx due to")
113                                 txPool.RemoveTransaction(&tx.ID)
114                                 continue
115                         }
116                         gasOnlyTx = true
117                 }
118
119                 if err := view.ApplyTransaction(bcBlock, tx, gasOnlyTx); err != nil {
120                         log.WithField("error", err).Error("mining block generate skip tx due to")
121                         txPool.RemoveTransaction(&tx.ID)
122                         continue
123                 }
124
125                 b.BlockHeader.TransactionStatus.SetStatus(len(b.Transactions), gasOnlyTx)
126                 b.Transactions = append(b.Transactions, txDesc.Tx)
127                 txEntries = append(txEntries, tx)
128                 blockWeight += txDesc.Weight
129                 txFee += txDesc.Fee
130         }
131
132         // creater coinbase transaction
133         b.Transactions[0], err = createCoinbaseTx(accountManager, txFee, nextBlockHeight)
134         if err != nil {
135                 return nil, errors.Wrap(err, "fail on createCoinbaseTx")
136         }
137         txEntries[0] = b.Transactions[0].Tx
138
139         b.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = bc.MerkleRoot(txEntries)
140         return b, err
141 }