OSDN Git Service

Merge branch 'demo' of https://github.com/Bytom/bytom 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(*consensus.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         preBlock, snap := c.State()
57         newSnap := state.Copy(snap)
58
59         nextBlockHeight := preBlock.BlockHeader.Height + 1
60         preBcBlock := legacy.MapBlock(preBlock)
61         txDescs := txPool.GetTransactions()
62         txEntries := make([]*bc.Tx, 0, len(txDescs))
63         blockWeight := uint64(0)
64         txFee := uint64(0)
65
66         b := &legacy.Block{
67                 BlockHeader: legacy.BlockHeader{
68                         Version:           1,
69                         Height:            nextBlockHeight,
70                         PreviousBlockHash: preBlock.Hash(),
71                         TimestampMS:       bc.Millis(time.Now()),
72                         BlockCommitment:   legacy.BlockCommitment{},
73                         Bits:              consensus.CalcNextRequiredDifficulty(nil, nil),
74                 },
75                 Transactions: make([]*legacy.Tx, 0, len(txDescs)),
76         }
77         newSnap.PruneNonces(b.BlockHeader.TimestampMS)
78
79         appendTx := func(tx *legacy.Tx, weight, fee uint64) {
80                 b.Transactions = append(b.Transactions, tx)
81                 txEntries = append(txEntries, tx.Tx)
82                 blockWeight += weight
83                 txFee += fee
84         }
85
86         for _, txDesc := range txDescs {
87                 tx := txDesc.Tx.Tx
88                 if blockWeight+txDesc.Weight > consensus.MaxBlockSzie-consensus.MaxTxSize {
89                         break
90                 }
91                 if err := newSnap.ApplyTx(tx); err != nil {
92                         txPool.RemoveTransaction(&tx.ID)
93                         continue
94                 }
95                 if _, err := validation.ValidateTx(tx, preBcBlock); err != nil {
96                         txPool.RemoveTransaction(&tx.ID)
97                         continue
98                 }
99
100                 appendTx(txDesc.Tx, txDesc.Weight, txDesc.Fee)
101         }
102
103         cbTx, _ := createCoinbaseTx(txFee, nextBlockHeight, addr)
104         if err := newSnap.ApplyTx(cbTx.Tx); err != nil {
105                 return nil, errors.Wrap(err, "fail on append coinbase transaction to snap")
106         }
107         appendTx(cbTx, 0, 0)
108
109         b.BlockHeader.BlockCommitment.AssetsMerkleRoot = newSnap.Tree.RootHash()
110         b.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = bc.MerkleRoot(txEntries)
111         if err != nil {
112                 return nil, errors.Wrap(err, "calculating tx merkle root")
113         }
114
115         return b, nil
116 }