mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-03 09:56:38 -05:00
Remove use of CRPCTable::appendCommand in wallet code
This commit does not change behavior.
This commit is contained in:
parent
91868e6288
commit
4e4d9e9f85
10 changed files with 128 additions and 40 deletions
|
@ -15,12 +15,15 @@
|
||||||
#include <primitives/block.h>
|
#include <primitives/block.h>
|
||||||
#include <primitives/transaction.h>
|
#include <primitives/transaction.h>
|
||||||
#include <protocol.h>
|
#include <protocol.h>
|
||||||
|
#include <rpc/protocol.h>
|
||||||
|
#include <rpc/server.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <threadsafety.h>
|
#include <threadsafety.h>
|
||||||
#include <timedata.h>
|
#include <timedata.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
#include <univalue.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <validation.h>
|
#include <validation.h>
|
||||||
#include <validationinterface.h>
|
#include <validationinterface.h>
|
||||||
|
@ -212,6 +215,45 @@ public:
|
||||||
Chain::Notifications* m_notifications;
|
Chain::Notifications* m_notifications;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RpcHandlerImpl : public Handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RpcHandlerImpl(const CRPCCommand& command) : m_command(command), m_wrapped_command(&command)
|
||||||
|
{
|
||||||
|
m_command.actor = [this](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
|
||||||
|
if (!m_wrapped_command) return false;
|
||||||
|
try {
|
||||||
|
return m_wrapped_command->actor(request, result, last_handler);
|
||||||
|
} catch (const UniValue& e) {
|
||||||
|
// If this is not the last handler and a wallet not found
|
||||||
|
// exception was thrown, return false so the next handler can
|
||||||
|
// try to handle the request. Otherwise, reraise the exception.
|
||||||
|
if (!last_handler) {
|
||||||
|
const UniValue& code = e["code"];
|
||||||
|
if (code.isNum() && code.get_int() == RPC_WALLET_NOT_FOUND) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
::tableRPC.appendCommand(m_command.name, &m_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnect() override final
|
||||||
|
{
|
||||||
|
if (m_wrapped_command) {
|
||||||
|
m_wrapped_command = nullptr;
|
||||||
|
::tableRPC.removeCommand(m_command.name, &m_command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~RpcHandlerImpl() override { disconnect(); }
|
||||||
|
|
||||||
|
CRPCCommand m_command;
|
||||||
|
const CRPCCommand* m_wrapped_command;
|
||||||
|
};
|
||||||
|
|
||||||
class ChainImpl : public Chain
|
class ChainImpl : public Chain
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -310,8 +352,11 @@ public:
|
||||||
return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
|
return MakeUnique<NotificationsHandlerImpl>(*this, notifications);
|
||||||
}
|
}
|
||||||
void waitForNotifications() override { SyncWithValidationInterfaceQueue(); }
|
void waitForNotifications() override { SyncWithValidationInterfaceQueue(); }
|
||||||
|
std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) override
|
||||||
|
{
|
||||||
|
return MakeUnique<RpcHandlerImpl>(command);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
|
std::unique_ptr<Chain> MakeChain() { return MakeUnique<ChainImpl>(); }
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
class CBlock;
|
class CBlock;
|
||||||
class CFeeRate;
|
class CFeeRate;
|
||||||
|
class CRPCCommand;
|
||||||
class CScheduler;
|
class CScheduler;
|
||||||
class CValidationState;
|
class CValidationState;
|
||||||
class uint256;
|
class uint256;
|
||||||
|
@ -243,6 +244,10 @@ public:
|
||||||
|
|
||||||
//! Wait for pending notifications to be handled.
|
//! Wait for pending notifications to be handled.
|
||||||
virtual void waitForNotifications() = 0;
|
virtual void waitForNotifications() = 0;
|
||||||
|
|
||||||
|
//! Register handler for RPC. Command is not copied, so reference
|
||||||
|
//! needs to remain valid until Handler is disconnected.
|
||||||
|
virtual std::unique_ptr<Handler> handleRpc(const CRPCCommand& command) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Interface to let node manage chain clients (wallets, or maybe tools for
|
//! Interface to let node manage chain clients (wallets, or maybe tools for
|
||||||
|
|
|
@ -514,7 +514,7 @@ public:
|
||||||
: m_chain(chain), m_wallet_filenames(std::move(wallet_filenames))
|
: m_chain(chain), m_wallet_filenames(std::move(wallet_filenames))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void registerRpcs() override { return RegisterWalletRPCCommands(::tableRPC); }
|
void registerRpcs() override { return RegisterWalletRPCCommands(m_chain, m_rpc_handlers); }
|
||||||
bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); }
|
bool verify() override { return VerifyWallets(m_chain, m_wallet_filenames); }
|
||||||
bool load() override { return LoadWallets(m_chain, m_wallet_filenames); }
|
bool load() override { return LoadWallets(m_chain, m_wallet_filenames); }
|
||||||
void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
|
void start(CScheduler& scheduler) override { return StartWallets(scheduler); }
|
||||||
|
@ -524,6 +524,7 @@ public:
|
||||||
|
|
||||||
Chain& m_chain;
|
Chain& m_chain;
|
||||||
std::vector<std::string> m_wallet_filenames;
|
std::vector<std::string> m_wallet_filenames;
|
||||||
|
std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -30,6 +30,7 @@ static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server starte
|
||||||
static RPCTimerInterface* timerInterface = nullptr;
|
static RPCTimerInterface* timerInterface = nullptr;
|
||||||
/* Map of name to timer. */
|
/* Map of name to timer. */
|
||||||
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
|
static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers;
|
||||||
|
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler);
|
||||||
|
|
||||||
struct RPCCommandExecutionInfo
|
struct RPCCommandExecutionInfo
|
||||||
{
|
{
|
||||||
|
@ -173,11 +174,11 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
|
||||||
{
|
{
|
||||||
std::string strRet;
|
std::string strRet;
|
||||||
std::string category;
|
std::string category;
|
||||||
std::set<rpcfn_type> setDone;
|
std::set<intptr_t> setDone;
|
||||||
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
|
std::vector<std::pair<std::string, const CRPCCommand*> > vCommands;
|
||||||
|
|
||||||
for (const auto& entry : mapCommands)
|
for (const auto& entry : mapCommands)
|
||||||
vCommands.push_back(make_pair(entry.second->category + entry.first, entry.second));
|
vCommands.push_back(make_pair(entry.second.front()->category + entry.first, entry.second.front()));
|
||||||
sort(vCommands.begin(), vCommands.end());
|
sort(vCommands.begin(), vCommands.end());
|
||||||
|
|
||||||
JSONRPCRequest jreq(helpreq);
|
JSONRPCRequest jreq(helpreq);
|
||||||
|
@ -193,9 +194,9 @@ std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest&
|
||||||
jreq.strMethod = strMethod;
|
jreq.strMethod = strMethod;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
rpcfn_type pfn = pcmd->actor;
|
UniValue unused_result;
|
||||||
if (setDone.insert(pfn).second)
|
if (setDone.insert(pcmd->unique_id).second)
|
||||||
(*pfn)(jreq);
|
pcmd->actor(jreq, unused_result, true /* last_handler */);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -337,32 +338,32 @@ CRPCTable::CRPCTable()
|
||||||
const CRPCCommand *pcmd;
|
const CRPCCommand *pcmd;
|
||||||
|
|
||||||
pcmd = &vRPCCommands[vcidx];
|
pcmd = &vRPCCommands[vcidx];
|
||||||
mapCommands[pcmd->name] = pcmd;
|
mapCommands[pcmd->name].push_back(pcmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CRPCCommand *CRPCTable::operator[](const std::string &name) const
|
|
||||||
{
|
|
||||||
std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
|
|
||||||
if (it == mapCommands.end())
|
|
||||||
return nullptr;
|
|
||||||
return (*it).second;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
|
bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd)
|
||||||
{
|
{
|
||||||
if (IsRPCRunning())
|
if (IsRPCRunning())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// don't allow overwriting for now
|
mapCommands[name].push_back(pcmd);
|
||||||
std::map<std::string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
|
|
||||||
if (it != mapCommands.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
mapCommands[name] = pcmd;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd)
|
||||||
|
{
|
||||||
|
auto it = mapCommands.find(name);
|
||||||
|
if (it != mapCommands.end()) {
|
||||||
|
auto new_end = std::remove(it->second.begin(), it->second.end(), pcmd);
|
||||||
|
if (it->second.end() != new_end) {
|
||||||
|
it->second.erase(new_end, it->second.end());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void StartRPC()
|
void StartRPC()
|
||||||
{
|
{
|
||||||
LogPrint(BCLog::RPC, "Starting RPC\n");
|
LogPrint(BCLog::RPC, "Starting RPC\n");
|
||||||
|
@ -543,18 +544,28 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find method
|
// Find method
|
||||||
const CRPCCommand *pcmd = tableRPC[request.strMethod];
|
auto it = mapCommands.find(request.strMethod);
|
||||||
if (!pcmd)
|
if (it != mapCommands.end()) {
|
||||||
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
|
UniValue result;
|
||||||
|
for (const auto& command : it->second) {
|
||||||
|
if (ExecuteCommand(*command, request, result, &command == &it->second.back())) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ExecuteCommand(const CRPCCommand& command, const JSONRPCRequest& request, UniValue& result, bool last_handler)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RPCCommandExecution execution(request.strMethod);
|
RPCCommandExecution execution(request.strMethod);
|
||||||
// Execute, convert arguments to array if necessary
|
// Execute, convert arguments to array if necessary
|
||||||
if (request.params.isObject()) {
|
if (request.params.isObject()) {
|
||||||
return pcmd->actor(transformNamedArguments(request, pcmd->argNames));
|
return command.actor(transformNamedArguments(request, command.argNames), result, last_handler);
|
||||||
} else {
|
} else {
|
||||||
return pcmd->actor(request);
|
return command.actor(request, result, last_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
|
|
|
@ -131,10 +131,31 @@ typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
|
||||||
class CRPCCommand
|
class CRPCCommand
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
//! RPC method handler reading request and assigning result. Should return
|
||||||
|
//! true if request is fully handled, false if it should be passed on to
|
||||||
|
//! subsequent handlers.
|
||||||
|
using Actor = std::function<bool(const JSONRPCRequest& request, UniValue& result, bool last_handler)>;
|
||||||
|
|
||||||
|
//! Constructor taking Actor callback supporting multiple handlers.
|
||||||
|
CRPCCommand(std::string category, std::string name, Actor actor, std::vector<std::string> args, intptr_t unique_id)
|
||||||
|
: category(std::move(category)), name(std::move(name)), actor(std::move(actor)), argNames(std::move(args)),
|
||||||
|
unique_id(unique_id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Simplified constructor taking plain rpcfn_type function pointer.
|
||||||
|
CRPCCommand(const char* category, const char* name, rpcfn_type fn, std::initializer_list<const char*> args)
|
||||||
|
: CRPCCommand(category, name,
|
||||||
|
[fn](const JSONRPCRequest& request, UniValue& result, bool) { result = fn(request); return true; },
|
||||||
|
{args.begin(), args.end()}, intptr_t(fn))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::string category;
|
std::string category;
|
||||||
std::string name;
|
std::string name;
|
||||||
rpcfn_type actor;
|
Actor actor;
|
||||||
std::vector<std::string> argNames;
|
std::vector<std::string> argNames;
|
||||||
|
intptr_t unique_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,10 +164,9 @@ public:
|
||||||
class CRPCTable
|
class CRPCTable
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::map<std::string, const CRPCCommand*> mapCommands;
|
std::map<std::string, std::vector<const CRPCCommand*>> mapCommands;
|
||||||
public:
|
public:
|
||||||
CRPCTable();
|
CRPCTable();
|
||||||
const CRPCCommand* operator[](const std::string& name) const;
|
|
||||||
std::string help(const std::string& name, const JSONRPCRequest& helpreq) const;
|
std::string help(const std::string& name, const JSONRPCRequest& helpreq) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,9 +189,7 @@ public:
|
||||||
*
|
*
|
||||||
* Returns false if RPC server is already running (dump concurrency protection).
|
* Returns false if RPC server is already running (dump concurrency protection).
|
||||||
*
|
*
|
||||||
* Commands cannot be overwritten (returns false).
|
* Commands with different method names but the same unique_id will
|
||||||
*
|
|
||||||
* Commands with different method names but the same callback function will
|
|
||||||
* be considered aliases, and only the first registered method name will
|
* be considered aliases, and only the first registered method name will
|
||||||
* show up in the help text command listing. Aliased commands do not have
|
* show up in the help text command listing. Aliased commands do not have
|
||||||
* to have the same behavior. Server and client code can distinguish
|
* to have the same behavior. Server and client code can distinguish
|
||||||
|
@ -179,6 +197,7 @@ public:
|
||||||
* register different names, types, and numbers of parameters.
|
* register different names, types, and numbers of parameters.
|
||||||
*/
|
*/
|
||||||
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
|
bool appendCommand(const std::string& name, const CRPCCommand* pcmd);
|
||||||
|
bool removeCommand(const std::string& name, const CRPCCommand* pcmd);
|
||||||
};
|
};
|
||||||
|
|
||||||
bool IsDeprecatedRPCEnabled(const std::string& method);
|
bool IsDeprecatedRPCEnabled(const std::string& method);
|
||||||
|
|
|
@ -31,10 +31,9 @@ UniValue CallRPC(std::string args)
|
||||||
request.strMethod = strMethod;
|
request.strMethod = strMethod;
|
||||||
request.params = RPCConvertValues(strMethod, vArgs);
|
request.params = RPCConvertValues(strMethod, vArgs);
|
||||||
request.fHelp = false;
|
request.fHelp = false;
|
||||||
BOOST_CHECK(tableRPC[strMethod]);
|
if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
|
||||||
rpcfn_type method = tableRPC[strMethod]->actor;
|
|
||||||
try {
|
try {
|
||||||
UniValue result = (*method)(request);
|
UniValue result = tableRPC.execute(request);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (const UniValue& objError) {
|
catch (const UniValue& objError) {
|
||||||
|
|
|
@ -4156,8 +4156,8 @@ static const CRPCCommand commands[] =
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
void RegisterWalletRPCCommands(CRPCTable &t)
|
void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers)
|
||||||
{
|
{
|
||||||
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
|
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
|
||||||
t.appendCommand(commands[vcidx].name, &commands[vcidx]);
|
handlers.emplace_back(chain.handleRpc(commands[vcidx]));
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,9 @@
|
||||||
#ifndef BITCOIN_WALLET_RPCWALLET_H
|
#ifndef BITCOIN_WALLET_RPCWALLET_H
|
||||||
#define BITCOIN_WALLET_RPCWALLET_H
|
#define BITCOIN_WALLET_RPCWALLET_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CRPCTable;
|
class CRPCTable;
|
||||||
class CWallet;
|
class CWallet;
|
||||||
|
@ -14,7 +16,12 @@ class UniValue;
|
||||||
struct PartiallySignedTransaction;
|
struct PartiallySignedTransaction;
|
||||||
class CTransaction;
|
class CTransaction;
|
||||||
|
|
||||||
void RegisterWalletRPCCommands(CRPCTable &t);
|
namespace interfaces {
|
||||||
|
class Chain;
|
||||||
|
class Handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique_ptr<interfaces::Handler>>& handlers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Figures out what wallet, if any, to use for a JSONRPCRequest.
|
* Figures out what wallet, if any, to use for a JSONRPCRequest.
|
||||||
|
|
|
@ -15,5 +15,5 @@ WalletTestingSetup::WalletTestingSetup(const std::string& chainName):
|
||||||
m_wallet.LoadWallet(fFirstRun);
|
m_wallet.LoadWallet(fFirstRun);
|
||||||
m_wallet.m_chain_notifications_handler = m_chain->handleNotifications(m_wallet);
|
m_wallet.m_chain_notifications_handler = m_chain->handleNotifications(m_wallet);
|
||||||
|
|
||||||
RegisterWalletRPCCommands(tableRPC);
|
m_chain_client->registerRpcs();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ struct WalletTestingSetup: public TestingSetup {
|
||||||
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
|
explicit WalletTestingSetup(const std::string& chainName = CBaseChainParams::MAIN);
|
||||||
|
|
||||||
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
|
std::unique_ptr<interfaces::Chain> m_chain = interfaces::MakeChain();
|
||||||
|
std::unique_ptr<interfaces::ChainClient> m_chain_client = interfaces::MakeWalletClient(*m_chain, {});
|
||||||
CWallet m_wallet;
|
CWallet m_wallet;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue