Add support for the verifychain command.

So far we only do level 0 and level 1 checks (precense and basic
sanity). The checks done at higher levels in bitcoind are closely
coupled with their database layout.

arguably Closes #13
This commit is contained in:
Owain G. Ainsworth 2013-11-12 16:39:10 +00:00
parent 31f27cffd5
commit bb276b53aa
2 changed files with 65 additions and 1 deletions

View file

@ -466,7 +466,7 @@ var handlers = map[string]commandHandler{
"stop": handleStop,
"submitblock": handleUnimplemented,
"validateaddress": handleAskWallet,
"verifychain": handleUnimplemented,
"verifychain": handleVerifyChain,
"verifymessage": handleAskWallet,
"walletlock": handleAskWallet,
"walletpassphrase": handleAskWallet,
@ -819,6 +819,61 @@ func handleStop(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (
return "btcd stopping.", nil
}
func verifyChain(db btcdb.Db, level, depth int32) error {
_, curheight64, err := db.NewestSha()
if err != nil {
log.Errorf("RPCS: verify is unable to fetch current block "+
"height: %v", err)
}
curheight := int32(curheight64)
if depth > curheight {
depth = curheight
}
for height := curheight; height > (curheight - depth); height-- {
// Level 0 just looks up the block.
sha, err := db.FetchBlockShaByHeight(int64(height))
if err != nil {
log.Errorf("RPCS: verify is unable to fetch block at "+
"height %d: %v", height, err)
return err
}
block, err := db.FetchBlockBySha(sha)
if err != nil {
log.Errorf("RPCS: verify is unable to fetch block at "+
"sha %v height %d: %v", sha, height, err)
return err
}
// Level 1 does basic chain sanity checks.
if level > 0 {
err := btcchain.CheckBlockSanity(block,
activeNetParams.powLimit)
if err != nil {
log.Errorf("RPCS: verify is unable to "+
"validate block at sha %v height "+
"%s: %v", sha, height, err)
return err
}
}
}
log.Infof("RPCS: Chain verify completed successfully")
return nil
}
func handleVerifyChain(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (interface{}, error) {
c := cmd.(*btcjson.VerifyChainCmd)
err := verifyChain(s.server.db, c.CheckLevel, c.CheckDepth)
if err != nil {
}
return "", nil
}
// parseCmd parses a marshaled known command, returning any errors as a
// btcjson.Error that can be used in replies. The returned cmd may still
// be non-nil if b is at least a valid marshaled JSON-RPC message.

View file

@ -60,6 +60,7 @@ var commandHandlers = map[string]*handlerData{
"getpeerinfo": &handlerData{0, 0, displaySpewDump, nil, makeGetPeerInfo, ""},
"getrawmempool": &handlerData{0, 0, displaySpewDump, nil, makeGetRawMempool, ""},
"getrawtransaction": &handlerData{1, 1, displaySpewDump, []conversionHandler{nil, toInt}, makeGetRawTransaction, "<txhash> [verbose=0]"},
"verifychain": &handlerData{0, 2, displaySpewDump, []conversionHandler{toInt, toInt}, makeVerifyChain, "[level] [depth]"},
"stop": &handlerData{0, 0, displayGeneric, nil, makeStop, ""},
}
@ -192,6 +193,14 @@ func makeStop(args []interface{}) (btcjson.Cmd, error) {
return btcjson.NewStopCmd("btcctl")
}
func makeVerifyChain(args []interface{}) (btcjson.Cmd, error) {
iargs := make([]int32, 0, 2)
for _, i := range args {
iargs = append(iargs, int32(i.(int)))
}
return btcjson.NewVerifyChainCmd("btcctl", iargs...)
}
// send sends a JSON-RPC command to the specified RPC server and examines the
// results for various error conditions. It either returns a valid result or
// an appropriate error.