From bb276b53aa82df22ee626acf37741106cc576c79 Mon Sep 17 00:00:00 2001 From: "Owain G. Ainsworth" Date: Tue, 12 Nov 2013 16:39:10 +0000 Subject: [PATCH] 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 --- rpcserver.go | 57 ++++++++++++++++++++++++++++++++++++++++++- util/btcctl/btcctl.go | 9 +++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/rpcserver.go b/rpcserver.go index 5b8d4aed1..25b1e56c6 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -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. diff --git a/util/btcctl/btcctl.go b/util/btcctl/btcctl.go index 04ad8cdca..02e2e9f66 100644 --- a/util/btcctl/btcctl.go +++ b/util/btcctl/btcctl.go @@ -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, " [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.