OSDN Git Service

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