add basic support for the help rpc command.
This commit is contained in:
parent
d3e4bcdcf5
commit
1487a352da
2 changed files with 157 additions and 55 deletions
203
rpcserver.go
203
rpcserver.go
|
@ -45,79 +45,96 @@ var (
|
||||||
type commandHandler func(*rpcServer, btcjson.Cmd) (interface{}, error)
|
type commandHandler func(*rpcServer, btcjson.Cmd) (interface{}, error)
|
||||||
|
|
||||||
// handlers maps RPC command strings to appropriate handler functions.
|
// handlers maps RPC command strings to appropriate handler functions.
|
||||||
var rpcHandlers = map[string]commandHandler{
|
// this is copied by init because help references rpcHandlers and thus causes
|
||||||
"addmultisigaddress": handleAskWallet,
|
// a dependancy loop.
|
||||||
|
var rpcHandlers map[string]commandHandler
|
||||||
|
var rpcHandlersBeforeInit = map[string]commandHandler{
|
||||||
"addnode": handleAddNode,
|
"addnode": handleAddNode,
|
||||||
"backupwallet": handleAskWallet,
|
|
||||||
"createmultisig": handleAskWallet,
|
|
||||||
"createrawtransaction": handleCreateRawTransaction,
|
"createrawtransaction": handleCreateRawTransaction,
|
||||||
"debuglevel": handleDebugLevel,
|
"debuglevel": handleDebugLevel,
|
||||||
"decoderawtransaction": handleDecodeRawTransaction,
|
"decoderawtransaction": handleDecodeRawTransaction,
|
||||||
"decodescript": handleDecodeScript,
|
"decodescript": handleDecodeScript,
|
||||||
"dumpprivkey": handleAskWallet,
|
|
||||||
"dumpwallet": handleAskWallet,
|
|
||||||
"encryptwallet": handleAskWallet,
|
|
||||||
"getaccount": handleAskWallet,
|
|
||||||
"getaccountaddress": handleAskWallet,
|
|
||||||
"getaddednodeinfo": handleUnimplemented,
|
|
||||||
"getaddressesbyaccount": handleAskWallet,
|
|
||||||
"getbalance": handleAskWallet,
|
|
||||||
"getbestblockhash": handleGetBestBlockHash,
|
"getbestblockhash": handleGetBestBlockHash,
|
||||||
"getblock": handleGetBlock,
|
"getblock": handleGetBlock,
|
||||||
"getblockcount": handleGetBlockCount,
|
"getblockcount": handleGetBlockCount,
|
||||||
"getblockhash": handleGetBlockHash,
|
"getblockhash": handleGetBlockHash,
|
||||||
"getblocktemplate": handleUnimplemented,
|
|
||||||
"getconnectioncount": handleGetConnectionCount,
|
"getconnectioncount": handleGetConnectionCount,
|
||||||
"getdifficulty": handleGetDifficulty,
|
"getdifficulty": handleGetDifficulty,
|
||||||
"getgenerate": handleGetGenerate,
|
"getgenerate": handleGetGenerate,
|
||||||
"gethashespersec": handleGetHashesPerSec,
|
"gethashespersec": handleGetHashesPerSec,
|
||||||
"getinfo": handleUnimplemented,
|
|
||||||
"getmininginfo": handleUnimplemented,
|
|
||||||
"getnettotals": handleUnimplemented,
|
|
||||||
"getnetworkhashps": handleUnimplemented,
|
|
||||||
"getnewaddress": handleUnimplemented,
|
|
||||||
"getpeerinfo": handleGetPeerInfo,
|
"getpeerinfo": handleGetPeerInfo,
|
||||||
"getrawchangeaddress": handleAskWallet,
|
|
||||||
"getrawmempool": handleGetRawMempool,
|
"getrawmempool": handleGetRawMempool,
|
||||||
"getrawtransaction": handleGetRawTransaction,
|
"getrawtransaction": handleGetRawTransaction,
|
||||||
"getreceivedbyaccount": handleAskWallet,
|
"help": handleHelp,
|
||||||
"getreceivedbyaddress": handleAskWallet,
|
|
||||||
"gettransaction": handleAskWallet,
|
|
||||||
"gettxout": handleAskWallet,
|
|
||||||
"gettxoutsetinfo": handleAskWallet,
|
|
||||||
"getwork": handleUnimplemented,
|
|
||||||
"help": handleUnimplemented,
|
|
||||||
"importprivkey": handleAskWallet,
|
|
||||||
"importwallet": handleAskWallet,
|
|
||||||
"keypoolrefill": handleAskWallet,
|
|
||||||
"listaccounts": handleAskWallet,
|
|
||||||
"listaddressgroupings": handleAskWallet,
|
|
||||||
"listlockunspent": handleAskWallet,
|
|
||||||
"listreceivedbyaccount": handleAskWallet,
|
|
||||||
"listreceivedbyaddress": handleAskWallet,
|
|
||||||
"listsinceblock": handleAskWallet,
|
|
||||||
"listtransactions": handleAskWallet,
|
|
||||||
"listunspent": handleAskWallet,
|
|
||||||
"lockunspent": handleAskWallet,
|
|
||||||
"move": handleAskWallet,
|
|
||||||
"ping": handleUnimplemented,
|
|
||||||
"sendfrom": handleAskWallet,
|
|
||||||
"sendmany": handleAskWallet,
|
|
||||||
"sendrawtransaction": handleSendRawTransaction,
|
"sendrawtransaction": handleSendRawTransaction,
|
||||||
"sendtoaddress": handleAskWallet,
|
|
||||||
"setaccount": handleAskWallet,
|
|
||||||
"setgenerate": handleSetGenerate,
|
"setgenerate": handleSetGenerate,
|
||||||
"settxfee": handleAskWallet,
|
|
||||||
"signmessage": handleAskWallet,
|
|
||||||
"signrawtransaction": handleAskWallet,
|
|
||||||
"stop": handleStop,
|
"stop": handleStop,
|
||||||
"submitblock": handleSubmitBlock,
|
"submitblock": handleSubmitBlock,
|
||||||
"validateaddress": handleAskWallet,
|
|
||||||
"verifychain": handleVerifyChain,
|
"verifychain": handleVerifyChain,
|
||||||
"verifymessage": handleAskWallet,
|
}
|
||||||
"walletlock": handleAskWallet,
|
|
||||||
"walletpassphrase": handleAskWallet,
|
func init() {
|
||||||
"walletpassphrasechange": handleAskWallet,
|
rpcHandlers = rpcHandlersBeforeInit
|
||||||
|
}
|
||||||
|
|
||||||
|
// list of commands that we recognise, but for which btcd has no support because
|
||||||
|
// it lacks support for wallet functionality. For these commands the user
|
||||||
|
// should ask a connected instance of btcwallet.
|
||||||
|
var rpcAskWallet = map[string]bool{
|
||||||
|
"addmultisigaddress": true,
|
||||||
|
"backupwallet": true,
|
||||||
|
"createmultisig": true,
|
||||||
|
"dumpprivkey": true,
|
||||||
|
"dumpwallet": true,
|
||||||
|
"encryptwallet": true,
|
||||||
|
"getaccount": true,
|
||||||
|
"getaccountaddress": true,
|
||||||
|
"getaddressesbyaccount": true,
|
||||||
|
"getbalance": true,
|
||||||
|
"getrawchangeaddress": true,
|
||||||
|
"getreceivedbyaccount": true,
|
||||||
|
"getreceivedbyaddress": true,
|
||||||
|
"gettransaction": true,
|
||||||
|
"gettxout": true,
|
||||||
|
"gettxoutsetinfo": true,
|
||||||
|
"importprivkey": true,
|
||||||
|
"importwallet": true,
|
||||||
|
"keypoolrefill": true,
|
||||||
|
"listaccounts": true,
|
||||||
|
"listaddressgroupings": true,
|
||||||
|
"listlockunspent": true,
|
||||||
|
"listreceivedbyaccount": true,
|
||||||
|
"listreceivedbyaddress": true,
|
||||||
|
"listsinceblock": true,
|
||||||
|
"listtransactions": true,
|
||||||
|
"listunspent": true,
|
||||||
|
"lockunspent": true,
|
||||||
|
"move": true,
|
||||||
|
"sendfrom": true,
|
||||||
|
"sendmany": true,
|
||||||
|
"sendtoaddress": true,
|
||||||
|
"setaccount": true,
|
||||||
|
"settxfee": true,
|
||||||
|
"signmessage": true,
|
||||||
|
"signrawtransaction": true,
|
||||||
|
"validateaddress": true,
|
||||||
|
"verifymessage": true,
|
||||||
|
"walletlock": true,
|
||||||
|
"walletpassphrase": true,
|
||||||
|
"walletpassphrasechange": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commands that are temporarily unimplemented.
|
||||||
|
var rpcUnimplemented = map[string]bool{
|
||||||
|
"getaddednodeinfo": true,
|
||||||
|
"getblocktemplate": true,
|
||||||
|
"getinfo": true,
|
||||||
|
"getmininginfo": true,
|
||||||
|
"getnettotals": true,
|
||||||
|
"getnetworkhashps": true,
|
||||||
|
"getnewaddress": true,
|
||||||
|
"getwork": true,
|
||||||
|
"ping": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// rpcServer holds the items the rpc server may need to access (config,
|
// rpcServer holds the items the rpc server may need to access (config,
|
||||||
|
@ -1011,6 +1028,70 @@ func createTxRawResult(net btcwire.BitcoinNet, txSha string, mtx *btcwire.MsgTx,
|
||||||
return txReply, nil
|
return txReply, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var helpAddenda = map[string]string{
|
||||||
|
"getgenerate": `
|
||||||
|
NOTE: btcd does not mine so this will always return false. The call is provided
|
||||||
|
for compatibility only.`,
|
||||||
|
"gethashespersec": `
|
||||||
|
NOTE: btcd does not mine so this will always return false. The call is provided
|
||||||
|
for compatibility only.`,
|
||||||
|
"getpeerinfo": `
|
||||||
|
NOTE: btcd does not currently implement all fields. the "bytessent",
|
||||||
|
"bytesrecv", "pingtime", "pingwait" and "syncnode" fields are not yet
|
||||||
|
implemented.`,
|
||||||
|
"sendrawtransaction": `
|
||||||
|
NOTE: btcd does not currently support the "allowhighfees" parameter.`,
|
||||||
|
"setgenerate": `
|
||||||
|
NOTE: btcd does not mine so command has no effect. The call is provided
|
||||||
|
for compatibility only.`,
|
||||||
|
}
|
||||||
|
|
||||||
|
// getHelp text retreives help text from btcjson for the command in question.
|
||||||
|
// If there is any extra btcd specific information related to the given command
|
||||||
|
// then this is appended to the string.
|
||||||
|
func getHelpText(cmdName string) (string, error) {
|
||||||
|
help, err := btcjson.GetHelpString(cmdName)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if helpAddendum, ok := helpAddenda[cmdName]; ok {
|
||||||
|
help += helpAddendum
|
||||||
|
}
|
||||||
|
|
||||||
|
return help, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleHelp implements the help command.
|
||||||
|
func handleHelp(s *rpcServer, cmd btcjson.Cmd) (interface{}, error) {
|
||||||
|
help := cmd.(*btcjson.HelpCmd)
|
||||||
|
|
||||||
|
// if no args we give a list of all known commands
|
||||||
|
if help.Command == "" {
|
||||||
|
commands := ""
|
||||||
|
first := true
|
||||||
|
// TODO(oga) this should have one liner usage for each command
|
||||||
|
// really, but for now just a list of commands is sufficient.
|
||||||
|
for k := range rpcHandlers {
|
||||||
|
if !first {
|
||||||
|
commands += "\n"
|
||||||
|
}
|
||||||
|
commands += k
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
return commands, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we actually support the command asked for. We only
|
||||||
|
// search the main list of hanlders since we do not wish to provide help
|
||||||
|
// for commands that are unimplemented or relate to wallet
|
||||||
|
// functionality.
|
||||||
|
if _, ok := rpcHandlers[help.Command]; !ok {
|
||||||
|
return "", fmt.Errorf("help: unknown command: %s", help.Command)
|
||||||
|
}
|
||||||
|
|
||||||
|
return getHelpText(help.Command)
|
||||||
|
}
|
||||||
|
|
||||||
// handleSendRawTransaction implements the sendrawtransaction command.
|
// handleSendRawTransaction implements the sendrawtransaction command.
|
||||||
func handleSendRawTransaction(s *rpcServer, cmd btcjson.Cmd) (interface{}, error) {
|
func handleSendRawTransaction(s *rpcServer, cmd btcjson.Cmd) (interface{}, error) {
|
||||||
c := cmd.(*btcjson.SendRawTransactionCmd)
|
c := cmd.(*btcjson.SendRawTransactionCmd)
|
||||||
|
@ -1174,10 +1255,22 @@ func standardCmdReply(cmd btcjson.Cmd, s *rpcServer) (reply btcjson.Reply) {
|
||||||
reply.Id = &id
|
reply.Id = &id
|
||||||
|
|
||||||
handler, ok := rpcHandlers[cmd.Method()]
|
handler, ok := rpcHandlers[cmd.Method()]
|
||||||
if !ok {
|
if ok {
|
||||||
reply.Error = &btcjson.ErrMethodNotFound
|
goto handled
|
||||||
return reply
|
|
||||||
}
|
}
|
||||||
|
_, ok = rpcAskWallet[cmd.Method()]
|
||||||
|
if ok {
|
||||||
|
handler = handleAskWallet
|
||||||
|
goto handled
|
||||||
|
}
|
||||||
|
_, ok = rpcUnimplemented[cmd.Method()]
|
||||||
|
if ok {
|
||||||
|
handler = handleUnimplemented
|
||||||
|
goto handled
|
||||||
|
}
|
||||||
|
reply.Error = &btcjson.ErrMethodNotFound
|
||||||
|
return reply
|
||||||
|
handled:
|
||||||
|
|
||||||
result, err := handler(s, cmd)
|
result, err := handler(s, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -64,6 +64,7 @@ var commandHandlers = map[string]*handlerData{
|
||||||
"getpeerinfo": &handlerData{0, 0, displayJSONDump, nil, makeGetPeerInfo, ""},
|
"getpeerinfo": &handlerData{0, 0, displayJSONDump, nil, makeGetPeerInfo, ""},
|
||||||
"getrawmempool": &handlerData{0, 1, displayJSONDump, []conversionHandler{toBool}, makeGetRawMempool, "[verbose=false]"},
|
"getrawmempool": &handlerData{0, 1, displayJSONDump, []conversionHandler{toBool}, makeGetRawMempool, "[verbose=false]"},
|
||||||
"getrawtransaction": &handlerData{1, 1, displayJSONDump, []conversionHandler{nil, toBool}, makeGetRawTransaction, "<txhash> [verbose=false]"},
|
"getrawtransaction": &handlerData{1, 1, displayJSONDump, []conversionHandler{nil, toBool}, makeGetRawTransaction, "<txhash> [verbose=false]"},
|
||||||
|
"help": &handlerData{0, 1, displayGeneric, nil, makeHelp, "[commandName]"},
|
||||||
"importprivkey": &handlerData{1, 2, displayGeneric, []conversionHandler{nil, nil, toBool}, makeImportPrivKey, "<wifprivkey> [label] [rescan=true]"},
|
"importprivkey": &handlerData{1, 2, displayGeneric, []conversionHandler{nil, nil, toBool}, makeImportPrivKey, "<wifprivkey> [label] [rescan=true]"},
|
||||||
"listtransactions": &handlerData{0, 3, displayJSONDump, []conversionHandler{nil, toInt, toInt}, makeListTransactions, "[account] [count=10] [from=0]"},
|
"listtransactions": &handlerData{0, 3, displayJSONDump, []conversionHandler{nil, toInt, toInt}, makeListTransactions, "[account] [count=10] [from=0]"},
|
||||||
"verifychain": &handlerData{0, 2, displayJSONDump, []conversionHandler{toInt, toInt}, makeVerifyChain, "[level] [numblocks]"},
|
"verifychain": &handlerData{0, 2, displayJSONDump, []conversionHandler{toInt, toInt}, makeVerifyChain, "[level] [numblocks]"},
|
||||||
|
@ -302,6 +303,14 @@ func makeGetRawMempool(args []interface{}) (btcjson.Cmd, error) {
|
||||||
return btcjson.NewGetRawMempoolCmd("btcctl", opt...)
|
return btcjson.NewGetRawMempoolCmd("btcctl", opt...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeHelp(args []interface{}) (btcjson.Cmd, error) {
|
||||||
|
opt := make([]string, 0, 1)
|
||||||
|
if len(args) > 0 {
|
||||||
|
opt = append(opt, args[0].(string))
|
||||||
|
}
|
||||||
|
return btcjson.NewHelpCmd("btcctl", opt...)
|
||||||
|
}
|
||||||
|
|
||||||
// makeRawTransaction generates the cmd structure for
|
// makeRawTransaction generates the cmd structure for
|
||||||
// getrawtransaction comands.
|
// getrawtransaction comands.
|
||||||
func makeGetRawTransaction(args []interface{}) (btcjson.Cmd, error) {
|
func makeGetRawTransaction(args []interface{}) (btcjson.Cmd, error) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue