wallet3 rpc initial commit

omq rpc intitialization; needs parameters

legacy rpc call definitions, descriptions, boilerplate, and addition
to omq rpc registry
This commit is contained in:
Thomas Winget 2022-02-14 17:15:28 -05:00
parent a6c88e3a18
commit e65cfb8ab6
13 changed files with 3996 additions and 30 deletions

View File

@ -8,10 +8,20 @@ add_library(wallet3
output_selection/output_selection.cpp
decoy_selection/decoy_selection.cpp
wallet.cpp
wallet2½.cpp)
wallet2½.cpp
rpc/command_parser.cpp
rpc/request_handler.cpp
rpc/omq_server.cpp)
target_link_libraries(wallet3
PUBLIC
rpc_common
common
nlohmann_json::nlohmann_json
oxenmq::oxenmq
PRIVATE
cryptonote_basic
cryptonote_core
SQLiteCpp)
cryptonote_protocol
cryptonote_basic
cryptonote_core
extra
SQLiteCpp)

View File

@ -6,7 +6,6 @@
#include <crypto/crypto.h>
#include <cryptonote_basic/subaddress_index.h>
#include <ringct/rctTypes.h>
#include <sqlitedb/database.hpp>
namespace wallet
{

View File

@ -0,0 +1,44 @@
# Copyright (c) 2018, The Loki Project
# Copyright (c) 2014-2019, The Monero Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
add_library(wallet3_rpc
command_parser.cpp
request_handler.cpp
omq_server.cpp
)
target_link_libraries(wallet3_rpc
PUBLIC
rpc_common
common
nlohmann_json::nlohmann_json
oxenmq::oxenmq
PRIVATE
cryptonote_protocol
extra)

View File

@ -0,0 +1,310 @@
#include "command_parser.h"
#include "oxenmq/bt_serialize.h"
#include "rpc/common/param_parser.hpp"
#include <nlohmann/json.hpp>
namespace wallet::rpc {
using nlohmann::json;
using cryptonote::rpc::required;
using rpc_input = std::variant<std::monostate, nlohmann::json, oxenmq::bt_dict_consumer>;
void parse_request(GET_BALANCE& argname, rpc_input in) {
}
void parse_request(GET_ADDRESS& argname, rpc_input in) {
}
void parse_request(GET_ADDRESS_INDEX& argname, rpc_input in) {
}
void parse_request(CREATE_ADDRESS& argname, rpc_input in) {
}
void parse_request(LABEL_ADDRESS& argname, rpc_input in) {
}
void parse_request(GET_ACCOUNTS& argname, rpc_input in) {
}
void parse_request(CREATE_ACCOUNT& argname, rpc_input in) {
}
void parse_request(LABEL_ACCOUNT& argname, rpc_input in) {
}
void parse_request(GET_ACCOUNT_TAGS& argname, rpc_input in) {
}
void parse_request(TAG_ACCOUNTS& argname, rpc_input in) {
}
void parse_request(UNTAG_ACCOUNTS& argname, rpc_input in) {
}
void parse_request(SET_ACCOUNT_TAG_DESCRIPTION& argname, rpc_input in) {
}
void parse_request(GET_HEIGHT& argname, rpc_input in) {
}
void parse_request(TRANSFER& argname, rpc_input in) {
}
void parse_request(TRANSFER_SPLIT& argname, rpc_input in) {
}
void parse_request(DESCRIBE_TRANSFER& argname, rpc_input in) {
}
void parse_request(SIGN_TRANSFER& argname, rpc_input in) {
}
void parse_request(SUBMIT_TRANSFER& argname, rpc_input in) {
}
void parse_request(SWEEP_DUST& argname, rpc_input in) {
}
void parse_request(SWEEP_ALL& argname, rpc_input in) {
}
void parse_request(SWEEP_SINGLE& argname, rpc_input in) {
}
void parse_request(RELAY_TX& argname, rpc_input in) {
}
void parse_request(STORE& argname, rpc_input in) {
}
void parse_request(GET_PAYMENTS& argname, rpc_input in) {
}
void parse_request(GET_BULK_PAYMENTS& argname, rpc_input in) {
}
void parse_request(INCOMING_TRANSFERS& argname, rpc_input in) {
}
void parse_request(QUERY_KEY& argname, rpc_input in) {
}
void parse_request(MAKE_INTEGRATED_ADDRESS& argname, rpc_input in) {
}
void parse_request(SPLIT_INTEGRATED_ADDRESS& argname, rpc_input in) {
}
void parse_request(STOP_WALLET& argname, rpc_input in) {
}
void parse_request(RESCAN_BLOCKCHAIN& argname, rpc_input in) {
}
void parse_request(SET_TX_NOTES& argname, rpc_input in) {
}
void parse_request(GET_TX_NOTES& argname, rpc_input in) {
}
void parse_request(SET_ATTRIBUTE& argname, rpc_input in) {
}
void parse_request(GET_ATTRIBUTE& argname, rpc_input in) {
}
void parse_request(GET_TX_KEY& argname, rpc_input in) {
}
void parse_request(CHECK_TX_KEY& argname, rpc_input in) {
}
void parse_request(GET_TX_PROOF& argname, rpc_input in) {
}
void parse_request(CHECK_TX_PROOF& argname, rpc_input in) {
}
void parse_request(GET_SPEND_PROOF& argname, rpc_input in) {
}
void parse_request(CHECK_SPEND_PROOF& argname, rpc_input in) {
}
void parse_request(GET_RESERVE_PROOF& argname, rpc_input in) {
}
void parse_request(CHECK_RESERVE_PROOF& argname, rpc_input in) {
}
void parse_request(GET_TRANSFERS& argname, rpc_input in) {
}
void parse_request(GET_TRANSFERS_CSV& argname, rpc_input in) {
}
void parse_request(GET_TRANSFER_BY_TXID& argname, rpc_input in) {
}
void parse_request(SIGN& argname, rpc_input in) {
}
void parse_request(VERIFY& argname, rpc_input in) {
}
void parse_request(EXPORT_OUTPUTS& argname, rpc_input in) {
}
void parse_request(EXPORT_TRANSFERS& argname, rpc_input in) {
}
void parse_request(IMPORT_OUTPUTS& argname, rpc_input in) {
}
void parse_request(EXPORT_KEY_IMAGES& argname, rpc_input in) {
}
void parse_request(IMPORT_KEY_IMAGES& argname, rpc_input in) {
}
void parse_request(MAKE_URI& argname, rpc_input in) {
}
void parse_request(PARSE_URI& argname, rpc_input in) {
}
void parse_request(ADD_ADDRESS_BOOK_ENTRY& argname, rpc_input in) {
}
void parse_request(EDIT_ADDRESS_BOOK_ENTRY& argname, rpc_input in) {
}
void parse_request(GET_ADDRESS_BOOK_ENTRY& argname, rpc_input in) {
}
void parse_request(DELETE_ADDRESS_BOOK_ENTRY& argname, rpc_input in) {
}
void parse_request(RESCAN_SPENT& argname, rpc_input in) {
}
void parse_request(REFRESH& argname, rpc_input in) {
}
void parse_request(AUTO_REFRESH& argname, rpc_input in) {
}
void parse_request(START_MINING& argname, rpc_input in) {
}
void parse_request(STOP_MINING& argname, rpc_input in) {
}
void parse_request(GET_LANGUAGES& argname, rpc_input in) {
}
void parse_request(CREATE_WALLET& argname, rpc_input in) {
}
void parse_request(OPEN_WALLET& argname, rpc_input in) {
}
void parse_request(CLOSE_WALLET& argname, rpc_input in) {
}
void parse_request(CHANGE_WALLET_PASSWORD& argname, rpc_input in) {
}
void parse_request(GENERATE_FROM_KEYS& argname, rpc_input in) {
}
void parse_request(RESTORE_DETERMINISTIC_WALLET& argname, rpc_input in) {
}
void parse_request(IS_MULTISIG& argname, rpc_input in) {
}
void parse_request(PREPARE_MULTISIG& argname, rpc_input in) {
}
void parse_request(MAKE_MULTISIG& argname, rpc_input in) {
}
void parse_request(EXPORT_MULTISIG& argname, rpc_input in) {
}
void parse_request(IMPORT_MULTISIG& argname, rpc_input in) {
}
void parse_request(FINALIZE_MULTISIG& argname, rpc_input in) {
}
void parse_request(EXCHANGE_MULTISIG_KEYS& argname, rpc_input in) {
}
void parse_request(SIGN_MULTISIG& argname, rpc_input in) {
}
void parse_request(SUBMIT_MULTISIG& argname, rpc_input in) {
}
void parse_request(GET_VERSION& argname, rpc_input in) {
}
void parse_request(STAKE& argname, rpc_input in) {
}
void parse_request(REGISTER_SERVICE_NODE& argname, rpc_input in) {
}
void parse_request(REQUEST_STAKE_UNLOCK& argname, rpc_input in) {
}
void parse_request(CAN_REQUEST_STAKE_UNLOCK& argname, rpc_input in) {
}
void parse_request(VALIDATE_ADDRESS& argname, rpc_input in) {
}
void parse_request(SET_DAEMON& argname, rpc_input in) {
}
void parse_request(SET_LOG_LEVEL& argname, rpc_input in) {
}
void parse_request(SET_LOG_CATEGORIES& argname, rpc_input in) {
}
void parse_request(ONS_BUY_MAPPING& argname, rpc_input in) {
}
void parse_request(ONS_RENEW_MAPPING& argname, rpc_input in) {
}
void parse_request(ONS_UPDATE_MAPPING& argname, rpc_input in) {
}
void parse_request(ONS_MAKE_UPDATE_SIGNATURE& argname, rpc_input in) {
}
void parse_request(ONS_HASH_NAME& argname, rpc_input in) {
}
void parse_request(ONS_KNOWN_NAMES& argname, rpc_input in) {
}
void parse_request(ONS_ADD_KNOWN_NAMES& argname, rpc_input in) {
}
void parse_request(ONS_ENCRYPT_VALUE& argname, rpc_input in) {
}
void parse_request(ONS_DECRYPT_VALUE& argname, rpc_input in) {
}
} // namespace wallet::rpc

View File

@ -0,0 +1,112 @@
#pragma once
#include "commands.h"
#include <nlohmann/json.hpp>
#include <oxenmq/bt_serialize.h>
namespace wallet::rpc {
using rpc_input = std::variant<std::monostate, nlohmann::json, oxenmq::bt_dict_consumer>;
inline void parse_request(NO_ARGS&, rpc_input) {}
void parse_request(GET_BALANCE& argname, rpc_input in);
void parse_request(GET_ADDRESS& argname, rpc_input in);
void parse_request(GET_ADDRESS_INDEX& argname, rpc_input in);
void parse_request(CREATE_ADDRESS& argname, rpc_input in);
void parse_request(LABEL_ADDRESS& argname, rpc_input in);
void parse_request(GET_ACCOUNTS& argname, rpc_input in);
void parse_request(CREATE_ACCOUNT& argname, rpc_input in);
void parse_request(LABEL_ACCOUNT& argname, rpc_input in);
void parse_request(GET_ACCOUNT_TAGS& argname, rpc_input in);
void parse_request(TAG_ACCOUNTS& argname, rpc_input in);
void parse_request(UNTAG_ACCOUNTS& argname, rpc_input in);
void parse_request(SET_ACCOUNT_TAG_DESCRIPTION& argname, rpc_input in);
void parse_request(GET_HEIGHT& argname, rpc_input in);
void parse_request(TRANSFER& argname, rpc_input in);
void parse_request(TRANSFER_SPLIT& argname, rpc_input in);
void parse_request(DESCRIBE_TRANSFER& argname, rpc_input in);
void parse_request(SIGN_TRANSFER& argname, rpc_input in);
void parse_request(SUBMIT_TRANSFER& argname, rpc_input in);
void parse_request(SWEEP_DUST& argname, rpc_input in);
void parse_request(SWEEP_ALL& argname, rpc_input in);
void parse_request(SWEEP_SINGLE& argname, rpc_input in);
void parse_request(RELAY_TX& argname, rpc_input in);
void parse_request(STORE& argname, rpc_input in);
void parse_request(GET_PAYMENTS& argname, rpc_input in);
void parse_request(GET_BULK_PAYMENTS& argname, rpc_input in);
void parse_request(INCOMING_TRANSFERS& argname, rpc_input in);
void parse_request(QUERY_KEY& argname, rpc_input in);
void parse_request(MAKE_INTEGRATED_ADDRESS& argname, rpc_input in);
void parse_request(SPLIT_INTEGRATED_ADDRESS& argname, rpc_input in);
void parse_request(STOP_WALLET& argname, rpc_input in);
void parse_request(RESCAN_BLOCKCHAIN& argname, rpc_input in);
void parse_request(SET_TX_NOTES& argname, rpc_input in);
void parse_request(GET_TX_NOTES& argname, rpc_input in);
void parse_request(SET_ATTRIBUTE& argname, rpc_input in);
void parse_request(GET_ATTRIBUTE& argname, rpc_input in);
void parse_request(GET_TX_KEY& argname, rpc_input in);
void parse_request(CHECK_TX_KEY& argname, rpc_input in);
void parse_request(GET_TX_PROOF& argname, rpc_input in);
void parse_request(CHECK_TX_PROOF& argname, rpc_input in);
void parse_request(GET_SPEND_PROOF& argname, rpc_input in);
void parse_request(CHECK_SPEND_PROOF& argname, rpc_input in);
void parse_request(GET_RESERVE_PROOF& argname, rpc_input in);
void parse_request(CHECK_RESERVE_PROOF& argname, rpc_input in);
void parse_request(GET_TRANSFERS& argname, rpc_input in);
void parse_request(GET_TRANSFERS_CSV& argname, rpc_input in);
void parse_request(GET_TRANSFER_BY_TXID& argname, rpc_input in);
void parse_request(SIGN& argname, rpc_input in);
void parse_request(VERIFY& argname, rpc_input in);
void parse_request(EXPORT_OUTPUTS& argname, rpc_input in);
void parse_request(EXPORT_TRANSFERS& argname, rpc_input in);
void parse_request(IMPORT_OUTPUTS& argname, rpc_input in);
void parse_request(EXPORT_KEY_IMAGES& argname, rpc_input in);
void parse_request(IMPORT_KEY_IMAGES& argname, rpc_input in);
void parse_request(MAKE_URI& argname, rpc_input in);
void parse_request(PARSE_URI& argname, rpc_input in);
void parse_request(ADD_ADDRESS_BOOK_ENTRY& argname, rpc_input in);
void parse_request(EDIT_ADDRESS_BOOK_ENTRY& argname, rpc_input in);
void parse_request(GET_ADDRESS_BOOK_ENTRY& argname, rpc_input in);
void parse_request(DELETE_ADDRESS_BOOK_ENTRY& argname, rpc_input in);
void parse_request(RESCAN_SPENT& argname, rpc_input in);
void parse_request(REFRESH& argname, rpc_input in);
void parse_request(AUTO_REFRESH& argname, rpc_input in);
void parse_request(START_MINING& argname, rpc_input in);
void parse_request(STOP_MINING& argname, rpc_input in);
void parse_request(GET_LANGUAGES& argname, rpc_input in);
void parse_request(CREATE_WALLET& argname, rpc_input in);
void parse_request(OPEN_WALLET& argname, rpc_input in);
void parse_request(CLOSE_WALLET& argname, rpc_input in);
void parse_request(CHANGE_WALLET_PASSWORD& argname, rpc_input in);
void parse_request(GENERATE_FROM_KEYS& argname, rpc_input in);
void parse_request(RESTORE_DETERMINISTIC_WALLET& argname, rpc_input in);
void parse_request(IS_MULTISIG& argname, rpc_input in);
void parse_request(PREPARE_MULTISIG& argname, rpc_input in);
void parse_request(MAKE_MULTISIG& argname, rpc_input in);
void parse_request(EXPORT_MULTISIG& argname, rpc_input in);
void parse_request(IMPORT_MULTISIG& argname, rpc_input in);
void parse_request(FINALIZE_MULTISIG& argname, rpc_input in);
void parse_request(EXCHANGE_MULTISIG_KEYS& argname, rpc_input in);
void parse_request(SIGN_MULTISIG& argname, rpc_input in);
void parse_request(SUBMIT_MULTISIG& argname, rpc_input in);
void parse_request(GET_VERSION& argname, rpc_input in);
void parse_request(STAKE& argname, rpc_input in);
void parse_request(REGISTER_SERVICE_NODE& argname, rpc_input in);
void parse_request(REQUEST_STAKE_UNLOCK& argname, rpc_input in);
void parse_request(CAN_REQUEST_STAKE_UNLOCK& argname, rpc_input in);
void parse_request(VALIDATE_ADDRESS& argname, rpc_input in);
void parse_request(SET_DAEMON& argname, rpc_input in);
void parse_request(SET_LOG_LEVEL& argname, rpc_input in);
void parse_request(SET_LOG_CATEGORIES& argname, rpc_input in);
void parse_request(ONS_BUY_MAPPING& argname, rpc_input in);
void parse_request(ONS_RENEW_MAPPING& argname, rpc_input in);
void parse_request(ONS_UPDATE_MAPPING& argname, rpc_input in);
void parse_request(ONS_MAKE_UPDATE_SIGNATURE& argname, rpc_input in);
void parse_request(ONS_HASH_NAME& argname, rpc_input in);
void parse_request(ONS_KNOWN_NAMES& argname, rpc_input in);
void parse_request(ONS_ADD_KNOWN_NAMES& argname, rpc_input in);
void parse_request(ONS_ENCRYPT_VALUE& argname, rpc_input in);
void parse_request(ONS_DECRYPT_VALUE& argname, rpc_input in);
} // namespace wallet::rpc

2885
src/wallet3/rpc/commands.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,99 @@
#include "omq_server.h"
#include "request_handler.h"
#include "commands.h"
#include <oxenmq/oxenmq.h>
#include <oxenmq/auth.h>
//TODO: get logging working in wallet3 and remove this
#include <iostream>
namespace {
// LMQ RPC responses consist of [CODE, DATA] for code we (partially) mimic HTTP error codes: 200
// means success, anything else means failure. (We don't have codes for Forbidden or Not Found
// because those happen at the LMQ protocol layer).
constexpr std::string_view
LMQ_OK{"200"sv},
LMQ_BAD_REQUEST{"400"sv},
LMQ_ERROR{"500"sv};
} // anonymous namespace
namespace wallet::rpc
{
using namespace cryptonote::rpc;
using oxenmq::AuthLevel;
OmqServer::OmqServer(std::shared_ptr<oxenmq::OxenMQ> omq, RequestHandler& request_handler)
: omq(omq)
, request_handler(request_handler)
{
//TODO: parametrize listening address(es) and auth
omq->listen_plain("ipc://./rpc.sock");
omq->add_category("rpc", AuthLevel::none, 0 /*no reserved threads*/, 100 /*max queued requests*/);
omq->add_category("restricted", AuthLevel::basic, 0 /*no reserved threads*/, 100 /*max queued requests*/);
//TODO: admin commands for wallet RPC?
//omq->add_category("admin", oxenmq::AuthLevel::admin, 1 /* one reserved admin command thread */);
for (auto& cmd : rpc_commands) {
omq->add_request_command(cmd.second->is_restricted ? "restricted" : "rpc", cmd.first,
[name=std::string_view{cmd.first}, &call=*cmd.second, &request_handler, this](oxenmq::Message& m) {
if (m.data.size() > 1)
m.send_reply(LMQ_BAD_REQUEST, "Bad request: RPC commands must have at most one data part "
"(received " + std::to_string(m.data.size()) + ")");
rpc_request request{};
request.context.admin = m.access.auth >= AuthLevel::admin;
request.context.source = rpc_source::omq;
request.context.remote = m.remote;
if (!m.data.empty())
request.body = m.data[0];
try {
auto result = std::visit([](auto&& v) -> std::string {
using T = decltype(v);
if constexpr (std::is_same_v<oxenmq::bt_value&&, T>)
return bt_serialize(std::move(v));
else if constexpr (std::is_same_v<nlohmann::json&&, T>)
return v.dump();
else {
static_assert(std::is_same_v<std::string&&, T>);
return std::move(v);
}
}, call.invoke(std::move(request), request_handler));
m.send_reply(LMQ_OK, std::move(result));
return;
} catch (const parse_error& e) {
// This isn't really WARNable as it's the client fault; log at info level instead.
//
// TODO: for various parsing errors there are still some stupid forced ERROR-level
// warnings that get generated deep inside epee, for example when passing a string or
// number instead of a JSON object. If you want to find some, `grep number2 epee` (for
// real).
std::cout << "LMQ RPC request '" << (call.is_restricted ? "restricted." : "rpc.") << name << "' called with invalid/unparseable data: " << e.what() << "\n";
m.send_reply(LMQ_BAD_REQUEST, "Unable to parse request: "s + e.what());
return;
} catch (const rpc_error& e) {
std::cout << "LMQ RPC request '" << (call.is_restricted ? "restricted." : "rpc.") << name << "' failed with: " << e.what() << "\n";
m.send_reply(LMQ_ERROR, e.what());
return;
} catch (const std::exception& e) {
std::cout << "LMQ RPC request '" << (call.is_restricted ? "restricted." : "rpc.") << name << "' "
"raised an exception: " << e.what() << "\n";
} catch (...) {
std::cout << "LMQ RPC request '" << (call.is_restricted ? "restricted." : "rpc.") << name << "' "
"raised an unknown exception" << "\n";
}
// Don't include the exception message in case it contains something that we don't want go
// back to the user. If we want to support it eventually we could add some sort of
// `rpc::user_visible_exception` that carries a message to send back to the user.
m.send_reply(LMQ_ERROR, "An exception occured while processing your request");
});
}
}
} // namespace wallet::rpc

View File

@ -0,0 +1,25 @@
#pragma once
#include <memory>
namespace oxenmq { class OxenMQ; }
namespace wallet::rpc
{
class RequestHandler;
class OmqServer
{
std::shared_ptr<oxenmq::OxenMQ> omq;
RequestHandler& request_handler;
public:
OmqServer(std::shared_ptr<oxenmq::OxenMQ> omq, RequestHandler& request_handler);
};
} // namespace wallet::rpc

View File

@ -0,0 +1,349 @@
#include "request_handler.h"
#include "commands.h"
#include "command_parser.h"
#include <wallet3/wallet.hpp>
#include <sqlitedb/database.hpp>
#include <unordered_map>
#include <memory>
namespace wallet::rpc {
using cryptonote::rpc::rpc_context;
using cryptonote::rpc::rpc_request;
namespace {
template <typename RPC>
void register_rpc_command(std::unordered_map<std::string, std::shared_ptr<const rpc_command>>& regs)
{
using cryptonote::rpc::RPC_COMMAND;
using cryptonote::rpc::RESTRICTED;
static_assert(std::is_base_of_v<RPC_COMMAND, RPC>);
auto cmd = std::make_shared<rpc_command>();
cmd->is_restricted = std::is_base_of_v<RESTRICTED, RPC>;
cmd->invoke = cryptonote::rpc::make_invoke<RPC, RequestHandler, rpc_command>();
for (const auto& name : RPC::names())
regs.emplace(name, cmd);
}
template <typename... RPC, typename... BinaryRPC>
std::unordered_map<std::string, std::shared_ptr<const rpc_command>> register_rpc_commands(tools::type_list<RPC...>) {
std::unordered_map<std::string, std::shared_ptr<const rpc_command>> regs;
(register_rpc_command<RPC>(regs), ...);
return regs;
}
} // anonymous namespace
const std::unordered_map<std::string, std::shared_ptr<const rpc_command>> rpc_commands = register_rpc_commands(wallet_rpc_types{});
void RequestHandler::invoke(GET_BALANCE& command, rpc_context context) {
}
void RequestHandler::invoke(GET_ADDRESS& command, rpc_context context) {
}
void RequestHandler::invoke(GET_ADDRESS_INDEX& command, rpc_context context) {
}
void RequestHandler::invoke(CREATE_ADDRESS& command, rpc_context context) {
}
void RequestHandler::invoke(LABEL_ADDRESS& command, rpc_context context) {
}
void RequestHandler::invoke(GET_ACCOUNTS& command, rpc_context context) {
}
void RequestHandler::invoke(CREATE_ACCOUNT& command, rpc_context context) {
}
void RequestHandler::invoke(LABEL_ACCOUNT& command, rpc_context context) {
}
void RequestHandler::invoke(GET_ACCOUNT_TAGS& command, rpc_context context) {
}
void RequestHandler::invoke(TAG_ACCOUNTS& command, rpc_context context) {
}
void RequestHandler::invoke(UNTAG_ACCOUNTS& command, rpc_context context) {
}
void RequestHandler::invoke(SET_ACCOUNT_TAG_DESCRIPTION& command, rpc_context context) {
}
void RequestHandler::invoke(GET_HEIGHT& command, rpc_context context) {
auto height = wallet.db->prepared_get<int64_t>("SELECT COUNT(*) FROM blocks;");
command.response["height"] = height;
//TODO: this
command.response["immutable_height"] = height;
}
void RequestHandler::invoke(TRANSFER& command, rpc_context context) {
}
void RequestHandler::invoke(TRANSFER_SPLIT& command, rpc_context context) {
}
void RequestHandler::invoke(DESCRIBE_TRANSFER& command, rpc_context context) {
}
void RequestHandler::invoke(SIGN_TRANSFER& command, rpc_context context) {
}
void RequestHandler::invoke(SUBMIT_TRANSFER& command, rpc_context context) {
}
void RequestHandler::invoke(SWEEP_DUST& command, rpc_context context) {
}
void RequestHandler::invoke(SWEEP_ALL& command, rpc_context context) {
}
void RequestHandler::invoke(SWEEP_SINGLE& command, rpc_context context) {
}
void RequestHandler::invoke(RELAY_TX& command, rpc_context context) {
}
void RequestHandler::invoke(STORE& command, rpc_context context) {
}
void RequestHandler::invoke(GET_PAYMENTS& command, rpc_context context) {
}
void RequestHandler::invoke(GET_BULK_PAYMENTS& command, rpc_context context) {
}
void RequestHandler::invoke(INCOMING_TRANSFERS& command, rpc_context context) {
}
void RequestHandler::invoke(QUERY_KEY& command, rpc_context context) {
}
void RequestHandler::invoke(MAKE_INTEGRATED_ADDRESS& command, rpc_context context) {
}
void RequestHandler::invoke(SPLIT_INTEGRATED_ADDRESS& command, rpc_context context) {
}
void RequestHandler::invoke(STOP_WALLET& command, rpc_context context) {
}
void RequestHandler::invoke(RESCAN_BLOCKCHAIN& command, rpc_context context) {
}
void RequestHandler::invoke(SET_TX_NOTES& command, rpc_context context) {
}
void RequestHandler::invoke(GET_TX_NOTES& command, rpc_context context) {
}
void RequestHandler::invoke(SET_ATTRIBUTE& command, rpc_context context) {
}
void RequestHandler::invoke(GET_ATTRIBUTE& command, rpc_context context) {
}
void RequestHandler::invoke(GET_TX_KEY& command, rpc_context context) {
}
void RequestHandler::invoke(CHECK_TX_KEY& command, rpc_context context) {
}
void RequestHandler::invoke(GET_TX_PROOF& command, rpc_context context) {
}
void RequestHandler::invoke(CHECK_TX_PROOF& command, rpc_context context) {
}
void RequestHandler::invoke(GET_SPEND_PROOF& command, rpc_context context) {
}
void RequestHandler::invoke(CHECK_SPEND_PROOF& command, rpc_context context) {
}
void RequestHandler::invoke(GET_RESERVE_PROOF& command, rpc_context context) {
}
void RequestHandler::invoke(CHECK_RESERVE_PROOF& command, rpc_context context) {
}
void RequestHandler::invoke(GET_TRANSFERS& command, rpc_context context) {
}
void RequestHandler::invoke(GET_TRANSFERS_CSV& command, rpc_context context) {
}
void RequestHandler::invoke(GET_TRANSFER_BY_TXID& command, rpc_context context) {
}
void RequestHandler::invoke(SIGN& command, rpc_context context) {
}
void RequestHandler::invoke(VERIFY& command, rpc_context context) {
}
void RequestHandler::invoke(EXPORT_OUTPUTS& command, rpc_context context) {
}
void RequestHandler::invoke(EXPORT_TRANSFERS& command, rpc_context context) {
}
void RequestHandler::invoke(IMPORT_OUTPUTS& command, rpc_context context) {
}
void RequestHandler::invoke(EXPORT_KEY_IMAGES& command, rpc_context context) {
}
void RequestHandler::invoke(IMPORT_KEY_IMAGES& command, rpc_context context) {
}
void RequestHandler::invoke(MAKE_URI& command, rpc_context context) {
}
void RequestHandler::invoke(PARSE_URI& command, rpc_context context) {
}
void RequestHandler::invoke(ADD_ADDRESS_BOOK_ENTRY& command, rpc_context context) {
}
void RequestHandler::invoke(EDIT_ADDRESS_BOOK_ENTRY& command, rpc_context context) {
}
void RequestHandler::invoke(GET_ADDRESS_BOOK_ENTRY& command, rpc_context context) {
}
void RequestHandler::invoke(DELETE_ADDRESS_BOOK_ENTRY& command, rpc_context context) {
}
void RequestHandler::invoke(RESCAN_SPENT& command, rpc_context context) {
}
void RequestHandler::invoke(REFRESH& command, rpc_context context) {
}
void RequestHandler::invoke(AUTO_REFRESH& command, rpc_context context) {
}
void RequestHandler::invoke(START_MINING& command, rpc_context context) {
}
void RequestHandler::invoke(STOP_MINING& command, rpc_context context) {
}
void RequestHandler::invoke(GET_LANGUAGES& command, rpc_context context) {
}
void RequestHandler::invoke(CREATE_WALLET& command, rpc_context context) {
}
void RequestHandler::invoke(OPEN_WALLET& command, rpc_context context) {
}
void RequestHandler::invoke(CLOSE_WALLET& command, rpc_context context) {
}
void RequestHandler::invoke(CHANGE_WALLET_PASSWORD& command, rpc_context context) {
}
void RequestHandler::invoke(GENERATE_FROM_KEYS& command, rpc_context context) {
}
void RequestHandler::invoke(RESTORE_DETERMINISTIC_WALLET& command, rpc_context context) {
}
void RequestHandler::invoke(IS_MULTISIG& command, rpc_context context) {
}
void RequestHandler::invoke(PREPARE_MULTISIG& command, rpc_context context) {
}
void RequestHandler::invoke(MAKE_MULTISIG& command, rpc_context context) {
}
void RequestHandler::invoke(EXPORT_MULTISIG& command, rpc_context context) {
}
void RequestHandler::invoke(IMPORT_MULTISIG& command, rpc_context context) {
}
void RequestHandler::invoke(FINALIZE_MULTISIG& command, rpc_context context) {
}
void RequestHandler::invoke(EXCHANGE_MULTISIG_KEYS& command, rpc_context context) {
}
void RequestHandler::invoke(SIGN_MULTISIG& command, rpc_context context) {
}
void RequestHandler::invoke(SUBMIT_MULTISIG& command, rpc_context context) {
}
void RequestHandler::invoke(GET_VERSION& command, rpc_context context) {
}
void RequestHandler::invoke(STAKE& command, rpc_context context) {
}
void RequestHandler::invoke(REGISTER_SERVICE_NODE& command, rpc_context context) {
}
void RequestHandler::invoke(REQUEST_STAKE_UNLOCK& command, rpc_context context) {
}
void RequestHandler::invoke(CAN_REQUEST_STAKE_UNLOCK& command, rpc_context context) {
}
void RequestHandler::invoke(VALIDATE_ADDRESS& command, rpc_context context) {
}
void RequestHandler::invoke(SET_DAEMON& command, rpc_context context) {
}
void RequestHandler::invoke(SET_LOG_LEVEL& command, rpc_context context) {
}
void RequestHandler::invoke(SET_LOG_CATEGORIES& command, rpc_context context) {
}
void RequestHandler::invoke(ONS_BUY_MAPPING& command, rpc_context context) {
}
void RequestHandler::invoke(ONS_RENEW_MAPPING& command, rpc_context context) {
}
void RequestHandler::invoke(ONS_UPDATE_MAPPING& command, rpc_context context) {
}
void RequestHandler::invoke(ONS_MAKE_UPDATE_SIGNATURE& command, rpc_context context) {
}
void RequestHandler::invoke(ONS_HASH_NAME& command, rpc_context context) {
}
void RequestHandler::invoke(ONS_KNOWN_NAMES& command, rpc_context context) {
}
void RequestHandler::invoke(ONS_ADD_KNOWN_NAMES& command, rpc_context context) {
}
void RequestHandler::invoke(ONS_ENCRYPT_VALUE& command, rpc_context context) {
}
void RequestHandler::invoke(ONS_DECRYPT_VALUE& command, rpc_context context) {
}
} // namespace wallet::rpc

View File

@ -0,0 +1,146 @@
#pragma once
#include "commands.h"
#include "rpc/common/rpc_command.h"
#include <nlohmann/json.hpp>
#include <oxenmq/bt_value.h>
#include <string>
#include <unordered_map>
namespace wallet {
class Wallet;
}
namespace wallet::rpc {
class RequestHandler;
using cryptonote::rpc::rpc_context;
using cryptonote::rpc::rpc_request;
/// Stores an RPC command callback. These are set up in request_handler.cpp.
struct rpc_command {
using result_type = std::variant<oxenmq::bt_value, nlohmann::json, std::string>;
// Called with the incoming command data; returns the response body if all goes well,
// otherwise throws an exception.
result_type(*invoke)(rpc_request&&, RequestHandler&);
bool is_restricted; // only callable via restricted RPC
};
/// RPC command registration; to add a new command, define it in commands.h
/// and then actually do the registration in request_handler.cpp.
extern const std::unordered_map<std::string, std::shared_ptr<const rpc_command>> rpc_commands;
class RequestHandler {
wallet::Wallet& wallet;
public:
RequestHandler(wallet::Wallet& wallet) : wallet(wallet) {};
void invoke(GET_BALANCE& command, rpc_context context);
void invoke(GET_ADDRESS& command, rpc_context context);
void invoke(GET_ADDRESS_INDEX& command, rpc_context context);
void invoke(CREATE_ADDRESS& command, rpc_context context);
void invoke(LABEL_ADDRESS& command, rpc_context context);
void invoke(GET_ACCOUNTS& command, rpc_context context);
void invoke(CREATE_ACCOUNT& command, rpc_context context);
void invoke(LABEL_ACCOUNT& command, rpc_context context);
void invoke(GET_ACCOUNT_TAGS& command, rpc_context context);
void invoke(TAG_ACCOUNTS& command, rpc_context context);
void invoke(UNTAG_ACCOUNTS& command, rpc_context context);
void invoke(SET_ACCOUNT_TAG_DESCRIPTION& command, rpc_context context);
void invoke(GET_HEIGHT& command, rpc_context context);
void invoke(TRANSFER& command, rpc_context context);
void invoke(TRANSFER_SPLIT& command, rpc_context context);
void invoke(DESCRIBE_TRANSFER& command, rpc_context context);
void invoke(SIGN_TRANSFER& command, rpc_context context);
void invoke(SUBMIT_TRANSFER& command, rpc_context context);
void invoke(SWEEP_DUST& command, rpc_context context);
void invoke(SWEEP_ALL& command, rpc_context context);
void invoke(SWEEP_SINGLE& command, rpc_context context);
void invoke(RELAY_TX& command, rpc_context context);
void invoke(STORE& command, rpc_context context);
void invoke(GET_PAYMENTS& command, rpc_context context);
void invoke(GET_BULK_PAYMENTS& command, rpc_context context);
void invoke(INCOMING_TRANSFERS& command, rpc_context context);
void invoke(QUERY_KEY& command, rpc_context context);
void invoke(MAKE_INTEGRATED_ADDRESS& command, rpc_context context);
void invoke(SPLIT_INTEGRATED_ADDRESS& command, rpc_context context);
void invoke(STOP_WALLET& command, rpc_context context);
void invoke(RESCAN_BLOCKCHAIN& command, rpc_context context);
void invoke(SET_TX_NOTES& command, rpc_context context);
void invoke(GET_TX_NOTES& command, rpc_context context);
void invoke(SET_ATTRIBUTE& command, rpc_context context);
void invoke(GET_ATTRIBUTE& command, rpc_context context);
void invoke(GET_TX_KEY& command, rpc_context context);
void invoke(CHECK_TX_KEY& command, rpc_context context);
void invoke(GET_TX_PROOF& command, rpc_context context);
void invoke(CHECK_TX_PROOF& command, rpc_context context);
void invoke(GET_SPEND_PROOF& command, rpc_context context);
void invoke(CHECK_SPEND_PROOF& command, rpc_context context);
void invoke(GET_RESERVE_PROOF& command, rpc_context context);
void invoke(CHECK_RESERVE_PROOF& command, rpc_context context);
void invoke(GET_TRANSFERS& command, rpc_context context);
void invoke(GET_TRANSFERS_CSV& command, rpc_context context);
void invoke(GET_TRANSFER_BY_TXID& command, rpc_context context);
void invoke(SIGN& command, rpc_context context);
void invoke(VERIFY& command, rpc_context context);
void invoke(EXPORT_OUTPUTS& command, rpc_context context);
void invoke(EXPORT_TRANSFERS& command, rpc_context context);
void invoke(IMPORT_OUTPUTS& command, rpc_context context);
void invoke(EXPORT_KEY_IMAGES& command, rpc_context context);
void invoke(IMPORT_KEY_IMAGES& command, rpc_context context);
void invoke(MAKE_URI& command, rpc_context context);
void invoke(PARSE_URI& command, rpc_context context);
void invoke(ADD_ADDRESS_BOOK_ENTRY& command, rpc_context context);
void invoke(EDIT_ADDRESS_BOOK_ENTRY& command, rpc_context context);
void invoke(GET_ADDRESS_BOOK_ENTRY& command, rpc_context context);
void invoke(DELETE_ADDRESS_BOOK_ENTRY& command, rpc_context context);
void invoke(RESCAN_SPENT& command, rpc_context context);
void invoke(REFRESH& command, rpc_context context);
void invoke(AUTO_REFRESH& command, rpc_context context);
void invoke(START_MINING& command, rpc_context context);
void invoke(STOP_MINING& command, rpc_context context);
void invoke(GET_LANGUAGES& command, rpc_context context);
void invoke(CREATE_WALLET& command, rpc_context context);
void invoke(OPEN_WALLET& command, rpc_context context);
void invoke(CLOSE_WALLET& command, rpc_context context);
void invoke(CHANGE_WALLET_PASSWORD& command, rpc_context context);
void invoke(GENERATE_FROM_KEYS& command, rpc_context context);
void invoke(RESTORE_DETERMINISTIC_WALLET& command, rpc_context context);
void invoke(IS_MULTISIG& command, rpc_context context);
void invoke(PREPARE_MULTISIG& command, rpc_context context);
void invoke(MAKE_MULTISIG& command, rpc_context context);
void invoke(EXPORT_MULTISIG& command, rpc_context context);
void invoke(IMPORT_MULTISIG& command, rpc_context context);
void invoke(FINALIZE_MULTISIG& command, rpc_context context);
void invoke(EXCHANGE_MULTISIG_KEYS& command, rpc_context context);
void invoke(SIGN_MULTISIG& command, rpc_context context);
void invoke(SUBMIT_MULTISIG& command, rpc_context context);
void invoke(GET_VERSION& command, rpc_context context);
void invoke(STAKE& command, rpc_context context);
void invoke(REGISTER_SERVICE_NODE& command, rpc_context context);
void invoke(REQUEST_STAKE_UNLOCK& command, rpc_context context);
void invoke(CAN_REQUEST_STAKE_UNLOCK& command, rpc_context context);
void invoke(VALIDATE_ADDRESS& command, rpc_context context);
void invoke(SET_DAEMON& command, rpc_context context);
void invoke(SET_LOG_LEVEL& command, rpc_context context);
void invoke(SET_LOG_CATEGORIES& command, rpc_context context);
void invoke(ONS_BUY_MAPPING& command, rpc_context context);
void invoke(ONS_RENEW_MAPPING& command, rpc_context context);
void invoke(ONS_UPDATE_MAPPING& command, rpc_context context);
void invoke(ONS_MAKE_UPDATE_SIGNATURE& command, rpc_context context);
void invoke(ONS_HASH_NAME& command, rpc_context context);
void invoke(ONS_KNOWN_NAMES& command, rpc_context context);
void invoke(ONS_ADD_KNOWN_NAMES& command, rpc_context context);
void invoke(ONS_ENCRYPT_VALUE& command, rpc_context context);
void invoke(ONS_DECRYPT_VALUE& command, rpc_context context);
};
} // namespace wallet::rpc

View File

@ -31,6 +31,8 @@ namespace wallet
, tx_scanner{keys, db}
, tx_constructor{tx_constructor}
, daemon_comms{daemon_comms}
, request_handler{*this}
, omq_server{omq, request_handler}
{
create_schema(db->db);
last_scanned_height = db->prepared_get<int64_t>("SELECT last_scan_height FROM metadata WHERE id=0;");
@ -40,6 +42,8 @@ namespace wallet
void
Wallet::init()
{
omq->start();
daemon_comms->set_remote("ipc://./oxend.sock");
daemon_comms->register_wallet(*this, last_scanned_height + 1 /*next needed block*/, true);
}

View File

@ -5,6 +5,9 @@
#include "daemon_comms.hpp"
#include "keyring.hpp"
#include "rpc/request_handler.h"
#include "rpc/omq_server.h"
#include <memory>
#include <string_view>
@ -25,6 +28,8 @@ namespace wallet
class Wallet : public std::enable_shared_from_this<Wallet>
{
friend class wallet::rpc::RequestHandler;
protected:
Wallet(
std::shared_ptr<oxenmq::OxenMQ> omq,
@ -108,6 +113,8 @@ namespace wallet
TransactionScanner tx_scanner;
std::shared_ptr<TransactionConstructor> tx_constructor;
std::shared_ptr<DaemonComms> daemon_comms;
wallet::rpc::RequestHandler request_handler;
wallet::rpc::OmqServer omq_server;
bool running = true;
};

View File

@ -28,9 +28,8 @@ int main(void)
auto oxenmq = std::make_shared<oxenmq::OxenMQ>();
auto comms = std::make_shared<wallet::DefaultDaemonComms>(oxenmq);
comms->set_remote("ipc://./oxend.sock");
oxenmq->start();
auto ctor = std::make_shared<wallet::TransactionConstructor>(nullptr, comms);
auto wallet = wallet::Wallet::create(oxenmq, keyring, ctor, comms, ":memory:", "");
std::this_thread::sleep_for(2s);
@ -38,34 +37,11 @@ int main(void)
std::cout << "chain height: " << chain_height << "\n";
std::shared_ptr<wallet::Wallet> wallet2{nullptr};
bool made_second = false;
bool dereg_second = false;
while (true)
{
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
std::cout << "after block " << wallet->last_scanned_height << ", balance is: " << wallet->get_balance() << "\n";
if (wallet->last_scanned_height > 5000 and not made_second)
{
wallet2 = wallet::Wallet::create(oxenmq, keyring, ctor, comms, ":memory:", "");
made_second = true;
}
if (wallet2)
{
std::cout << "after block " << wallet2->last_scanned_height << ", wallet2 balance is: " << wallet2->get_balance() << "\n";
if (wallet2->last_scanned_height > 3000)
{
if (not dereg_second)
{
wallet2->deregister();
dereg_second = true;
}
std::cout << "After deregister(), ref count = " << wallet2.use_count() << "\n";
}
}
}
}