Implement some BIP0023 getblocktemplate mutations.
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 #124.
This commit is contained in:
parent
21050b4751
commit
180f4ac0a2
1 changed files with 49 additions and 5 deletions
54
rpcserver.go
54
rpcserver.go
|
@ -65,6 +65,11 @@ const (
|
||||||
hash1Len = (1 + ((btcwire.HashSize + 8) / fastsha256.BlockSize)) *
|
hash1Len = (1 + ((btcwire.HashSize + 8) / fastsha256.BlockSize)) *
|
||||||
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
|
// gbtRegenerateSeconds is the number of seconds that must pass before
|
||||||
// a new template is generated when the previous block hash has not
|
// a new template is generated when the previous block hash has not
|
||||||
// changed and there have been changes to the available transactions
|
// changed and there have been changes to the available transactions
|
||||||
|
@ -73,6 +78,14 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
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
|
// gbtCoinbaseAux describes additional data that miners should include
|
||||||
// in the coinbase signature script. It is declared here to avoid the
|
// in the coinbase signature script. It is declared here to avoid the
|
||||||
// overhead of creating a new object on every invocation for constant
|
// overhead of creating a new object on every invocation for constant
|
||||||
|
@ -1547,11 +1560,36 @@ func (state *gbtWorkState) updateBlockTemplate(s *rpcServer, useCoinbaseValue bo
|
||||||
//
|
//
|
||||||
// This function MUST be called with the state locked.
|
// This function MUST be called with the state locked.
|
||||||
func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld *bool) (*btcjson.GetBlockTemplateResult, error) {
|
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
|
// Convert each transaction in the block template to a template result
|
||||||
// transaction. The result does not include the coinbase, so notice
|
// transaction. The result does not include the coinbase, so notice
|
||||||
// the adjustments to the various lengths and indices.
|
// the adjustments to the various lengths and indices.
|
||||||
template := state.template
|
|
||||||
msgBlock := template.block
|
|
||||||
numTx := len(msgBlock.Transactions)
|
numTx := len(msgBlock.Transactions)
|
||||||
transactions := make([]btcjson.GetBlockTemplateResultTx, 0, numTx-1)
|
transactions := make([]btcjson.GetBlockTemplateResultTx, 0, numTx-1)
|
||||||
txIndex := make(map[btcwire.ShaHash]int64, numTx)
|
txIndex := make(map[btcwire.ShaHash]int64, numTx)
|
||||||
|
@ -1600,13 +1638,15 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld
|
||||||
transactions = append(transactions, resultTx)
|
transactions = append(transactions, resultTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the block template reply.
|
// Generate the block template reply. Note that following mutations are
|
||||||
header := &msgBlock.Header
|
// implied by the included or omission of fields:
|
||||||
|
// Including MinTime -> time/decrement
|
||||||
|
// Omitting CoinbaseTxn -> coinbase, generation
|
||||||
targetDifficulty := fmt.Sprintf("%064x", btcchain.CompactToBig(header.Bits))
|
targetDifficulty := fmt.Sprintf("%064x", btcchain.CompactToBig(header.Bits))
|
||||||
templateID := encodeTemplateID(state.prevHash, state.lastGenerated)
|
templateID := encodeTemplateID(state.prevHash, state.lastGenerated)
|
||||||
reply := btcjson.GetBlockTemplateResult{
|
reply := btcjson.GetBlockTemplateResult{
|
||||||
Bits: strconv.FormatInt(int64(header.Bits), 16),
|
Bits: strconv.FormatInt(int64(header.Bits), 16),
|
||||||
CurTime: time.Now().Unix(),
|
CurTime: curTime.Unix(),
|
||||||
Height: template.height,
|
Height: template.height,
|
||||||
PreviousHash: header.PrevBlock.String(),
|
PreviousHash: header.PrevBlock.String(),
|
||||||
SigOpLimit: btcchain.MaxSigOpsPerBlock,
|
SigOpLimit: btcchain.MaxSigOpsPerBlock,
|
||||||
|
@ -1616,6 +1656,10 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld
|
||||||
LongPollID: templateID,
|
LongPollID: templateID,
|
||||||
SubmitOld: submitOld,
|
SubmitOld: submitOld,
|
||||||
Target: targetDifficulty,
|
Target: targetDifficulty,
|
||||||
|
MinTime: state.minTimestamp.Unix(),
|
||||||
|
MaxTime: maxTime.Unix(),
|
||||||
|
Mutable: gbtMutableFields,
|
||||||
|
NonceRange: gbtNonceRange,
|
||||||
Capabilities: gbtCapabilities,
|
Capabilities: gbtCapabilities,
|
||||||
}
|
}
|
||||||
if useCoinbaseValue {
|
if useCoinbaseValue {
|
||||||
|
|
Loading…
Reference in a new issue