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.
10 log "github.com/sirupsen/logrus"
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"
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()
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)
44 builder := txbuilder.NewBuilder(time.Now())
45 builder.AddOutput(legacy.NewTxOutput(*consensus.BTMAssetID, amount, cbScript, nil))
46 _, txData, err := builder.Build()
49 Tx: legacy.MapTx(txData),
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.
58 preBlock, snap := c.State()
59 newSnap := state.Copy(snap)
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)
68 var compareDiffBH *legacy.BlockHeader
69 if compareDiffBlock, err := c.GetBlockByHeight(nextBlockHeight - consensus.BlocksPerRetarget); err == nil {
70 compareDiffBH = &compareDiffBlock.BlockHeader
74 BlockHeader: legacy.BlockHeader{
76 Height: nextBlockHeight,
77 PreviousBlockHash: preBlock.Hash(),
78 TimestampMS: bc.Millis(time.Now()),
79 BlockCommitment: legacy.BlockCommitment{},
80 Bits: consensus.CalcNextRequiredDifficulty(&preBlock.BlockHeader, compareDiffBH),
82 Transactions: make([]*legacy.Tx, 0, len(txDescs)),
84 newSnap.PruneNonces(b.BlockHeader.TimestampMS)
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...)
93 for _, txDesc := range txDescs {
95 if blockWeight+txDesc.Weight > consensus.MaxBlockSzie-consensus.MaxTxSize {
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)
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)
109 appendTx(txDesc.Tx, txDesc.Weight, txDesc.Fee)
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")
118 b.BlockHeader.BlockCommitment.AssetsMerkleRoot = newSnap.Tree.RootHash()
119 b.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = bc.MerkleRoot(txEntries)
121 return nil, errors.Wrap(err, "calculating tx merkle root")