OSDN Git Service

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