Modify NewBlockTemplate to accept nil pay addr.

There are certain cases such as getblocktemplate which allow external
callers to be repsonsible for creating their own coinbase to replace the
generated one.  By allowing the pay address to be nil in such cases, the
need to specify mining addresses via --miningaddr can be avoided thereby
leaving the payment address management up to the caller.
This commit is contained in:
Dave Collins 2014-06-27 00:41:09 -05:00
parent d40cff64b0
commit 0c9c005c33
3 changed files with 54 additions and 32 deletions

View file

@ -298,7 +298,7 @@ out:
// Create a new block template using the available transactions // Create a new block template using the available transactions
// in the memory pool as a source of transactions to potentially // in the memory pool as a source of transactions to potentially
// include in the block. // include in the block.
template, err := NewBlockTemplate(payToAddr, m.server.txMemPool) template, err := NewBlockTemplate(m.server.txMemPool, payToAddr)
m.submitBlockLock.Unlock() m.submitBlockLock.Unlock()
if err != nil { if err != nil {
errStr := fmt.Sprintf("Failed to create new block "+ errStr := fmt.Sprintf("Failed to create new block "+

View file

@ -165,9 +165,11 @@ func newTxPriorityQueue(reserve int, sortByFee bool) *txPriorityQueue {
// details about the fees and the number of signature operations for each // details about the fees and the number of signature operations for each
// transaction in the block. // transaction in the block.
type BlockTemplate struct { type BlockTemplate struct {
block *btcwire.MsgBlock block *btcwire.MsgBlock
fees []int64 fees []int64
sigOpCounts []int64 sigOpCounts []int64
height int64
validPayAddress bool
} }
// minInt is a helper function to return the minimum of two ints. This avoids // minInt is a helper function to return the minimum of two ints. This avoids
@ -203,16 +205,25 @@ func standardCoinbaseScript(nextBlockHeight int64, extraNonce uint64) []byte {
} }
// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy // createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
// based on the passed block height to the passed public key. It also accepts // based on the passed block height to the provided address. When the address
// an extra nonce value for the signature script. This extra nonce helps ensure // is nil, the coinbase transaction will instead be redeemable by anyone.
// the transaction is not a duplicate transaction (paying the same value to the //
// same public key address would otherwise be an identical transaction for // See the comment for NewBlockTemplate for more information about why the nil
// block version 1). // address handling is useful.
func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int64, addr btcutil.Address) (*btcutil.Tx, error) { func createCoinbaseTx(coinbaseScript []byte, nextBlockHeight int64, addr btcutil.Address) (*btcutil.Tx, error) {
// Create a script to pay to the specific address. // Create the script to pay to the provided payment address if one was
pkScript, err := btcscript.PayToAddrScript(addr) // specified. Otherwise create a script that allows the coinbase to be
if err != nil { // redeemable by anyone.
return nil, err var pkScript []byte
if addr != nil {
var err error
pkScript, err = btcscript.PayToAddrScript(addr)
if err != nil {
return nil, err
}
} else {
scriptBuilder := btcscript.NewScriptBuilder()
pkScript = scriptBuilder.AddOp(btcscript.OP_TRUE).Script()
} }
tx := btcwire.NewMsgTx() tx := btcwire.NewMsgTx()
@ -332,16 +343,22 @@ func medianAdjustedTime(chainState *chainState) (time.Time, error) {
return newTimestamp, nil return newTimestamp, nil
} }
// NewBlockTemplate returns a new block template using the transactions from the // NewBlockTemplate returns a new block template that is ready to be solved
// passed transaction memory pool with a coinbase that pays to the passed // using the transactions from the passed transaction memory pool and a coinbase
// address and is ready to be solved. The transactions selected and included // that either pays to the passed address if it is not nil, or a coinbase that
// are prioritized according to several factors. First, each transaction has a // is redeemable by anyone if the passed address is nil. The nil address
// priority calculated based on its value, age of inputs, and size. // functionality is useful since there are cases such as the getblocktemplate
// Transactions which consist of larger amounts, older inputs, and small sizes // RPC where external mining software is responsible for creating their own
// have the highest priority. Second, a fee per kilobyte is calculated for each // coinbase which will replace the one generated for the block template. Thus
// transaction. Transactions with a higher fee per kilobyte are preferred. // the need to have configured address can be avoided.
// Finally, the block generation related configuration options are all taken //
// into account. // The transactions selected and included are prioritized according to several
// factors. First, each transaction has a priority calculated based on its
// value, age of inputs, and size. Transactions which consist of larger
// amounts, older inputs, and small sizes have the highest priority. Second, a
// fee per kilobyte is calculated for each transaction. Transactions with a
// higher fee per kilobyte are preferred. Finally, the block generation related
// configuration options are all taken into account.
// //
// Transactions which only spend outputs from other transactions already in the // Transactions which only spend outputs from other transactions already in the
// block chain are immediately added to a priority queue which either // block chain are immediately added to a priority queue which either
@ -387,7 +404,7 @@ func medianAdjustedTime(chainState *chainState) (time.Time, error) {
// | transactions (while block size | | // | transactions (while block size | |
// | <= cfg.BlockMinSize) | | // | <= cfg.BlockMinSize) | |
// ----------------------------------- -- // ----------------------------------- --
func NewBlockTemplate(payToAddress btcutil.Address, mempool *txMemPool) (*BlockTemplate, error) { func NewBlockTemplate(mempool *txMemPool, payToAddress btcutil.Address) (*BlockTemplate, error) {
blockManager := mempool.server.blockManager blockManager := mempool.server.blockManager
chainState := &blockManager.chainState chainState := &blockManager.chainState
chain := blockManager.blockChain chain := blockManager.blockChain
@ -402,7 +419,10 @@ func NewBlockTemplate(payToAddress btcutil.Address, mempool *txMemPool) (*BlockT
// address. NOTE: The coinbase value will be updated to include the // address. NOTE: The coinbase value will be updated to include the
// fees from the selected transactions later after they have actually // fees from the selected transactions later after they have actually
// been selected. It is created here to detect any errors early // been selected. It is created here to detect any errors early
// before potentially doing a lot of work below. // before potentially doing a lot of work below. The extra nonce helps
// ensure the transaction is not a duplicate transaction (paying the
// same value to the same public key address would otherwise be an
// identical transaction for block version 1).
extraNonce := uint64(0) extraNonce := uint64(0)
coinbaseScript := standardCoinbaseScript(nextBlockHeight, extraNonce) coinbaseScript := standardCoinbaseScript(nextBlockHeight, extraNonce)
coinbaseTx, err := createCoinbaseTx(coinbaseScript, nextBlockHeight, coinbaseTx, err := createCoinbaseTx(coinbaseScript, nextBlockHeight,
@ -444,8 +464,8 @@ func NewBlockTemplate(payToAddress btcutil.Address, mempool *txMemPool) (*BlockT
// a transaction as it is selected for inclusion in the final block. // a transaction as it is selected for inclusion in the final block.
// However, since the total fees aren't known yet, use a dummy value for // However, since the total fees aren't known yet, use a dummy value for
// the coinbase fee which will be updated later. // the coinbase fee which will be updated later.
txFees := make([]int64, len(mempoolTxns)) txFees := make([]int64, 0, len(mempoolTxns))
txSigOpCounts := make([]int64, len(mempoolTxns)) txSigOpCounts := make([]int64, 0, len(mempoolTxns))
txFees = append(txFees, -1) // Updated once known txFees = append(txFees, -1) // Updated once known
txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps) txSigOpCounts = append(txSigOpCounts, numCoinbaseSigOps)
@ -776,9 +796,11 @@ mempoolLoop:
blockSize, btcchain.CompactToBig(msgBlock.Header.Bits)) blockSize, btcchain.CompactToBig(msgBlock.Header.Bits))
return &BlockTemplate{ return &BlockTemplate{
block: &msgBlock, block: &msgBlock,
fees: txFees, fees: txFees,
sigOpCounts: txSigOpCounts, sigOpCounts: txSigOpCounts,
height: nextBlockHeight,
validPayAddress: payToAddress != nil,
}, nil }, nil
} }
@ -813,7 +835,7 @@ func UpdateBlockTime(msgBlock *btcwire.MsgBlock, bManager *blockManager) error {
// UpdateExtraNonce updates the extra nonce in the coinbase script of the passed // UpdateExtraNonce updates the extra nonce in the coinbase script of the passed
// block by regenerating the coinbase script with the passed value and block // block by regenerating the coinbase script with the passed value and block
// height. It also recalculates and updates the new merkle root the results // height. It also recalculates and updates the new merkle root that results
// from changing the coinbase script. // from changing the coinbase script.
func UpdateExtraNonce(msgBlock *btcwire.MsgBlock, blockHeight int64, extraNonce uint64) error { func UpdateExtraNonce(msgBlock *btcwire.MsgBlock, blockHeight int64, extraNonce uint64) error {
coinbaseScript := standardCoinbaseScript(blockHeight, extraNonce) coinbaseScript := standardCoinbaseScript(blockHeight, extraNonce)

View file

@ -1621,7 +1621,7 @@ func handleGetWorkRequest(s *rpcServer) (interface{}, error) {
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
payToAddr := cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))] payToAddr := cfg.miningAddrs[rand.Intn(len(cfg.miningAddrs))]
template, err := NewBlockTemplate(payToAddr, s.server.txMemPool) template, err := NewBlockTemplate(s.server.txMemPool, payToAddr)
if err != nil { if err != nil {
errStr := fmt.Sprintf("Failed to create new block "+ errStr := fmt.Sprintf("Failed to create new block "+
"template: %v", err) "template: %v", err)