OSDN Git Service

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