Skip to content

Commit

Permalink
Implement some BIP0023 getblocktemplate mutations.
Browse files Browse the repository at this point in the history
This commit implements a portion of the mutations section of BIP0023.
In particular, it adds the mutable, mintime, maxtime, and noncerange keys
to the returned block template along with indicating support for the time,
transactions/add, prevblock, and coinbase/append mutations.  Also, the
addition of the mintime and maxtime fields imply support for the
time/decrement and time/increment mutations.  Further, if the caller
indicates the coinbasevalue capability, the coinbasetxn field will be
omitted thereby implying support for the coinbase and generation
mutations.

Closes btcsuite#124.
  • Loading branch information
davecgh committed Jul 7, 2014
1 parent 558745b commit 80505ab
Showing 1 changed file with 49 additions and 5 deletions.
54 changes: 49 additions & 5 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ const (
hash1Len = (1 + ((btcwire.HashSize + 8) / fastsha256.BlockSize)) *
fastsha256.BlockSize

// gbtNonceRange is two 32-bit big-endian hexadecimal integers which
// represent the valid ranges of nonces returned by the getblocktemplate
// RPC.
gbtNonceRange = "00000000ffffffff"

// gbtRegenerateSeconds is the number of seconds that must pass before
// a new template is generated when the previous block hash has not
// changed and there have been changes to the available transactions
Expand All @@ -73,6 +78,14 @@ const (
)

var (
// gbtMutableFields are the manipulations the server allows to be made
// to block templates generated by the getblocktemplate RPC. It is
// declared here to avoid the overhead of creating the slice on every
// invocation for constant data.
gbtMutableFields = []string{
"time", "transactions/add", "prevblock", "coinbase/append",
}

// gbtCoinbaseAux describes additional data that miners should include
// in the coinbase signature script. It is declared here to avoid the
// overhead of creating a new object on every invocation for constant
Expand Down Expand Up @@ -1557,11 +1570,36 @@ func (state *gbtWorkState) updateBlockTemplate(s *rpcServer, useCoinbaseValue bo
//
// This function MUST be called with the state locked.
func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld *bool) (*btcjson.GetBlockTemplateResult, error) {
// Ensure the timestamps are still in valid range for the template.
// This should really only ever happen if the local clock is changed
// after the template is generated, but it's important to avoid serving
// invalid block templates.
template := state.template
msgBlock := template.block
header := &msgBlock.Header
curTime := time.Now()
if curTime.Before(state.minTimestamp) {
return nil, btcjson.Error{
Code: btcjson.ErrOutOfRange.Code,
Message: fmt.Sprintf("The local time is before the "+
"minimum allowed time for a block - current "+
"time %v, minimum time %v", curTime,
state.minTimestamp),
}
}
maxTime := curTime.Add(time.Second * btcchain.MaxTimeOffsetSeconds)
if header.Timestamp.After(maxTime) {
return nil, btcjson.Error{
Code: btcjson.ErrOutOfRange.Code,
Message: fmt.Sprintf("The template time is after the "+
"maximum allowed time for a block - template "+
"time %v, maximum time %v", curTime, maxTime),
}
}

// Convert each transaction in the block template to a template result
// transaction. The result does not include the coinbase, so notice
// the adjustments to the various lengths and indices.
template := state.template
msgBlock := template.block
numTx := len(msgBlock.Transactions)
transactions := make([]btcjson.GetBlockTemplateResultTx, 0, numTx-1)
txIndex := make(map[btcwire.ShaHash]int64, numTx)
Expand Down Expand Up @@ -1610,13 +1648,15 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld
transactions = append(transactions, resultTx)
}

// Generate the block template reply.
header := &msgBlock.Header
// Generate the block template reply. Note that following mutations are
// implied by the included or omission of fields:
// Including MinTime -> time/decrement
// Omitting CoinbaseTxn -> coinbase, generation
targetDifficulty := fmt.Sprintf("%064x", btcchain.CompactToBig(header.Bits))
templateID := encodeTemplateID(state.prevHash, state.lastGenerated)
reply := btcjson.GetBlockTemplateResult{
Bits: strconv.FormatInt(int64(header.Bits), 16),
CurTime: time.Now().Unix(),
CurTime: curTime.Unix(),
Height: template.height,
PreviousHash: header.PrevBlock.String(),
SigOpLimit: btcchain.MaxSigOpsPerBlock,
Expand All @@ -1626,6 +1666,10 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld
LongPollID: templateID,
SubmitOld: submitOld,
Target: targetDifficulty,
MinTime: state.minTimestamp.Unix(),
MaxTime: maxTime.Unix(),
Mutable: gbtMutableFields,
NonceRange: gbtNonceRange,
Capabilities: gbtCapabilities,
}
if useCoinbaseValue {
Expand Down

0 comments on commit 80505ab

Please sign in to comment.