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.
8 log "github.com/sirupsen/logrus"
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"
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()
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)
43 builder := txbuilder.NewBuilder(time.Now())
44 builder.AddOutput(legacy.NewTxOutput(*consensus.BTMAssetID, amount, cbScript, nil))
45 _, txData, err := builder.Build()
48 Tx: legacy.MapTx(txData),
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.
57 preBlock, snap := c.State()
58 newSnap := state.Copy(snap)
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)
67 var compareDiffBH *legacy.BlockHeader
68 if compareDiffBlock, err := c.GetBlock(nextBlockHeight - consensus.BlocksPerRetarget); err == nil {
69 compareDiffBH = &compareDiffBlock.BlockHeader
73 BlockHeader: legacy.BlockHeader{
75 Height: nextBlockHeight,
76 PreviousBlockHash: preBlock.Hash(),
77 TimestampMS: bc.Millis(time.Now()),
78 BlockCommitment: legacy.BlockCommitment{},
79 Bits: consensus.CalcNextRequiredDifficulty(&preBlock.BlockHeader, compareDiffBH),
81 Transactions: make([]*legacy.Tx, 0, len(txDescs)),
83 newSnap.PruneNonces(b.BlockHeader.TimestampMS)
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...)
92 for _, txDesc := range txDescs {
94 if blockWeight+txDesc.Weight > consensus.MaxBlockSzie-consensus.MaxTxSize {
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)
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)
108 appendTx(txDesc.Tx, txDesc.Weight, txDesc.Fee)
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")
117 b.BlockHeader.BlockCommitment.AssetsMerkleRoot = newSnap.Tree.RootHash()
118 b.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = bc.MerkleRoot(txEntries)
120 return nil, errors.Wrap(err, "calculating tx merkle root")