mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-05 21:56:50 +00:00
[NOD-820] When the node isn't synced, make getBlockTemplate return a boolean isSynced instead of an error (#716)
* [NOD-820] Add IsSynced to GetBlockTemplateResult. * [NOD-820] Add isSynced to the help file. * [NOD-820] Add MineWhenNotSynced to the kaspaminer config. * [NOD-820] Implement miner MineWhenNotSynced logic. * [NOD-820] Fixed capitalization in an error message.
This commit is contained in:
parent
585510d76c
commit
806eab817c
@ -30,16 +30,17 @@ var (
|
||||
)
|
||||
|
||||
type configFlags struct {
|
||||
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
|
||||
RPCUser string `short:"u" long:"rpcuser" description:"RPC username"`
|
||||
RPCPassword string `short:"P" long:"rpcpass" default-mask:"-" description:"RPC password"`
|
||||
RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to"`
|
||||
RPCCert string `short:"c" long:"rpccert" description:"RPC server certificate chain for validation"`
|
||||
DisableTLS bool `long:"notls" description:"Disable TLS"`
|
||||
Verbose bool `long:"verbose" short:"v" description:"Enable logging of RPC requests"`
|
||||
NumberOfBlocks uint64 `short:"n" long:"numblocks" description:"Number of blocks to mine. If omitted, will mine until the process is interrupted."`
|
||||
BlockDelay uint64 `long:"block-delay" description:"Delay for block submission (in milliseconds). This is used only for testing purposes."`
|
||||
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
|
||||
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
|
||||
RPCUser string `short:"u" long:"rpcuser" description:"RPC username"`
|
||||
RPCPassword string `short:"P" long:"rpcpass" default-mask:"-" description:"RPC password"`
|
||||
RPCServer string `short:"s" long:"rpcserver" description:"RPC server to connect to"`
|
||||
RPCCert string `short:"c" long:"rpccert" description:"RPC server certificate chain for validation"`
|
||||
DisableTLS bool `long:"notls" description:"Disable TLS"`
|
||||
Verbose bool `long:"verbose" short:"v" description:"Enable logging of RPC requests"`
|
||||
NumberOfBlocks uint64 `short:"n" long:"numblocks" description:"Number of blocks to mine. If omitted, will mine until the process is interrupted."`
|
||||
BlockDelay uint64 `long:"block-delay" description:"Delay for block submission (in milliseconds). This is used only for testing purposes."`
|
||||
MineWhenNotSynced bool `long:"mine-when-not-synced" description:"Mine even if the node is not synced with the rest of the network."`
|
||||
Profile string `long:"profile" description:"Enable HTTP profiling on given port -- NOTE port must be between 1024 and 65536"`
|
||||
config.NetworkFlags
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ func main() {
|
||||
|
||||
doneChan := make(chan struct{})
|
||||
spawn(func() {
|
||||
err = mineLoop(client, cfg.NumberOfBlocks, cfg.BlockDelay)
|
||||
err = mineLoop(client, cfg.NumberOfBlocks, cfg.BlockDelay, cfg.MineWhenNotSynced)
|
||||
if err != nil {
|
||||
panic(errors.Errorf("Error in mine loop: %s", err))
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ var hashesTried uint64
|
||||
|
||||
const logHashRateInterval = 10 * time.Second
|
||||
|
||||
func mineLoop(client *minerClient, numberOfBlocks uint64, blockDelay uint64) error {
|
||||
func mineLoop(client *minerClient, numberOfBlocks uint64, blockDelay uint64, mineWhenNotSynced bool) error {
|
||||
errChan := make(chan error)
|
||||
|
||||
templateStopChan := make(chan struct{})
|
||||
@ -35,7 +35,7 @@ func mineLoop(client *minerClient, numberOfBlocks uint64, blockDelay uint64) err
|
||||
wg := sync.WaitGroup{}
|
||||
for i := uint64(0); numberOfBlocks == 0 || i < numberOfBlocks; i++ {
|
||||
foundBlock := make(chan *util.Block)
|
||||
mineNextBlock(client, foundBlock, templateStopChan, errChan)
|
||||
mineNextBlock(client, foundBlock, mineWhenNotSynced, templateStopChan, errChan)
|
||||
block := <-foundBlock
|
||||
templateStopChan <- struct{}{}
|
||||
wg.Add(1)
|
||||
@ -80,13 +80,15 @@ func logHashRate() {
|
||||
})
|
||||
}
|
||||
|
||||
func mineNextBlock(client *minerClient, foundBlock chan *util.Block, templateStopChan chan struct{}, errChan chan error) {
|
||||
func mineNextBlock(client *minerClient, foundBlock chan *util.Block, mineWhenNotSynced bool,
|
||||
templateStopChan chan struct{}, errChan chan error) {
|
||||
|
||||
newTemplateChan := make(chan *rpcmodel.GetBlockTemplateResult)
|
||||
spawn(func() {
|
||||
templatesLoop(client, newTemplateChan, errChan, templateStopChan)
|
||||
})
|
||||
spawn(func() {
|
||||
solveLoop(newTemplateChan, foundBlock, errChan)
|
||||
solveLoop(newTemplateChan, foundBlock, mineWhenNotSynced, errChan)
|
||||
})
|
||||
}
|
||||
|
||||
@ -207,12 +209,23 @@ func getBlockTemplate(client *minerClient, longPollID string) (*rpcmodel.GetBloc
|
||||
return client.GetBlockTemplate([]string{"coinbasetxn"}, longPollID)
|
||||
}
|
||||
|
||||
func solveLoop(newTemplateChan chan *rpcmodel.GetBlockTemplateResult, foundBlock chan *util.Block, errChan chan error) {
|
||||
func solveLoop(newTemplateChan chan *rpcmodel.GetBlockTemplateResult, foundBlock chan *util.Block,
|
||||
mineWhenNotSynced bool, errChan chan error) {
|
||||
|
||||
var stopOldTemplateSolving chan struct{}
|
||||
for template := range newTemplateChan {
|
||||
if stopOldTemplateSolving != nil {
|
||||
close(stopOldTemplateSolving)
|
||||
}
|
||||
|
||||
if !template.IsSynced {
|
||||
if !mineWhenNotSynced {
|
||||
errChan <- errors.Errorf("got template with isSynced=false")
|
||||
return
|
||||
}
|
||||
log.Warnf("Got template with isSynced=false")
|
||||
}
|
||||
|
||||
stopOldTemplateSolving = make(chan struct{})
|
||||
block, err := parseBlock(template)
|
||||
if err != nil {
|
||||
|
@ -151,6 +151,7 @@ type GetBlockTemplateResult struct {
|
||||
CoinbaseTxn *GetBlockTemplateResultTx `json:"coinbaseTxn,omitempty"`
|
||||
CoinbaseValue *uint64 `json:"coinbaseValue,omitempty"`
|
||||
WorkID string `json:"workId,omitempty"`
|
||||
IsSynced bool `json:"isSynced"`
|
||||
|
||||
// Optional long polling from BIP 0022.
|
||||
LongPollID string `json:"longPollId,omitempty"`
|
||||
|
@ -71,6 +71,7 @@ type gbtWorkState struct {
|
||||
template *mining.BlockTemplate
|
||||
notifyMap map[string]map[int64]chan struct{}
|
||||
timeSource blockdag.TimeSource
|
||||
isSynced bool
|
||||
}
|
||||
|
||||
// newGbtWorkState returns a new instance of a gbtWorkState with all internal
|
||||
@ -105,17 +106,6 @@ func handleGetBlockTemplate(s *Server, cmd interface{}, closeChan <-chan struct{
|
||||
mode = request.Mode
|
||||
}
|
||||
|
||||
// No point in generating templates or processing proposals before
|
||||
// the DAG is synced. Note that we make a special check for when
|
||||
// we have nothing besides the genesis block (blueScore == 0),
|
||||
// because in that state IsCurrent may still return true.
|
||||
if !isSyncedForMining(s) {
|
||||
return nil, &rpcmodel.RPCError{
|
||||
Code: rpcmodel.ErrRPCClientInInitialDownload,
|
||||
Message: "Kaspa is downloading blocks...",
|
||||
}
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case "template":
|
||||
return handleGetBlockTemplateRequest(s, request, closeChan)
|
||||
@ -655,6 +645,15 @@ func (state *gbtWorkState) updateBlockTemplate(s *Server, useCoinbaseValue bool)
|
||||
// consensus rules.
|
||||
minTimestamp := s.cfg.DAG.NextBlockMinimumTime()
|
||||
|
||||
// Check whether this node is synced with the rest of of the
|
||||
// network. There's almost never a good reason to mine on top
|
||||
// of an unsynced DAG, and miners are generally expected not to
|
||||
// mine when isSynced is false.
|
||||
// This is not a straight-up error because the choice of whether
|
||||
// to mine or not is the responsibility of the miner rather
|
||||
// than the node's.
|
||||
isSynced := isSyncedForMining(s)
|
||||
|
||||
// Update work state to ensure another block template isn't
|
||||
// generated until needed.
|
||||
state.template = template
|
||||
@ -662,6 +661,7 @@ func (state *gbtWorkState) updateBlockTemplate(s *Server, useCoinbaseValue bool)
|
||||
state.lastTxUpdate = lastTxUpdate
|
||||
state.tipHashes = tipHashes
|
||||
state.minTimestamp = minTimestamp
|
||||
state.isSynced = isSynced
|
||||
|
||||
log.Debugf("Generated block template (timestamp %s, "+
|
||||
"target %s, merkle root %s)",
|
||||
@ -820,6 +820,7 @@ func (state *gbtWorkState) blockTemplateResult(dag *blockdag.BlockDAG, useCoinba
|
||||
Mutable: gbtMutableFields,
|
||||
NonceRange: gbtNonceRange,
|
||||
Capabilities: gbtCapabilities,
|
||||
IsSynced: state.isSynced,
|
||||
}
|
||||
|
||||
if useCoinbaseValue {
|
||||
|
@ -331,6 +331,7 @@ var helpDescsEnUS = map[string]string{
|
||||
"getBlockTemplateResult-nonceRange": "Two concatenated hex-encoded big-endian 64-bit integers which represent the valid ranges of nonces the miner may scan",
|
||||
"getBlockTemplateResult-capabilities": "List of server capabilities including 'proposal' to indicate support for block proposals",
|
||||
"getBlockTemplateResult-rejectReason": "Reason the proposal was invalid as-is (only applies to proposal responses)",
|
||||
"getBlockTemplateResult-isSynced": "Whether this node is synced with the rest of of the network. Miners are generally expected not to mine when isSynced is false",
|
||||
|
||||
// GetBlockTemplateCmd help.
|
||||
"getBlockTemplate--synopsis": "Returns a JSON object with information necessary to construct a block to mine or accepts a proposal to validate.\n" +
|
||||
|
Loading…
x
Reference in New Issue
Block a user