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 "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"
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()
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)
42 builder := txbuilder.NewBuilder(time.Now())
43 builder.AddOutput(legacy.NewTxOutput(*consensus.BTMAssetID, amount, cbScript, nil))
44 _, txData, err := builder.Build()
47 Tx: legacy.MapTx(txData),
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.
56 preBlock, snap := c.State()
57 newSnap := state.Copy(snap)
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)
67 BlockHeader: legacy.BlockHeader{
69 Height: nextBlockHeight,
70 PreviousBlockHash: preBlock.Hash(),
71 TimestampMS: bc.Millis(time.Now()),
72 BlockCommitment: legacy.BlockCommitment{},
73 Bits: consensus.CalcNextRequiredDifficulty(nil, nil),
75 Transactions: make([]*legacy.Tx, 0, len(txDescs)),
77 newSnap.PruneNonces(b.BlockHeader.TimestampMS)
79 appendTx := func(tx *legacy.Tx, weight, fee uint64) {
80 b.Transactions = append(b.Transactions, tx)
81 txEntries = append(txEntries, tx.Tx)
86 for _, txDesc := range txDescs {
88 if blockWeight+txDesc.Weight > consensus.MaxBlockSzie-consensus.MaxTxSize {
91 if err := newSnap.ApplyTx(tx); err != nil {
92 txPool.RemoveTransaction(&tx.ID)
95 if _, err := validation.ValidateTx(tx, preBcBlock); err != nil {
96 txPool.RemoveTransaction(&tx.ID)
100 appendTx(txDesc.Tx, txDesc.Weight, txDesc.Fee)
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")
109 b.BlockHeader.BlockCommitment.AssetsMerkleRoot = newSnap.Tree.RootHash()
110 b.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = bc.MerkleRoot(txEntries)
112 return nil, errors.Wrap(err, "calculating tx merkle root")