Correct RPC time handling for getblocktemplate.

This commit modifies the getblocktemplate RPC to correctly handle the
curtime field.

Currently, the RPC server will refuse to serve a block template if the
current time is before the minimum allowed time for a block even though
the real generated block template already accounted for it.

This consists of three changes:
- Remove the unnecessary and incorrect check in the RPC invocation for the
  current time against the min required time since it is already handled
  properly by the block template generation.
- Expose the network time source to the RPC work state and use the
  adjusted time for checking against the maximum allowed time instead of
  the current time.
- Set the returned RPC result curtime field to the time of the generated
  block header.

Fixes #209.
This commit is contained in:
Dave Collins 2015-01-08 00:57:13 -06:00
parent 4b727d2035
commit a64ffb820a

View file

@ -247,13 +247,15 @@ type gbtWorkState struct {
minTimestamp time.Time minTimestamp time.Time
template *BlockTemplate template *BlockTemplate
notifyMap map[btcwire.ShaHash]map[int64]chan struct{} notifyMap map[btcwire.ShaHash]map[int64]chan struct{}
timeSource btcchain.MedianTimeSource
} }
// newGbtWorkState returns a new instance of a gbtWorkState with all internal // newGbtWorkState returns a new instance of a gbtWorkState with all internal
// fields initialized and ready to use. // fields initialized and ready to use.
func newGbtWorkState() *gbtWorkState { func newGbtWorkState(timeSource btcchain.MedianTimeSource) *gbtWorkState {
return &gbtWorkState{ return &gbtWorkState{
notifyMap: make(map[btcwire.ShaHash]map[int64]chan struct{}), notifyMap: make(map[btcwire.ShaHash]map[int64]chan struct{}),
timeSource: timeSource,
} }
} }
@ -519,7 +521,7 @@ func newRPCServer(listenAddrs []string, s *server) (*rpcServer, error) {
server: s, server: s,
statusLines: make(map[int]string), statusLines: make(map[int]string),
workState: newWorkState(), workState: newWorkState(),
gbtWorkState: newGbtWorkState(), gbtWorkState: newGbtWorkState(s.timeSource),
quit: make(chan int), quit: make(chan int),
} }
rpc.ntfnMgr = newWsNotificationManager(&rpc) rpc.ntfnMgr = newWsNotificationManager(&rpc)
@ -1546,23 +1548,15 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld
template := state.template template := state.template
msgBlock := template.block msgBlock := template.block
header := &msgBlock.Header header := &msgBlock.Header
curTime := time.Now() adjustedTime := state.timeSource.AdjustedTime()
if curTime.Before(state.minTimestamp) { maxTime := adjustedTime.Add(time.Second * btcchain.MaxTimeOffsetSeconds)
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) { if header.Timestamp.After(maxTime) {
return nil, btcjson.Error{ return nil, btcjson.Error{
Code: btcjson.ErrOutOfRange.Code, Code: btcjson.ErrOutOfRange.Code,
Message: fmt.Sprintf("The template time is after the "+ Message: fmt.Sprintf("The template time is after the "+
"maximum allowed time for a block - template "+ "maximum allowed time for a block - template "+
"time %v, maximum time %v", curTime, maxTime), "time %v, maximum time %v", adjustedTime,
maxTime),
} }
} }
@ -1625,7 +1619,7 @@ func (state *gbtWorkState) blockTemplateResult(useCoinbaseValue bool, submitOld
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: curTime.Unix(), CurTime: header.Timestamp.Unix(),
Height: template.height, Height: template.height,
PreviousHash: header.PrevBlock.String(), PreviousHash: header.PrevBlock.String(),
SigOpLimit: btcchain.MaxSigOpsPerBlock, SigOpLimit: btcchain.MaxSigOpsPerBlock,