OSDN Git Service

Merge branch 'master' into demo
[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         "time"
9
10         "github.com/bytom/blockchain/txbuilder"
11         "github.com/bytom/consensus"
12         "github.com/bytom/errors"
13         "github.com/bytom/protocol"
14         "github.com/bytom/protocol/bc"
15         "github.com/bytom/protocol/bc/legacy"
16         "github.com/bytom/protocol/state"
17         "github.com/bytom/protocol/validation"
18         "github.com/bytom/protocol/vm"
19         "github.com/bytom/protocol/vm/vmutil"
20 )
21
22 // standardCoinbaseScript returns a standard script suitable for use as the
23 // signature script of the coinbase transaction of a new block.
24 func standardCoinbaseScript(blockHeight uint64) ([]byte, error) {
25         //TODO: add verify conditions, block heigh & sign
26         scriptBuild := vmutil.NewBuilder()
27         scriptBuild.AddOp(vm.OP_TRUE)
28         return scriptBuild.Build()
29 }
30
31 // createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
32 // based on the passed block height to the provided address.  When the address
33 // is nil, the coinbase transaction will instead be redeemable by anyone.
34 func createCoinbaseTx(amount uint64, blockHeight uint64, addr []byte) (*legacy.Tx, error) {
35         //TODO: make sure things works
36         amount += consensus.BlockSubsidy(blockHeight)
37         cbScript, err := standardCoinbaseScript(blockHeight)
38         if err != nil {
39                 return nil, err
40         }
41
42         builder := txbuilder.NewBuilder(time.Now())
43         builder.AddOutput(legacy.NewTxOutput(*validation.BTMAssetID, amount, cbScript, nil))
44         _, txData, err := builder.Build()
45         tx := &legacy.Tx{
46                 TxData: *txData,
47                 Tx:     legacy.MapTx(txData),
48         }
49         return tx, err
50 }
51
52 // NewBlockTemplate returns a new block template that is ready to be solved
53 func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, addr []byte) (*legacy.Block, error) {
54         // Extend the most recently known best block.
55         var err error
56         newSnap := state.Empty()
57         var blockData *bc.Block
58         nextBlockHeight := uint64(1)
59         preBlockHash := bc.Hash{}
60
61         block, snap := c.State()
62         if block != nil {
63                 nextBlockHeight = block.BlockHeader.Height + 1
64                 preBlockHash = block.Hash()
65                 newSnap = state.Copy(snap)
66                 blockData = legacy.MapBlock(block)
67         }
68
69         txDescs := txPool.GetTransactions()
70         blockTxns := make([]*legacy.Tx, 0, len(txDescs))
71         blockWeight := uint64(0)
72         txFee := uint64(0)
73
74         b := &legacy.Block{
75                 BlockHeader: legacy.BlockHeader{
76                         Version:           1,
77                         Height:            nextBlockHeight,
78                         PreviousBlockHash: preBlockHash,
79                         TimestampMS:       bc.Millis(time.Now()),
80                         BlockCommitment:   legacy.BlockCommitment{},
81                         Bits:              consensus.CalcNextRequiredDifficulty(),
82                 },
83         }
84         newSnap.PruneNonces(b.BlockHeader.TimestampMS)
85
86         var txEntries []*bc.Tx
87         for _, txDesc := range txDescs {
88                 tx := txDesc.Tx.Tx
89                 blockPlusTxWeight := blockWeight + txDesc.Weight
90                 if blockPlusTxWeight > validation.MaxBlockSzie {
91                         break
92                 }
93
94                 if err := newSnap.ApplyTx(tx); err != nil {
95                         txPool.RemoveTransaction(&tx.ID)
96                         continue
97                 }
98
99                 if _, err := validation.ValidateTx(tx, blockData); err != nil {
100                         txPool.RemoveTransaction(&tx.ID)
101                         continue
102                 }
103
104                 blockTxns = append(blockTxns, txDesc.Tx)
105                 txEntries = append(txEntries, tx)
106                 blockWeight = blockPlusTxWeight
107                 txFee += txDesc.Fee
108         }
109
110         cbTx, _ := createCoinbaseTx(txFee, nextBlockHeight, addr)
111         newSnap.ApplyTx(cbTx.Tx)
112         blockTxns = append([]*legacy.Tx{cbTx}, blockTxns...)
113
114         b.Transactions = blockTxns
115
116         b.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = bc.MerkleRoot(txEntries)
117         b.BlockHeader.BlockCommitment.AssetsMerkleRoot = newSnap.Tree.RootHash()
118         if err != nil {
119                 return nil, errors.Wrap(err, "calculating tx merkle root")
120         }
121
122         return b, nil
123 }