diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index a0beaa35..78529494 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -3484,7 +3484,7 @@ TEST (rpc, wallet_create_fail) { system.poll (); } - ASSERT_EQ ("Failed to create wallet. Increase lmdb_max_dbs in node config.", response.json.get ("error")); + ASSERT_EQ ("Failed to create wallet. Increase lmdb_max_dbs in node config", response.json.get ("error")); } TEST (rpc, wallet_ledger) diff --git a/rai/lib/errors.cpp b/rai/lib/errors.cpp index 0a14f040..d686e3a3 100644 --- a/rai/lib/errors.cpp +++ b/rai/lib/errors.cpp @@ -10,22 +10,42 @@ std::string nano::error_common_messages::message (int ev) const return "Account already exists"; case nano::error_common::account_not_found: return "Account not found"; + case nano::error_common::account_not_found_wallet: + return "Account not found in wallet"; case nano::error_common::bad_account_number: return "Bad account number"; + case nano::error_common::bad_private_key: + return "Bad private key"; case nano::error_common::bad_public_key: return "Bad public key"; case nano::error_common::bad_seed: return "Bad seed"; + case nano::error_common::bad_threshold: + return "Bad threshold number"; case nano::error_common::bad_wallet_number: return "Bad wallet number"; case nano::error_common::bad_work_format: return "Bad work"; - case nano::error_common::invalid_work: - return "Invalid work"; + case nano::error_common::insufficient_balance: + return "Insufficient balance"; + case nano::error_common::invalid_amount: + return "Invalid amount number"; + case nano::error_common::invalid_amount_big: + return "Amount too big"; + case nano::error_common::invalid_count: + return "Invalid count"; + case nano::error_common::invalid_ip_address: + return "Invalid IP address"; + case nano::error_common::invalid_port: + return "Invalid port"; case nano::error_common::invalid_index: return "Invalid index"; + case nano::error_common::invalid_work: + return "Invalid work"; case nano::error_common::numeric_conversion: return "Numeric conversion error"; + case nano::error_common::wallet_lmdb_max_dbs: + return "Failed to create wallet. Increase lmdb_max_dbs in node config"; case nano::error_common::wallet_locked: return "Wallet is locked"; case nano::error_common::wallet_not_found: @@ -43,10 +63,108 @@ std::string nano::error_blocks_messages::message (int ev) const return "Unknown error"; case nano::error_blocks::bad_hash_number: return "Bad hash number"; + case nano::error_blocks::invalid_block: + return "Block is invalid"; case nano::error_blocks::invalid_block_hash: return "Invalid block hash"; + case nano::error_blocks::invalid_type: + return "Invalid block type"; case nano::error_blocks::not_found: return "Block not found"; + case nano::error_blocks::work_low: + return "Block work is less than threshold"; + } + + return "Invalid error code"; +} + +std::string nano::error_rpc_messages::message (int ev) const +{ + switch (static_cast (ev)) + { + case nano::error_rpc::generic: + return "Unknown error"; + case nano::error_rpc::bad_destination: + return "Bad destination account"; + case nano::error_rpc::bad_key: + return "Bad key"; + case nano::error_rpc::bad_link: + return "Bad link number"; + case nano::error_rpc::bad_previous: + return "Bad previous"; + case nano::error_rpc::bad_representative_number: + return "Bad representative number"; + case nano::error_rpc::bad_source: + return "Bad source"; + case nano::error_rpc::bad_timeout: + return "Bad timeout number"; + case nano::error_rpc::block_create_balance_mismatch: + return "Balance mismatch for previous block"; + case nano::error_rpc::block_create_key_required: + return "Private key or local wallet and account required"; + case nano::error_rpc::block_create_public_key_mismatch: + return "Incorrect key for given account"; + case nano::error_rpc::block_create_requirements_state: + return "Previous, representative, final balance and link (source or destination) are required"; + case nano::error_rpc::block_create_requirements_open: + return "Representative account and source hash required"; + case nano::error_rpc::block_create_requirements_receive: + return "Previous hash and source hash required"; + case nano::error_rpc::block_create_requirements_change: + return "Representative account and previous hash required"; + case nano::error_rpc::block_create_requirements_send: + return "Destination account, previous hash, current balance and amount required"; + case nano::error_rpc::invalid_balance: + return "Invalid balance number"; + case nano::error_rpc::invalid_destinations: + return "Invalid destinations number"; + case nano::error_rpc::invalid_offset: + return "Invalid offset"; + case nano::error_rpc::invalid_missing_type: + return "Invalid or missing type argument"; + case nano::error_rpc::invalid_sources: + return "Invalid sources number"; + case nano::error_rpc::payment_account_balance: + return "Account has non-zero balance"; + case nano::error_rpc::payment_unable_create_account: + return "Unable to create transaction account"; + case nano::error_rpc::rpc_control_disabled: + return "RPC control is disabled"; + case nano::error_rpc::source_not_found: + return "Source not found"; + } + + return "Invalid error code"; +} + +std::string nano::error_process_messages::message (int ev) const +{ + switch (static_cast (ev)) + { + case nano::error_process::generic: + return "Unknown error"; + case nano::error_process::bad_signature: + return "Bad signature"; + case nano::error_process::old: + return "Old block"; + case nano::error_process::negative_spend: + return "Negative spend"; + case nano::error_process::fork: + return "Fork"; + case nano::error_process::unreceivable: + return "Unreceivable"; + case nano::error_process::gap_previous: + return "Gap previous block"; + case nano::error_process::gap_source: + return "Gap source block"; + case nano::error_process::opened_burn_account: + return "Burning account"; + case nano::error_process::balance_mismatch: + return "Balance and amount delta do not match"; + case nano::error_process::block_position: + return "This block cannot follow the previous block"; + case nano::error_process::other: + "Error processing block"; } return "Invalid error code"; diff --git a/rai/lib/errors.hpp b/rai/lib/errors.hpp index 5878fac0..22a2c2c7 100644 --- a/rai/lib/errors.hpp +++ b/rai/lib/errors.hpp @@ -29,15 +29,25 @@ enum class error_common { generic = 1, account_not_found, + account_not_found_wallet, account_exists, bad_account_number, + bad_private_key, bad_public_key, bad_seed, + bad_threshold, bad_wallet_number, bad_work_format, - invalid_work, + invalid_amount, + invalid_amount_big, + invalid_count, invalid_index, + invalid_ip_address, + invalid_port, + invalid_work, + insufficient_balance, numeric_conversion, + wallet_lmdb_max_dbs, wallet_locked, wallet_not_found }; @@ -47,8 +57,58 @@ enum class error_blocks { generic = 1, bad_hash_number, + invalid_block, invalid_block_hash, - not_found + invalid_type, + not_found, + work_low +}; + +/** RPC related errors */ +enum class error_rpc +{ + generic = 1, + bad_destination, + bad_key, + bad_link, + bad_previous, + bad_representative_number, + bad_source, + bad_timeout, + block_create_balance_mismatch, + block_create_key_required, + block_create_public_key_mismatch, + block_create_requirements_state, + block_create_requirements_open, + block_create_requirements_receive, + block_create_requirements_change, + block_create_requirements_send, + invalid_balance, + invalid_destinations, + invalid_offset, + invalid_missing_type, + invalid_sources, + payment_account_balance, + payment_unable_create_account, + rpc_control_disabled, + source_not_found +}; + +/** process_result related errors */ +enum class error_process +{ + generic = 1, + bad_signature, // Signature was bad, forged or transmission error + old, // Already seen and was valid + negative_spend, // Malicious attempt to spend a negative amount + fork, // Malicious fork based on previous + unreceivable, // Source block doesn't exist or has already been received + gap_previous, // Block marked as previous is unknown + gap_source, // Block marked as source is unknown + opened_burn_account, // The impossible happened, someone found the private key associated with the public key '0'. + balance_mismatch, // Balance and amount delta don't match + block_position, // This block cannot follow the previous block + other }; } @@ -95,3 +155,5 @@ enum class error_blocks REGISTER_ERROR_CODES (nano, error_common); REGISTER_ERROR_CODES (nano, error_blocks); +REGISTER_ERROR_CODES (nano, error_rpc); +REGISTER_ERROR_CODES (nano, error_process); diff --git a/rai/lib/numbers.cpp b/rai/lib/numbers.cpp index fcac09eb..296bdc7e 100644 --- a/rai/lib/numbers.cpp +++ b/rai/lib/numbers.cpp @@ -422,6 +422,13 @@ void rai::deterministic_key (rai::uint256_union const & seed_a, uint32_t index_a blake2b_final (&hash, prv_a.bytes.data (), prv_a.bytes.size ()); } +rai::public_key rai::pub_key (rai::private_key const & privatekey_a) +{ + rai::uint256_union result; + ed25519_publickey (privatekey_a.bytes.data (), result.bytes.data ()); + return result; +} + bool rai::validate_message (rai::public_key const & public_key, rai::uint256_union const & message, rai::uint512_union const & signature) { auto result (0 != ed25519_sign_open (message.bytes.data (), sizeof (message.bytes), public_key.bytes.data (), signature.bytes.data ())); diff --git a/rai/lib/numbers.hpp b/rai/lib/numbers.hpp index 8e7aa7bb..c97b9463 100644 --- a/rai/lib/numbers.hpp +++ b/rai/lib/numbers.hpp @@ -121,6 +121,7 @@ using signature = uint512_union; rai::uint512_union sign_message (rai::raw_key const &, rai::public_key const &, rai::uint256_union const &); bool validate_message (rai::public_key const &, rai::uint256_union const &, rai::uint512_union const &); void deterministic_key (rai::uint256_union const &, uint32_t, rai::uint256_union &); +rai::public_key pub_key (rai::private_key const &); } namespace std diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 2a793c08..9143947d 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -5,12 +5,12 @@ #include #include -#include - #ifdef RAIBLOCKS_SECURE_RPC #include #endif +#include + rai::rpc_secure_config::rpc_secure_config () : enable (false), verbose_logging (false) @@ -202,6 +202,119 @@ void rai::error_response (std::function rai::rpc_handler::wallet_impl () +{ + if (!ec) + { + std::string wallet_text (request.get ("wallet")); + rai::uint256_union wallet; + if (!wallet.decode_hex (wallet_text)) + { + auto existing (node.wallets.items.find (wallet)); + if (existing != node.wallets.items.end ()) + { + return existing->second; + } + else + { + ec = nano::error_common::wallet_not_found; + } + } + else + { + ec = nano::error_common::bad_wallet_number; + } + } + return nullptr; +} + +rai::account rai::rpc_handler::account_impl (std::string account_text) +{ + rai::account result (0); + if (!ec) + { + if (account_text.empty ()) + { + account_text = request.get ("account"); + } + if (result.decode_account (account_text)) + { + ec = nano::error_common::bad_account_number; + } + } + return result; +} + +rai::amount rai::rpc_handler::amount_impl () +{ + rai::amount result (0); + if (!ec) + { + std::string amount_text (request.get ("amount")); + if (result.decode_dec (amount_text)) + { + ec = nano::error_common::invalid_amount; + } + } + return result; +} + +rai::block_hash rai::rpc_handler::hash_impl (std::string search_text) +{ + rai::block_hash result (0); + if (!ec) + { + std::string hash_text (request.get (search_text)); + if (result.decode_hex (hash_text)) + { + ec = nano::error_blocks::invalid_block_hash; + } + } + return result; +} + +rai::amount rai::rpc_handler::threshold_optional_impl () +{ + rai::amount result (0); + boost::optional threshold_text (request.get_optional ("threshold")); + if (!ec && threshold_text.is_initialized ()) + { + if (result.decode_dec (threshold_text.get ())) + { + ec = nano::error_common::bad_threshold; + } + } + return result; +} + +uint64_t rai::rpc_handler::work_optional_impl () +{ + uint64_t result (0); + boost::optional work_text (request.get_optional ("work")); + if (!ec && work_text.is_initialized ()) + { + if (rai::from_string_hex (work_text.get (), result)) + { + ec = nano::error_common::bad_work_format; + } + } + return result; +} + namespace { bool decode_unsigned (std::string const & text, uint64_t & number) @@ -226,115 +339,120 @@ bool decode_unsigned (std::string const & text, uint64_t & number) } } +uint64_t rai::rpc_handler::count_impl () +{ + uint64_t result (0); + if (!ec) + { + std::string count_text (request.get ("count")); + if (decode_unsigned (count_text, result) || result == 0) + { + ec = nano::error_common::invalid_count; + } + } + return result; +} + +uint64_t rai::rpc_handler::count_optional_impl (uint64_t result) +{ + boost::optional count_text (request.get_optional ("count")); + if (!ec && count_text.is_initialized ()) + { + if (decode_unsigned (count_text.get (), result)) + { + ec = nano::error_common::invalid_count; + } + } + return result; +} + +bool rai::rpc_handler::rpc_control_impl () +{ + bool result (false); + if (!ec) + { + if (!rpc.config.enable_control) + { + ec = nano::error_rpc::rpc_control_disabled; + } + else + { + result = true; + } + } + return result; +} + void rai::rpc_handler::account_balance () { - std::string account_text (request.get ("account")); - rai::uint256_union account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl ()); + if (!ec) { auto balance (node.balance_pending (account)); - boost::property_tree::ptree response_l; response_l.put ("balance", balance.first.convert_to ()); response_l.put ("pending", balance.second.convert_to ()); - response (response_l); - } - else - { - error_response (response, "Bad account number"); } + response_errors (); } void rai::rpc_handler::account_block_count () { - std::string account_text (request.get ("account")); - rai::uint256_union account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl ()); + if (!ec) { rai::transaction transaction (node.store.environment, nullptr, false); rai::account_info info; if (!node.store.account_get (transaction, account, info)) { - boost::property_tree::ptree response_l; response_l.put ("block_count", std::to_string (info.block_count)); - response (response_l); } else { - error_response (response, "Account not found"); + ec = nano::error_common::account_not_found; } } - else - { - error_response (response, "Bad account number"); - } + response_errors (); } void rai::rpc_handler::account_create () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + const bool generate_work = request.get ("work", true); + rai::account new_key (wallet->deterministic_insert (generate_work)); + if (!new_key.is_zero ()) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - const bool generate_work = request.get ("work", true); - rai::account new_key (existing->second->deterministic_insert (generate_work)); - if (!new_key.is_zero ()) - { - boost::property_tree::ptree response_l; - response_l.put ("account", new_key.to_account ()); - response (response_l); - } - else - { - error_response (response, "Wallet is locked"); - } - } - else - { - error_response (response, "Wallet not found"); - } + response_l.put ("account", new_key.to_account ()); } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::wallet_locked; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::account_get () { std::string key_text (request.get ("key")); rai::uint256_union pub; - auto error (pub.decode_hex (key_text)); - if (!error) + if (!pub.decode_hex (key_text)) { - boost::property_tree::ptree response_l; response_l.put ("account", pub.to_account ()); - response (response_l); } else { - error_response (response, "Bad public key"); + ec = nano::error_common::bad_public_key; } + response_errors (); } void rai::rpc_handler::account_info () { - std::string account_text (request.get ("account")); - rai::uint256_union account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl ()); + if (!ec) { const bool representative = request.get ("representative", false); const bool weight = request.get ("weight", false); @@ -343,7 +461,6 @@ void rai::rpc_handler::account_info () rai::account_info info; if (!node.store.account_get (transaction, account, info)) { - boost::property_tree::ptree response_l; response_l.put ("frontier", info.head.to_string ()); response_l.put ("open_block", info.open_block.to_string ()); response_l.put ("representative_block", info.rep_block.to_string ()); @@ -369,343 +486,216 @@ void rai::rpc_handler::account_info () auto account_pending (node.ledger.account_pending (transaction, account)); response_l.put ("pending", account_pending.convert_to ()); } - response (response_l); } else { - error_response (response, "Account not found"); + ec = nano::error_common::account_not_found; } } - else - { - error_response (response, "Bad account number"); - } + response_errors (); } void rai::rpc_handler::account_key () { - std::string account_text (request.get ("account")); - rai::account account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl ()); + if (!ec) { - boost::property_tree::ptree response_l; response_l.put ("key", account.to_string ()); - response (response_l); - } - else - { - error_response (response, "Bad account number"); } + response_errors (); } void rai::rpc_handler::account_list () { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + boost::property_tree::ptree accounts; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (wallet->store.begin (transaction)), j (wallet->store.end ()); i != j; ++i) { - boost::property_tree::ptree response_l; - boost::property_tree::ptree accounts; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (existing->second->store.begin (transaction)), j (existing->second->store.end ()); i != j; ++i) - { - boost::property_tree::ptree entry; - entry.put ("", rai::uint256_union (i->first.uint256 ()).to_account ()); - accounts.push_back (std::make_pair ("", entry)); - } - response_l.add_child ("accounts", accounts); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); + boost::property_tree::ptree entry; + entry.put ("", rai::uint256_union (i->first.uint256 ()).to_account ()); + accounts.push_back (std::make_pair ("", entry)); } + response_l.add_child ("accounts", accounts); } - else - { - error_response (response, "Bad wallet number"); - } + response_errors (); } void rai::rpc_handler::account_move () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); std::string source_text (request.get ("source")); auto accounts_text (request.get_child ("accounts")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + rai::uint256_union source; + if (!source.decode_hex (source_text)) { - auto existing (node.wallets.items.find (wallet)); + auto existing (node.wallets.items.find (source)); if (existing != node.wallets.items.end ()) { - auto wallet (existing->second); - rai::uint256_union source; - auto error (source.decode_hex (source_text)); - if (!error) + auto source (existing->second); + std::vector accounts; + for (auto i (accounts_text.begin ()), n (accounts_text.end ()); i != n; ++i) { - auto existing (node.wallets.items.find (source)); - if (existing != node.wallets.items.end ()) - { - auto source (existing->second); - std::vector accounts; - for (auto i (accounts_text.begin ()), n (accounts_text.end ()); i != n; ++i) - { - rai::public_key account; - account.decode_hex (i->second.get ("")); - accounts.push_back (account); - } - rai::transaction transaction (node.store.environment, nullptr, true); - auto error (wallet->store.move (transaction, source->store, accounts)); - boost::property_tree::ptree response_l; - response_l.put ("moved", error ? "0" : "1"); - response (response_l); - } - else - { - error_response (response, "Source not found"); - } - } - else - { - error_response (response, "Bad source number"); + rai::public_key account; + account.decode_hex (i->second.get ("")); + accounts.push_back (account); } + rai::transaction transaction (node.store.environment, nullptr, true); + auto error (wallet->store.move (transaction, source->store, accounts)); + response_l.put ("moved", error ? "0" : "1"); } else { - error_response (response, "Wallet not found"); + ec = nano::error_rpc::source_not_found; } } else { - error_response (response, "Bad wallet number"); + ec = nano::error_rpc::bad_source; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::account_remove () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + auto account (account_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - std::string account_text (request.get ("account")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + rai::transaction transaction (node.store.environment, nullptr, true); + if (wallet->store.valid_password (transaction)) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + if (wallet->store.find (transaction, account) != wallet->store.end ()) { - auto wallet (existing->second); - rai::transaction transaction (node.store.environment, nullptr, true); - if (existing->second->store.valid_password (transaction)) - { - rai::account account_id; - auto error (account_id.decode_account (account_text)); - if (!error) - { - auto account (wallet->store.find (transaction, account_id)); - if (account != wallet->store.end ()) - { - wallet->store.erase (transaction, account_id); - boost::property_tree::ptree response_l; - response_l.put ("removed", "1"); - response (response_l); - } - else - { - error_response (response, "Account not found in wallet"); - } - } - else - { - error_response (response, "Bad account number"); - } - } - else - { - error_response (response, "Wallet locked"); - } + wallet->store.erase (transaction, account); + response_l.put ("removed", "1"); } else { - error_response (response, "Wallet not found"); + ec = nano::error_common::account_not_found_wallet; } } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::wallet_locked; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::account_representative () { - std::string account_text (request.get ("account")); - rai::account account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl ()); + if (!ec) { rai::transaction transaction (node.store.environment, nullptr, false); rai::account_info info; - auto error (node.store.account_get (transaction, account, info)); - if (!error) + if (!node.store.account_get (transaction, account, info)) { auto block (node.store.block_get (transaction, info.rep_block)); assert (block != nullptr); - boost::property_tree::ptree response_l; response_l.put ("representative", block->representative ().to_account ()); - response (response_l); } else { - error_response (response, "Account not found"); + ec = nano::error_common::account_not_found; } } - else - { - error_response (response, "Bad account number"); - } + response_errors (); } void rai::rpc_handler::account_representative_set () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + auto account (account_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + if (wallet->valid_password ()) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + std::string representative_text (request.get ("representative")); + rai::account representative; + if (!representative.decode_account (representative_text)) { - auto wallet (existing->second); - if (wallet->valid_password ()) + auto work (work_optional_impl ()); + if (!ec && work) { - std::string account_text (request.get ("account")); - rai::account account; - auto error (account.decode_account (account_text)); - if (!error) + rai::transaction transaction (node.store.environment, nullptr, true); + rai::account_info info; + if (!node.store.account_get (transaction, account, info)) { - std::string representative_text (request.get ("representative")); - rai::account representative; - auto error (representative.decode_account (representative_text)); - if (!error) + if (!rai::work_validate (info.head, work)) { - uint64_t work (0); - boost::optional work_text (request.get_optional ("work")); - if (work_text.is_initialized ()) - { - auto work_error (rai::from_string_hex (work_text.get (), work)); - if (work_error) - { - error_response (response, "Bad work"); - } - } - if (work) - { - rai::transaction transaction (node.store.environment, nullptr, true); - rai::account_info info; - if (!node.store.account_get (transaction, account, info)) - { - if (!rai::work_validate (info.head, work)) - { - existing->second->store.work_put (transaction, account, work); - } - else - { - error_response (response, "Invalid work"); - } - } - else - { - error_response (response, "Account not found"); - } - } - auto response_a (response); - wallet->change_async (account, representative, [response_a](std::shared_ptr block) { - rai::block_hash hash (0); - if (block != nullptr) - { - hash = block->hash (); - } - boost::property_tree::ptree response_l; - response_l.put ("block", hash.to_string ()); - response_a (response_l); - }, - work == 0); + wallet->store.work_put (transaction, account, work); + } + else + { + ec = nano::error_common::invalid_work; } } else { - error_response (response, "Bad account number"); + ec = nano::error_common::account_not_found; } } - else + if (!ec) { - error_response (response, "Wallet locked"); + auto response_a (response); + wallet->change_async (account, representative, [response_a](std::shared_ptr block) { + rai::block_hash hash (0); + if (block != nullptr) + { + hash = block->hash (); + } + boost::property_tree::ptree response_l; + response_l.put ("block", hash.to_string ()); + response_a (response_l); + }, + work == 0); } } else { - error_response (response, "Wallet not found"); + ec = nano::error_rpc::bad_representative_number; } } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::wallet_locked; } } - else + // Because of change_async + if (ec) { - error_response (response, "RPC control is disabled"); + response_errors (); } } void rai::rpc_handler::account_weight () { - std::string account_text (request.get ("account")); - rai::uint256_union account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl ()); + if (!ec) { auto balance (node.weight (account)); - boost::property_tree::ptree response_l; response_l.put ("weight", balance.convert_to ()); - response (response_l); - } - else - { - error_response (response, "Bad account number"); } + response_errors (); } void rai::rpc_handler::accounts_balances () { - boost::property_tree::ptree response_l; boost::property_tree::ptree balances; for (auto & accounts : request.get_child ("accounts")) { - std::string account_text = accounts.second.data (); - rai::uint256_union account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl (accounts.second.data ())); + if (!ec) { boost::property_tree::ptree entry; auto balance (node.balance_pending (account)); @@ -713,80 +703,43 @@ void rai::rpc_handler::accounts_balances () entry.put ("pending", balance.second.convert_to ()); balances.push_back (std::make_pair (account.to_account (), entry)); } - else - { - error_response (response, "Bad account number"); - } } response_l.add_child ("balances", balances); - response (response_l); + response_errors (); } void rai::rpc_handler::accounts_create () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + auto count (count_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + const bool generate_work = request.get ("work", false); + boost::property_tree::ptree accounts; + for (auto i (0); accounts.size () < count; ++i) { - uint64_t count; - std::string count_text (request.get ("count")); - auto count_error (decode_unsigned (count_text, count)); - if (!count_error && count != 0) + rai::account new_key (wallet->deterministic_insert (generate_work)); + if (!new_key.is_zero ()) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - const bool generate_work = request.get ("work", false); - boost::property_tree::ptree response_l; - boost::property_tree::ptree accounts; - for (auto i (0); accounts.size () < count; ++i) - { - rai::account new_key (existing->second->deterministic_insert (generate_work)); - if (!new_key.is_zero ()) - { - boost::property_tree::ptree entry; - entry.put ("", new_key.to_account ()); - accounts.push_back (std::make_pair ("", entry)); - } - } - response_l.add_child ("accounts", accounts); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Invalid count limit"); + boost::property_tree::ptree entry; + entry.put ("", new_key.to_account ()); + accounts.push_back (std::make_pair ("", entry)); } } - else - { - error_response (response, "Bad wallet number"); - } - } - else - { - error_response (response, "RPC control is disabled"); + response_l.add_child ("accounts", accounts); } + response_errors (); } void rai::rpc_handler::accounts_frontiers () { - boost::property_tree::ptree response_l; boost::property_tree::ptree frontiers; rai::transaction transaction (node.store.environment, nullptr, false); for (auto & accounts : request.get_child ("accounts")) { - std::string account_text = accounts.second.data (); - rai::uint256_union account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl (accounts.second.data ())); + if (!ec) { auto latest (node.ledger.latest (transaction, account)); if (!latest.is_zero ()) @@ -794,46 +747,22 @@ void rai::rpc_handler::accounts_frontiers () frontiers.put (account.to_account (), latest.to_string ()); } } - else - { - error_response (response, "Bad account number"); - } } response_l.add_child ("frontiers", frontiers); - response (response_l); + response_errors (); } void rai::rpc_handler::accounts_pending () { - uint64_t count (std::numeric_limits::max ()); - rai::uint128_union threshold (0); - boost::optional count_text (request.get_optional ("count")); - if (count_text.is_initialized ()) - { - auto error (decode_unsigned (count_text.get (), count)); - if (error) - { - error_response (response, "Invalid count limit"); - } - } - boost::optional threshold_text (request.get_optional ("threshold")); - if (threshold_text.is_initialized ()) - { - auto error_threshold (threshold.decode_dec (threshold_text.get ())); - if (error_threshold) - { - error_response (response, "Bad threshold number"); - } - } + auto count (count_optional_impl ()); + auto threshold (threshold_optional_impl ()); const bool source = request.get ("source", false); - boost::property_tree::ptree response_l; boost::property_tree::ptree pending; rai::transaction transaction (node.store.environment, nullptr, false); for (auto & accounts : request.get_child ("accounts")) { - std::string account_text = accounts.second.data (); - rai::uint256_union account; - if (!account.decode_account (account_text)) + auto account (account_impl (accounts.second.data ())); + if (!ec) { boost::property_tree::ptree peers_l; rai::account end (account.number () + 1); @@ -867,13 +796,9 @@ void rai::rpc_handler::accounts_pending () } pending.add_child (account.to_account (), peers_l); } - else - { - error_response (response, "Bad account number"); - } } response_l.add_child ("blocks", pending); - response (response_l); + response_errors (); } void rai::rpc_handler::available_supply () @@ -883,97 +808,84 @@ void rai::rpc_handler::available_supply () auto faucet_balance (node.balance (rai::account ("8E319CE6F3025E5B2DF66DA7AB1467FE48F1679C13DD43BFDB29FA2E9FC40D3B"))); // Faucet account auto burned_balance ((node.balance_pending (rai::account (0))).second); // Burning 0 account auto available (rai::genesis_amount - genesis_balance - landing_balance - faucet_balance - burned_balance); - boost::property_tree::ptree response_l; response_l.put ("available", available.convert_to ()); - response (response_l); + response_errors (); } void rai::rpc_handler::block () { - std::string hash_text (request.get ("hash")); - rai::uint256_union hash; - auto error (hash.decode_hex (hash_text)); - if (!error) + auto hash (hash_impl ()); + if (!ec) { rai::transaction transaction (node.store.environment, nullptr, false); auto block (node.store.block_get (transaction, hash)); if (block != nullptr) { - boost::property_tree::ptree response_l; std::string contents; block->serialize_json (contents); response_l.put ("contents", contents); - response (response_l); } else { - error_response (response, "Block not found"); + ec = nano::error_blocks::not_found; } } - else - { - error_response (response, "Bad hash number"); - } + response_errors (); } void rai::rpc_handler::block_confirm () { - std::string hash_text (request.get ("hash")); - rai::block_hash hash_l; - if (!hash_l.decode_hex (hash_text)) + auto hash (hash_impl ()); + if (!ec) { rai::transaction transaction (node.store.environment, nullptr, false); - auto block_l (node.store.block_get (transaction, hash_l)); + auto block_l (node.store.block_get (transaction, hash)); if (block_l != nullptr) { node.block_confirm (std::move (block_l)); - boost::property_tree::ptree response_l; response_l.put ("started", "1"); - response (response_l); } else { - error_response (response, "Block not found"); + ec = nano::error_blocks::not_found; } } - else - { - error_response (response, "Invalid block hash"); - } + response_errors (); } void rai::rpc_handler::blocks () { std::vector hashes; - boost::property_tree::ptree response_l; boost::property_tree::ptree blocks; rai::transaction transaction (node.store.environment, nullptr, false); for (boost::property_tree::ptree::value_type & hashes : request.get_child ("hashes")) { - std::string hash_text = hashes.second.data (); - rai::uint256_union hash; - auto error (hash.decode_hex (hash_text)); - if (!error) + if (!ec) { - auto block (node.store.block_get (transaction, hash)); - if (block != nullptr) + std::string hash_text = hashes.second.data (); + rai::uint256_union hash; + if (!hash.decode_hex (hash_text)) { - std::string contents; - block->serialize_json (contents); - blocks.put (hash_text, contents); + auto block (node.store.block_get (transaction, hash)); + if (block != nullptr) + { + std::string contents; + block->serialize_json (contents); + blocks.put (hash_text, contents); + } + else + { + ec = nano::error_blocks::not_found; + } } else { - error_response (response, "Block not found"); + ec = nano::error_blocks::bad_hash_number; } } - else - { - error_response (response, "Bad hash number"); - } } response_l.add_child ("blocks", blocks); - response (response_l); + response_errors (); } void rai::rpc_handler::blocks_info () @@ -982,111 +894,104 @@ void rai::rpc_handler::blocks_info () const bool source = request.get ("source", false); const bool balance = request.get ("balance", false); std::vector hashes; - boost::property_tree::ptree response_l; boost::property_tree::ptree blocks; rai::transaction transaction (node.store.environment, nullptr, false); for (boost::property_tree::ptree::value_type & hashes : request.get_child ("hashes")) { - std::string hash_text = hashes.second.data (); - rai::uint256_union hash; - auto error (hash.decode_hex (hash_text)); - if (!error) + if (!ec) { - auto block (node.store.block_get (transaction, hash)); - if (block != nullptr) + std::string hash_text = hashes.second.data (); + rai::uint256_union hash; + if (!hash.decode_hex (hash_text)) { - boost::property_tree::ptree entry; - auto account (node.ledger.account (transaction, hash)); - entry.put ("block_account", account.to_account ()); - auto amount (node.ledger.amount (transaction, hash)); - entry.put ("amount", amount.convert_to ()); - std::string contents; - block->serialize_json (contents); - entry.put ("contents", contents); - if (pending) + auto block (node.store.block_get (transaction, hash)); + if (block != nullptr) { - bool exists (false); - auto destination (node.ledger.block_destination (transaction, *block)); - if (!destination.is_zero ()) + boost::property_tree::ptree entry; + auto account (node.ledger.account (transaction, hash)); + entry.put ("block_account", account.to_account ()); + auto amount (node.ledger.amount (transaction, hash)); + entry.put ("amount", amount.convert_to ()); + std::string contents; + block->serialize_json (contents); + entry.put ("contents", contents); + if (pending) { - exists = node.store.pending_exists (transaction, rai::pending_key (destination, hash)); + bool exists (false); + auto destination (node.ledger.block_destination (transaction, *block)); + if (!destination.is_zero ()) + { + exists = node.store.pending_exists (transaction, rai::pending_key (destination, hash)); + } + entry.put ("pending", exists ? "1" : "0"); } - entry.put ("pending", exists ? "1" : "0"); + if (source) + { + rai::block_hash source_hash (node.ledger.block_source (transaction, *block)); + std::unique_ptr block_a (node.store.block_get (transaction, source_hash)); + if (block_a != nullptr) + { + auto source_account (node.ledger.account (transaction, source_hash)); + entry.put ("source_account", source_account.to_account ()); + } + else + { + entry.put ("source_account", "0"); + } + } + if (balance) + { + auto balance (node.ledger.balance (transaction, hash)); + entry.put ("balance", balance.convert_to ()); + } + blocks.push_back (std::make_pair (hash_text, entry)); } - if (source) + else { - rai::block_hash source_hash (node.ledger.block_source (transaction, *block)); - std::unique_ptr block_a (node.store.block_get (transaction, source_hash)); - if (block_a != nullptr) - { - auto source_account (node.ledger.account (transaction, source_hash)); - entry.put ("source_account", source_account.to_account ()); - } - else - { - entry.put ("source_account", "0"); - } + ec = nano::error_blocks::not_found; } - if (balance) - { - auto balance (node.ledger.balance (transaction, hash)); - entry.put ("balance", balance.convert_to ()); - } - blocks.push_back (std::make_pair (hash_text, entry)); } else { - error_response (response, "Block not found"); + ec = nano::error_blocks::bad_hash_number; } } - else - { - error_response (response, "Bad hash number"); - } } response_l.add_child ("blocks", blocks); - response (response_l); + response_errors (); } void rai::rpc_handler::block_account () { - std::string hash_text (request.get ("hash")); - rai::block_hash hash; - if (!hash.decode_hex (hash_text)) + auto hash (hash_impl ()); + if (!ec) { rai::transaction transaction (node.store.environment, nullptr, false); if (node.store.block_exists (transaction, hash)) { - boost::property_tree::ptree response_l; auto account (node.ledger.account (transaction, hash)); response_l.put ("account", account.to_account ()); - response (response_l); } else { - error_response (response, "Block not found"); + ec = nano::error_blocks::not_found; } } - else - { - error_response (response, "Invalid block hash"); - } + response_errors (); } void rai::rpc_handler::block_count () { rai::transaction transaction (node.store.environment, nullptr, false); - boost::property_tree::ptree response_l; response_l.put ("count", std::to_string (node.store.block_count (transaction).sum ())); response_l.put ("unchecked", std::to_string (node.store.unchecked_count (transaction))); - response (response_l); + response_errors (); } void rai::rpc_handler::block_count_type () { rai::transaction transaction (node.store.environment, nullptr, false); rai::block_counts count (node.store.block_count (transaction)); - boost::property_tree::ptree response_l; response_l.put ("send", std::to_string (count.send)); response_l.put ("receive", std::to_string (count.receive)); response_l.put ("open", std::to_string (count.open)); @@ -1094,99 +999,83 @@ void rai::rpc_handler::block_count_type () response_l.put ("state_v0", std::to_string (count.state_v0)); response_l.put ("state_v1", std::to_string (count.state_v1)); response_l.put ("state", std::to_string (count.state_v0 + count.state_v1)); - response (response_l); + response_errors (); } void rai::rpc_handler::block_create () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { std::string type (request.get ("type")); rai::uint256_union wallet (0); boost::optional wallet_text (request.get_optional ("wallet")); if (wallet_text.is_initialized ()) { - auto error (wallet.decode_hex (wallet_text.get ())); - if (error) + if (wallet.decode_hex (wallet_text.get ())) { - error_response (response, "Bad wallet number"); + ec = nano::error_common::bad_wallet_number; } } rai::uint256_union account (0); boost::optional account_text (request.get_optional ("account")); - if (account_text.is_initialized ()) + if (!ec && account_text.is_initialized ()) { - auto error_account (account.decode_account (account_text.get ())); - if (error_account) + if (account.decode_account (account_text.get ())) { - error_response (response, "Bad account number"); + ec = nano::error_common::bad_account_number; } } rai::uint256_union representative (0); boost::optional representative_text (request.get_optional ("representative")); - if (representative_text.is_initialized ()) + if (!ec && representative_text.is_initialized ()) { - auto error_representative (representative.decode_account (representative_text.get ())); - if (error_representative) + if (representative.decode_account (representative_text.get ())) { - error_response (response, "Bad representative account"); + ec = nano::error_rpc::bad_representative_number; } } rai::uint256_union destination (0); boost::optional destination_text (request.get_optional ("destination")); - if (destination_text.is_initialized ()) + if (!ec && destination_text.is_initialized ()) { - auto error_destination (destination.decode_account (destination_text.get ())); - if (error_destination) + if (destination.decode_account (destination_text.get ())) { - error_response (response, "Bad destination account"); + ec = nano::error_rpc::bad_destination; } } rai::block_hash source (0); boost::optional source_text (request.get_optional ("source")); - if (source_text.is_initialized ()) + if (!ec && source_text.is_initialized ()) { - auto error_source (source.decode_hex (source_text.get ())); - if (error_source) + if (source.decode_hex (source_text.get ())) { - error_response (response, "Invalid source hash"); + ec = nano::error_rpc::bad_source; } } rai::uint128_union amount (0); boost::optional amount_text (request.get_optional ("amount")); - if (amount_text.is_initialized ()) + if (!ec && amount_text.is_initialized ()) { - auto error_amount (amount.decode_dec (amount_text.get ())); - if (error_amount) + if (amount.decode_dec (amount_text.get ())) { - error_response (response, "Bad amount number"); - } - } - uint64_t work (0); - boost::optional work_text (request.get_optional ("work")); - if (work_text.is_initialized ()) - { - auto work_error (rai::from_string_hex (work_text.get (), work)); - if (work_error) - { - error_response (response, "Bad work"); + ec = nano::error_common::invalid_amount; } } + auto work (work_optional_impl ()); rai::raw_key prv; prv.data.clear (); rai::uint256_union previous (0); rai::uint128_union balance (0); - if (wallet != 0 && account != 0) + if (!ec && wallet != 0 && account != 0) { auto existing (node.wallets.items.find (wallet)); if (existing != node.wallets.items.end ()) { rai::transaction transaction (node.store.environment, nullptr, false); - auto unlock_check (existing->second->store.valid_password (transaction)); - if (unlock_check) + if (existing->second->store.valid_password (transaction)) { - auto account_check (existing->second->store.find (transaction, account)); - if (account_check != existing->second->store.end ()) + if (existing->second->store.find (transaction, account) != existing->second->store.end ()) { existing->second->store.fetch (transaction, account, prv); previous = node.ledger.latest (transaction, account); @@ -1194,57 +1083,52 @@ void rai::rpc_handler::block_create () } else { - error_response (response, "Account not found in wallet"); + ec = nano::error_common::account_not_found_wallet; } } else { - error_response (response, "Wallet is locked"); + ec = nano::error_common::wallet_locked; } } else { - error_response (response, "Wallet not found"); + ec = nano::error_common::wallet_not_found; } } boost::optional key_text (request.get_optional ("key")); - if (key_text.is_initialized ()) + if (!ec && key_text.is_initialized ()) { - auto error_key (prv.data.decode_hex (key_text.get ())); - if (error_key) + if (prv.data.decode_hex (key_text.get ())) { - error_response (response, "Bad private key"); + ec = nano::error_common::bad_private_key; } } boost::optional previous_text (request.get_optional ("previous")); - if (previous_text.is_initialized ()) + if (!ec && previous_text.is_initialized ()) { - auto error_previous (previous.decode_hex (previous_text.get ())); - if (error_previous) + if (previous.decode_hex (previous_text.get ())) { - error_response (response, "Invalid previous hash"); + ec = nano::error_rpc::bad_previous; } } boost::optional balance_text (request.get_optional ("balance")); - if (balance_text.is_initialized ()) + if (!ec && balance_text.is_initialized ()) { - auto error_balance (balance.decode_dec (balance_text.get ())); - if (error_balance) + if (balance.decode_dec (balance_text.get ())) { - error_response (response, "Bad balance number"); + ec = nano::error_rpc::invalid_balance; } } rai::uint256_union link (0); boost::optional link_text (request.get_optional ("link")); - if (link_text.is_initialized ()) + if (!ec && link_text.is_initialized ()) { - auto error_link (link.decode_account (link_text.get ())); - if (error_link) + if (link.decode_account (link_text.get ())) { - auto error_link (link.decode_hex (link_text.get ())); - if (error_link) + if (link.decode_hex (link_text.get ())) { - error_response (response, "Bad link number"); + ec = nano::error_rpc::bad_link; } } } @@ -1255,8 +1139,7 @@ void rai::rpc_handler::block_create () } if (prv.data != 0) { - rai::uint256_union pub; - ed25519_publickey (prv.data.bytes.data (), pub.bytes.data ()); + rai::uint256_union pub (rai::pub_key (prv.data)); // Fetching account balance & previous for send blocks (if aren't given directly) if (!previous_text.is_initialized () && !balance_text.is_initialized ()) { @@ -1270,15 +1153,15 @@ void rai::rpc_handler::block_create () rai::transaction transaction (node.store.environment, nullptr, false); if (node.store.block_exists (transaction, previous) && node.store.block_balance (transaction, previous) != balance.number ()) { - error_response (response, "Balance mismatch for previous block"); + ec = nano::error_rpc::block_create_balance_mismatch; } } // Check for incorrect account key - if (account_text.is_initialized ()) + if (!ec && account_text.is_initialized ()) { if (account != pub) { - error_response (response, "Incorrect key for given account"); + ec = nano::error_rpc::block_create_public_key_mismatch; } } if (type == "state") @@ -1290,16 +1173,14 @@ void rai::rpc_handler::block_create () work = node.work_generate_blocking (previous.is_zero () ? pub : previous); } rai::state_block state (pub, previous, representative, balance, link, prv, pub, work); - boost::property_tree::ptree response_l; response_l.put ("hash", state.hash ().to_string ()); std::string contents; state.serialize_json (contents); response_l.put ("block", contents); - response (response_l); } else { - error_response (response, "Previous, representative, final balance and link (source or destination) are required"); + ec = nano::error_rpc::block_create_requirements_state; } } else if (type == "open") @@ -1311,16 +1192,14 @@ void rai::rpc_handler::block_create () work = node.work_generate_blocking (pub); } rai::open_block open (source, representative, pub, prv, pub, work); - boost::property_tree::ptree response_l; response_l.put ("hash", open.hash ().to_string ()); std::string contents; open.serialize_json (contents); response_l.put ("block", contents); - response (response_l); } else { - error_response (response, "Representative account and source hash required"); + ec = nano::error_rpc::block_create_requirements_open; } } else if (type == "receive") @@ -1332,16 +1211,14 @@ void rai::rpc_handler::block_create () work = node.work_generate_blocking (previous); } rai::receive_block receive (previous, source, prv, pub, work); - boost::property_tree::ptree response_l; response_l.put ("hash", receive.hash ().to_string ()); std::string contents; receive.serialize_json (contents); response_l.put ("block", contents); - response (response_l); } else { - error_response (response, "Previous hash and source hash required"); + ec = nano::error_rpc::block_create_requirements_receive; } } else if (type == "change") @@ -1353,16 +1230,14 @@ void rai::rpc_handler::block_create () work = node.work_generate_blocking (previous); } rai::change_block change (previous, representative, prv, pub, work); - boost::property_tree::ptree response_l; response_l.put ("hash", change.hash ().to_string ()); std::string contents; change.serialize_json (contents); response_l.put ("block", contents); - response (response_l); } else { - error_response (response, "Representative account and previous hash required"); + ec = nano::error_rpc::block_create_requirements_change; } } else if (type == "send") @@ -1376,37 +1251,32 @@ void rai::rpc_handler::block_create () work = node.work_generate_blocking (previous); } rai::send_block send (previous, destination, balance.number () - amount.number (), prv, pub, work); - boost::property_tree::ptree response_l; response_l.put ("hash", send.hash ().to_string ()); std::string contents; send.serialize_json (contents); response_l.put ("block", contents); - response (response_l); } else { - error_response (response, "Insufficient balance"); + ec = nano::error_common::insufficient_balance; } } else { - error_response (response, "Destination account, previous hash, current balance and amount required"); + ec = nano::error_rpc::block_create_requirements_send; } } else { - error_response (response, "Invalid block type"); + ec = nano::error_blocks::invalid_type; } } else { - error_response (response, "Private key or local wallet and account required"); + ec = nano::error_rpc::block_create_key_required; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::block_hash () @@ -1420,138 +1290,78 @@ void rai::rpc_handler::block_hash () auto block (rai::deserialize_block_json (block_l)); if (block != nullptr) { - boost::property_tree::ptree response_l; response_l.put ("hash", block->hash ().to_string ()); - response (response_l); } else { - error_response (response, "Block is invalid"); - } -} - -void rai::rpc_handler::successors () -{ - std::string block_text (request.get ("block")); - std::string count_text (request.get ("count")); - rai::block_hash block; - if (!block.decode_hex (block_text)) - { - uint64_t count; - if (!decode_unsigned (count_text, count)) - { - boost::property_tree::ptree response_l; - boost::property_tree::ptree blocks; - rai::transaction transaction (node.store.environment, nullptr, false); - while (!block.is_zero () && blocks.size () < count) - { - auto block_l (node.store.block_get (transaction, block)); - if (block_l != nullptr) - { - boost::property_tree::ptree entry; - entry.put ("", block.to_string ()); - blocks.push_back (std::make_pair ("", entry)); - block = node.store.block_successor (transaction, block); - } - else - { - block.clear (); - } - } - response_l.add_child ("blocks", blocks); - response (response_l); - } - else - { - error_response (response, "Invalid count limit"); - } - } - else - { - error_response (response, "Invalid block hash"); + ec = nano::error_blocks::invalid_block; } + response_errors (); } void rai::rpc_handler::bootstrap () { std::string address_text = request.get ("address"); std::string port_text = request.get ("port"); - boost::system::error_code ec; - auto address (boost::asio::ip::address_v6::from_string (address_text, ec)); - if (!ec) + boost::system::error_code address_ec; + auto address (boost::asio::ip::address_v6::from_string (address_text, address_ec)); + if (!address_ec) { uint16_t port; if (!rai::parse_port (port_text, port)) { node.bootstrap_initiator.bootstrap (rai::endpoint (address, port)); - boost::property_tree::ptree response_l; response_l.put ("success", ""); - response (response_l); } else { - error_response (response, "Invalid port"); + ec = nano::error_common::invalid_port; } } else { - error_response (response, "Invalid address"); + ec = nano::error_common::invalid_ip_address; } + response_errors (); } void rai::rpc_handler::bootstrap_any () { node.bootstrap_initiator.bootstrap (); - boost::property_tree::ptree response_l; response_l.put ("success", ""); - response (response_l); + response_errors (); } -void rai::rpc_handler::chain () +void rai::rpc_handler::chain (bool successors) { - std::string block_text (request.get ("block")); - std::string count_text (request.get ("count")); - rai::block_hash block; - if (!block.decode_hex (block_text)) + auto hash (hash_impl ("block")); + auto count (count_impl ()); + if (!ec) { - uint64_t count; - if (!decode_unsigned (count_text, count)) + boost::property_tree::ptree blocks; + rai::transaction transaction (node.store.environment, nullptr, false); + while (!hash.is_zero () && blocks.size () < count) { - boost::property_tree::ptree response_l; - boost::property_tree::ptree blocks; - rai::transaction transaction (node.store.environment, nullptr, false); - while (!block.is_zero () && blocks.size () < count) + auto block_l (node.store.block_get (transaction, hash)); + if (block_l != nullptr) { - auto block_l (node.store.block_get (transaction, block)); - if (block_l != nullptr) - { - boost::property_tree::ptree entry; - entry.put ("", block.to_string ()); - blocks.push_back (std::make_pair ("", entry)); - block = block_l->previous (); - } - else - { - block.clear (); - } + boost::property_tree::ptree entry; + entry.put ("", hash.to_string ()); + blocks.push_back (std::make_pair ("", entry)); + hash = successors ? node.store.block_successor (transaction, hash) : block_l->previous (); + } + else + { + hash.clear (); } - response_l.add_child ("blocks", blocks); - response (response_l); - } - else - { - error_response (response, "Invalid count limit"); } + response_l.add_child ("blocks", blocks); } - else - { - error_response (response, "Invalid block hash"); - } + response_errors (); } void rai::rpc_handler::confirmation_history () { - boost::property_tree::ptree response_l; boost::property_tree::ptree elections; { std::lock_guard lock (node.active.mutex); @@ -1564,17 +1374,14 @@ void rai::rpc_handler::confirmation_history () } } response_l.add_child ("confirmations", elections); - response (response_l); + response_errors (); } void rai::rpc_handler::delegators () { - std::string account_text (request.get ("account")); - rai::account account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl ()); + if (!ec) { - boost::property_tree::ptree response_l; boost::property_tree::ptree delegators; rai::transaction transaction (node.store.environment, nullptr, false); for (auto i (node.store.latest_begin (transaction)), n (node.store.latest_end ()); i != n; ++i) @@ -1590,20 +1397,14 @@ void rai::rpc_handler::delegators () } } response_l.add_child ("delegators", delegators); - response (response_l); - } - else - { - error_response (response, "Bad account number"); } + response_errors (); } void rai::rpc_handler::delegators_count () { - std::string account_text (request.get ("account")); - rai::account account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl ()); + if (!ec) { uint64_t count (0); rai::transaction transaction (node.store.environment, nullptr, false); @@ -1617,14 +1418,9 @@ void rai::rpc_handler::delegators_count () ++count; } } - boost::property_tree::ptree response_l; response_l.put ("count", std::to_string (count)); - response (response_l); - } - else - { - error_response (response, "Bad account number"); } + response_errors (); } void rai::rpc_handler::deterministic_key () @@ -1632,76 +1428,53 @@ void rai::rpc_handler::deterministic_key () std::string seed_text (request.get ("seed")); std::string index_text (request.get ("index")); rai::raw_key seed; - auto error (seed.data.decode_hex (seed_text)); - if (!error) + if (!seed.data.decode_hex (seed_text)) { - uint64_t index_a; - if (!decode_unsigned (index_text, index_a)) + try { - rai::uint256_union index (index_a); + uint32_t index (std::stoul (index_text)); rai::uint256_union prv; - blake2b_state hash; - blake2b_init (&hash, prv.bytes.size ()); - blake2b_update (&hash, seed.data.bytes.data (), seed.data.bytes.size ()); - blake2b_update (&hash, reinterpret_cast (&index.dwords[7]), sizeof (uint32_t)); - blake2b_final (&hash, prv.bytes.data (), prv.bytes.size ()); - boost::property_tree::ptree response_l; - rai::uint256_union pub; - ed25519_publickey (prv.bytes.data (), pub.bytes.data ()); + rai::deterministic_key (seed.data, index, prv); + rai::uint256_union pub (rai::pub_key (prv)); response_l.put ("private", prv.to_string ()); response_l.put ("public", pub.to_string ()); response_l.put ("account", pub.to_account ()); - response (response_l); } - else + catch (std::logic_error const &) { - error_response (response, "Invalid index"); + ec = nano::error_common::invalid_index; } } else { - error_response (response, "Bad seed"); + ec = nano::error_common::bad_seed; } + response_errors (); } void rai::rpc_handler::frontiers () { - std::string account_text (request.get ("account")); - std::string count_text (request.get ("count")); - rai::account start; - if (!start.decode_account (account_text)) + auto start (account_impl ()); + auto count (count_impl ()); + if (!ec) { - uint64_t count; - if (!decode_unsigned (count_text, count)) + boost::property_tree::ptree frontiers; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n && frontiers.size () < count; ++i) { - boost::property_tree::ptree response_l; - boost::property_tree::ptree frontiers; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n && frontiers.size () < count; ++i) - { - frontiers.put (rai::account (i->first.uint256 ()).to_account (), rai::account_info (i->second, i->from_secondary_store ? rai::epoch::epoch_1 : rai::epoch::epoch_0).head.to_string ()); - } - response_l.add_child ("frontiers", frontiers); - response (response_l); - } - else - { - error_response (response, "Invalid count limit"); + frontiers.put (rai::account (i->first.uint256 ()).to_account (), rai::account_info (i->second, i->from_secondary_store ? rai::epoch::epoch_1 : rai::epoch::epoch_0).head.to_string ()); } + response_l.add_child ("frontiers", frontiers); } - else - { - error_response (response, "Invalid starting account"); - } + response_errors (); } void rai::rpc_handler::account_count () { rai::transaction transaction (node.store.environment, nullptr, false); auto size (node.store.account_count (transaction)); - boost::property_tree::ptree response_l; response_l.put ("count", std::to_string (size)); - response (response_l); + response_errors (); } namespace @@ -1846,107 +1619,84 @@ public: void rai::rpc_handler::account_history () { - std::string account_text; - std::string count_text (request.get ("count")); + rai::account account; bool output_raw (request.get_optional ("raw") == true); - auto error (false); rai::block_hash hash; auto head_str (request.get_optional ("head")); rai::transaction transaction (node.store.environment, nullptr, false); if (head_str) { - error = hash.decode_hex (*head_str); - if (!error) + if (!hash.decode_hex (*head_str)) { - account_text = node.ledger.account (transaction, hash).to_account (); + account = node.ledger.account (transaction, hash); } else { - error_response (response, "Invalid block hash"); + ec = nano::error_blocks::bad_hash_number; } } else { - account_text = request.get ("account"); - rai::uint256_union account; - error = account.decode_account (account_text); - if (!error) + account = account_impl (); + if (!ec) { hash = node.ledger.latest (transaction, account); } - else - { - error_response (response, "Bad account number"); - } } - if (!error) + auto count (count_impl ()); + if (!ec) { - uint64_t count; - if (!decode_unsigned (count_text, count)) + uint64_t offset = 0; + auto offset_text (request.get_optional ("offset")); + if (!offset_text || !decode_unsigned (*offset_text, offset)) { - uint64_t offset = 0; - auto offset_text (request.get_optional ("offset")); - if (!offset_text || !decode_unsigned (*offset_text, offset)) + boost::property_tree::ptree history; + response_l.put ("account", account.to_account ()); + auto block (node.store.block_get (transaction, hash)); + while (block != nullptr && count > 0) { - boost::property_tree::ptree response_l; - boost::property_tree::ptree history; - if (!error) + if (offset > 0) { - response_l.put ("account", account_text); - auto block (node.store.block_get (transaction, hash)); - while (block != nullptr && count > 0) - { - if (offset > 0) - { - --offset; - } - else - { - boost::property_tree::ptree entry; - history_visitor visitor (*this, output_raw, transaction, entry, hash); - block->visit (visitor); - if (!entry.empty ()) - { - entry.put ("hash", hash.to_string ()); - if (output_raw) - { - entry.put ("work", rai::to_string_hex (block->block_work ())); - entry.put ("signature", block->block_signature ().to_string ()); - } - history.push_back (std::make_pair ("", entry)); - } - --count; - } - hash = block->previous (); - block = node.store.block_get (transaction, hash); - } - response_l.add_child ("history", history); - if (!hash.is_zero ()) - { - response_l.put ("previous", hash.to_string ()); - } - response (response_l); + --offset; } else { - error_response (response, "Failed to decode head block hash"); + boost::property_tree::ptree entry; + history_visitor visitor (*this, output_raw, transaction, entry, hash); + block->visit (visitor); + if (!entry.empty ()) + { + entry.put ("hash", hash.to_string ()); + if (output_raw) + { + entry.put ("work", rai::to_string_hex (block->block_work ())); + entry.put ("signature", block->block_signature ().to_string ()); + } + history.push_back (std::make_pair ("", entry)); + } + --count; } + hash = block->previous (); + block = node.store.block_get (transaction, hash); } - else + response_l.add_child ("history", history); + if (!hash.is_zero ()) { - error_response (response, "Invalid offset"); + response_l.put ("previous", hash.to_string ()); } } else { - error_response (response, "Invalid count limit"); + ec = nano::error_rpc::invalid_offset; } } + response_errors (); } void rai::rpc_handler::keepalive () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { std::string address_text (request.get ("address")); std::string port_text (request.get ("port")); @@ -1954,73 +1704,56 @@ void rai::rpc_handler::keepalive () if (!rai::parse_port (port_text, port)) { node.keepalive (address_text, port); - boost::property_tree::ptree response_l; - response (response_l); + response_l.put ("started", "1"); } else { - error_response (response, "Invalid port"); + ec = nano::error_common::invalid_port; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::key_create () { - boost::property_tree::ptree response_l; rai::keypair pair; response_l.put ("private", pair.prv.data.to_string ()); response_l.put ("public", pair.pub.to_string ()); response_l.put ("account", pair.pub.to_account ()); - response (response_l); + response_errors (); } void rai::rpc_handler::key_expand () { std::string key_text (request.get ("key")); rai::uint256_union prv; - auto error (prv.decode_hex (key_text)); - if (!error) + if (!prv.decode_hex (key_text)) { - boost::property_tree::ptree response_l; - rai::uint256_union pub; - ed25519_publickey (prv.bytes.data (), pub.bytes.data ()); + rai::uint256_union pub (rai::pub_key (prv)); response_l.put ("private", prv.to_string ()); response_l.put ("public", pub.to_string ()); response_l.put ("account", pub.to_account ()); - response (response_l); } else { - error_response (response, "Bad private key"); + ec = nano::error_common::bad_private_key; } + response_errors (); } void rai::rpc_handler::ledger () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto count (count_optional_impl ()); + if (!ec) { rai::account start (0); - uint64_t count (std::numeric_limits::max ()); boost::optional account_text (request.get_optional ("account")); if (account_text.is_initialized ()) { - auto error (start.decode_account (account_text.get ())); - if (error) + if (start.decode_account (account_text.get ())) { - error_response (response, "Invalid starting account"); - } - } - boost::optional count_text (request.get_optional ("count")); - if (count_text.is_initialized ()) - { - auto error_count (decode_unsigned (count_text.get (), count)); - if (error_count) - { - error_response (response, "Invalid count limit"); + ec = nano::error_common::bad_account_number; } } uint64_t modified_since (0); @@ -2033,11 +1766,9 @@ void rai::rpc_handler::ledger () const bool representative = request.get ("representative", false); const bool weight = request.get ("weight", false); const bool pending = request.get ("pending", false); - boost::property_tree::ptree response_a; - boost::property_tree::ptree response_l; boost::property_tree::ptree accounts; rai::transaction transaction (node.store.environment, nullptr, false); - if (!sorting) // Simple + if (!ec && !sorting) // Simple { for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n && accounts.size () < count; ++i) { @@ -2045,36 +1776,36 @@ void rai::rpc_handler::ledger () if (info.modified >= modified_since) { rai::account account (i->first.uint256 ()); - boost::property_tree::ptree response_l; - response_l.put ("frontier", info.head.to_string ()); - response_l.put ("open_block", info.open_block.to_string ()); - response_l.put ("representative_block", info.rep_block.to_string ()); + boost::property_tree::ptree response_a; + response_a.put ("frontier", info.head.to_string ()); + response_a.put ("open_block", info.open_block.to_string ()); + response_a.put ("representative_block", info.rep_block.to_string ()); std::string balance; rai::uint128_union (info.balance).encode_dec (balance); - response_l.put ("balance", balance); - response_l.put ("modified_timestamp", std::to_string (info.modified)); - response_l.put ("block_count", std::to_string (info.block_count)); + response_a.put ("balance", balance); + response_a.put ("modified_timestamp", std::to_string (info.modified)); + response_a.put ("block_count", std::to_string (info.block_count)); if (representative) { auto block (node.store.block_get (transaction, info.rep_block)); assert (block != nullptr); - response_l.put ("representative", block->representative ().to_account ()); + response_a.put ("representative", block->representative ().to_account ()); } if (weight) { auto account_weight (node.ledger.weight (transaction, account)); - response_l.put ("weight", account_weight.convert_to ()); + response_a.put ("weight", account_weight.convert_to ()); } if (pending) { auto account_pending (node.ledger.account_pending (transaction, account)); - response_l.put ("pending", account_pending.convert_to ()); + response_a.put ("pending", account_pending.convert_to ()); } - accounts.push_back (std::make_pair (account.to_account (), response_l)); + accounts.push_back (std::make_pair (account.to_account (), response_a)); } } } - else // Sorting + else if (!ec) // Sorting { std::vector> ledger_l; for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n; ++i) @@ -2093,223 +1824,115 @@ void rai::rpc_handler::ledger () { node.store.account_get (transaction, i->second, info); rai::account account (i->second); - response_l.put ("frontier", info.head.to_string ()); - response_l.put ("open_block", info.open_block.to_string ()); - response_l.put ("representative_block", info.rep_block.to_string ()); + boost::property_tree::ptree response_a; + response_a.put ("frontier", info.head.to_string ()); + response_a.put ("open_block", info.open_block.to_string ()); + response_a.put ("representative_block", info.rep_block.to_string ()); std::string balance; (i->first).encode_dec (balance); - response_l.put ("balance", balance); - response_l.put ("modified_timestamp", std::to_string (info.modified)); - response_l.put ("block_count", std::to_string (info.block_count)); + response_a.put ("balance", balance); + response_a.put ("modified_timestamp", std::to_string (info.modified)); + response_a.put ("block_count", std::to_string (info.block_count)); if (representative) { auto block (node.store.block_get (transaction, info.rep_block)); assert (block != nullptr); - response_l.put ("representative", block->representative ().to_account ()); + response_a.put ("representative", block->representative ().to_account ()); } if (weight) { auto account_weight (node.ledger.weight (transaction, account)); - response_l.put ("weight", account_weight.convert_to ()); + response_a.put ("weight", account_weight.convert_to ()); } if (pending) { auto account_pending (node.ledger.account_pending (transaction, account)); - response_l.put ("pending", account_pending.convert_to ()); + response_a.put ("pending", account_pending.convert_to ()); } - accounts.push_back (std::make_pair (account.to_account (), response_l)); + accounts.push_back (std::make_pair (account.to_account (), response_a)); } } - response_a.add_child ("accounts", accounts); - response (response_a); - } - else - { - error_response (response, "RPC control is disabled"); + response_l.add_child ("accounts", accounts); } + response_errors (); } -void rai::rpc_handler::mrai_from_raw () +void rai::rpc_handler::mrai_from_raw (rai::uint128_t ratio) { - std::string amount_text (request.get ("amount")); - rai::uint128_union amount; - if (!amount.decode_dec (amount_text)) + auto amount (amount_impl ()); + if (!ec) { - auto result (amount.number () / rai::Mxrb_ratio); - boost::property_tree::ptree response_l; + auto result (amount.number () / ratio); response_l.put ("amount", result.convert_to ()); - response (response_l); - } - else - { - error_response (response, "Bad amount number"); } + response_errors (); } -void rai::rpc_handler::mrai_to_raw () +void rai::rpc_handler::mrai_to_raw (rai::uint128_t ratio) { - std::string amount_text (request.get ("amount")); - rai::uint128_union amount; - if (!amount.decode_dec (amount_text)) + auto amount (amount_impl ()); + if (!ec) { - auto result (amount.number () * rai::Mxrb_ratio); + auto result (amount.number () * ratio); if (result > amount.number ()) { - boost::property_tree::ptree response_l; response_l.put ("amount", result.convert_to ()); - response (response_l); } else { - error_response (response, "Amount too big"); + ec = nano::error_common::invalid_amount_big; } } - else - { - error_response (response, "Bad amount number"); - } -} - -void rai::rpc_handler::krai_from_raw () -{ - std::string amount_text (request.get ("amount")); - rai::uint128_union amount; - if (!amount.decode_dec (amount_text)) - { - auto result (amount.number () / rai::kxrb_ratio); - boost::property_tree::ptree response_l; - response_l.put ("amount", result.convert_to ()); - response (response_l); - } - else - { - error_response (response, "Bad amount number"); - } -} - -void rai::rpc_handler::krai_to_raw () -{ - std::string amount_text (request.get ("amount")); - rai::uint128_union amount; - if (!amount.decode_dec (amount_text)) - { - auto result (amount.number () * rai::kxrb_ratio); - if (result > amount.number ()) - { - boost::property_tree::ptree response_l; - response_l.put ("amount", result.convert_to ()); - response (response_l); - } - else - { - error_response (response, "Amount too big"); - } - } - else - { - error_response (response, "Bad amount number"); - } + response_errors (); } void rai::rpc_handler::password_change () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) - { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - rai::transaction transaction (node.store.environment, nullptr, true); - boost::property_tree::ptree response_l; - std::string password_text (request.get ("password")); - auto error (existing->second->store.rekey (transaction, password_text)); - response_l.put ("changed", error ? "0" : "1"); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Bad wallet number"); - } - } - else - { - error_response (response, "RPC control is disabled"); + rai::transaction transaction (node.store.environment, nullptr, true); + std::string password_text (request.get ("password")); + auto error (wallet->store.rekey (transaction, password_text)); + response_l.put ("changed", error ? "0" : "1"); } + response_errors (); } void rai::rpc_handler::password_enter () { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - boost::property_tree::ptree response_l; - std::string password_text (request.get ("password")); - auto error (existing->second->enter_password (password_text)); - response_l.put ("valid", error ? "0" : "1"); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Bad wallet number"); + std::string password_text (request.get ("password")); + auto error (wallet->enter_password (password_text)); + response_l.put ("valid", error ? "0" : "1"); } + response_errors (); } -void rai::rpc_handler::password_valid (bool wallet_locked = false) +void rai::rpc_handler::password_valid (bool wallet_locked) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + rai::transaction transaction (node.store.environment, nullptr, false); + auto valid (wallet->store.valid_password (transaction)); + if (!wallet_locked) { - rai::transaction transaction (node.store.environment, nullptr, false); - boost::property_tree::ptree response_l; - auto valid (existing->second->store.valid_password (transaction)); - if (!wallet_locked) - { - response_l.put ("valid", valid ? "1" : "0"); - } - else - { - response_l.put ("locked", valid ? "0" : "1"); - } - response (response_l); + response_l.put ("valid", valid ? "1" : "0"); } else { - error_response (response, "Wallet not found"); + response_l.put ("locked", valid ? "0" : "1"); } } - else - { - error_response (response, "Bad wallet number"); - } + response_errors (); } void rai::rpc_handler::peers () { - boost::property_tree::ptree response_l; boost::property_tree::ptree peers_l; auto peers_list (node.peers.list_version ()); for (auto i (peers_list.begin ()), n (peers_list.end ()); i != n; ++i) @@ -2319,93 +1942,65 @@ void rai::rpc_handler::peers () peers_l.push_back (boost::property_tree::ptree::value_type (text.str (), boost::property_tree::ptree (std::to_string (i->second)))); } response_l.add_child ("peers", peers_l); - response (response_l); + response_errors (); } void rai::rpc_handler::pending () { - std::string account_text (request.get ("account")); - rai::account account; - if (!account.decode_account (account_text)) + auto account (account_impl ()); + auto count (count_optional_impl ()); + auto threshold (threshold_optional_impl ()); + const bool source = request.get ("source", false); + const bool min_version = request.get ("min_version", false); + if (!ec) { - uint64_t count (std::numeric_limits::max ()); - rai::uint128_union threshold (0); - boost::optional count_text (request.get_optional ("count")); - if (count_text.is_initialized ()) - { - auto error (decode_unsigned (count_text.get (), count)); - if (error) - { - error_response (response, "Invalid count limit"); - } - } - boost::optional threshold_text (request.get_optional ("threshold")); - if (threshold_text.is_initialized ()) - { - auto error_threshold (threshold.decode_dec (threshold_text.get ())); - if (error_threshold) - { - error_response (response, "Bad threshold number"); - } - } - const bool source = request.get ("source", false); - const bool min_version = request.get ("min_version", false); - boost::property_tree::ptree response_l; boost::property_tree::ptree peers_l; + rai::transaction transaction (node.store.environment, nullptr, false); + rai::account end (account.number () + 1); + for (auto i (node.store.pending_begin (transaction, rai::pending_key (account, 0))), n (node.store.pending_begin (transaction, rai::pending_key (end, 0))); i != n && peers_l.size () < count; ++i) { - rai::transaction transaction (node.store.environment, nullptr, false); - rai::account end (account.number () + 1); - for (auto i (node.store.pending_begin (transaction, rai::pending_key (account, 0))), n (node.store.pending_begin (transaction, rai::pending_key (end, 0))); i != n && peers_l.size () < count; ++i) + rai::pending_key key (i->first); + if (threshold.is_zero () && !source && !min_version) { - rai::pending_key key (i->first); - if (threshold.is_zero () && !source && !min_version) + boost::property_tree::ptree entry; + entry.put ("", key.hash.to_string ()); + peers_l.push_back (std::make_pair ("", entry)); + } + else + { + rai::pending_info info (i->second, i->from_secondary_store ? rai::epoch::epoch_1 : rai::epoch::epoch_0); + if (info.amount.number () >= threshold.number ()) { - boost::property_tree::ptree entry; - entry.put ("", key.hash.to_string ()); - peers_l.push_back (std::make_pair ("", entry)); - } - else - { - rai::pending_info info (i->second, i->from_secondary_store ? rai::epoch::epoch_1 : rai::epoch::epoch_0); - if (info.amount.number () >= threshold.number ()) + if (source || min_version) { - if (source || min_version) + boost::property_tree::ptree pending_tree; + pending_tree.put ("amount", info.amount.number ().convert_to ()); + if (source) { - boost::property_tree::ptree pending_tree; - pending_tree.put ("amount", info.amount.number ().convert_to ()); - if (source) - { - pending_tree.put ("source", info.source.to_account ()); - } - if (min_version) - { - pending_tree.put ("min_version", info.epoch == rai::epoch::epoch_1 ? "1" : "0"); - } - peers_l.add_child (key.hash.to_string (), pending_tree); + pending_tree.put ("source", info.source.to_account ()); } - else + if (min_version) { - peers_l.put (key.hash.to_string (), info.amount.number ().convert_to ()); + pending_tree.put ("min_version", info.epoch == rai::epoch::epoch_1 ? "1" : "0"); } + peers_l.add_child (key.hash.to_string (), pending_tree); + } + else + { + peers_l.put (key.hash.to_string (), info.amount.number ().convert_to ()); } } } } response_l.add_child ("blocks", peers_l); - response (response_l); - } - else - { - error_response (response, "Bad account number"); } + response_errors (); } void rai::rpc_handler::pending_exists () { - std::string hash_text (request.get ("hash")); - rai::uint256_union hash; - auto error (hash.decode_hex (hash_text)); - if (!error) + auto hash (hash_impl ()); + if (!ec) { rai::transaction transaction (node.store.environment, nullptr, false); auto block (node.store.block_get (transaction, hash)); @@ -2417,19 +2012,14 @@ void rai::rpc_handler::pending_exists () { exists = node.store.pending_exists (transaction, rai::pending_key (destination, hash)); } - boost::property_tree::ptree response_l; response_l.put ("exists", exists ? "1" : "0"); - response (response_l); } else { - error_response (response, "Block not found"); + ec = nano::error_blocks::not_found; } } - else - { - error_response (response, "Bad hash number"); - } + response_errors (); } void rai::rpc_handler::payment_begin () @@ -2475,155 +2065,104 @@ void rai::rpc_handler::payment_begin () } while (account.is_zero ()); if (!account.is_zero ()) { - boost::property_tree::ptree response_l; response_l.put ("account", account.to_account ()); - response (response_l); } else { - error_response (response, "Unable to create transaction account"); + ec = nano::error_rpc::payment_unable_create_account; } } else { - error_response (response, "Wallet locked"); + ec = nano::error_common::wallet_locked; } } else { - error_response (response, "Unable to find wallets"); + ec = nano::error_common::wallet_not_found; } } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::bad_wallet_number; } + response_errors (); } void rai::rpc_handler::payment_init () { - std::string id_text (request.get ("wallet")); - rai::uint256_union id; - if (!id.decode_hex (id_text)) + auto wallet (wallet_impl ()); + if (!ec) { rai::transaction transaction (node.store.environment, nullptr, true); - auto existing (node.wallets.items.find (id)); - if (existing != node.wallets.items.end ()) + if (wallet->store.valid_password (transaction)) { - auto wallet (existing->second); - if (wallet->store.valid_password (transaction)) - { - wallet->init_free_accounts (transaction); - boost::property_tree::ptree response_l; - response_l.put ("status", "Ready"); - response (response_l); - } - else - { - boost::property_tree::ptree response_l; - response_l.put ("status", "Transaction wallet locked"); - response (response_l); - } + wallet->init_free_accounts (transaction); + response_l.put ("status", "Ready"); } else { - boost::property_tree::ptree response_l; - response_l.put ("status", "Unable to find transaction wallet"); - response (response_l); + ec = nano::error_common::wallet_locked; } } - else - { - error_response (response, "Bad transaction wallet number"); - } + response_errors (); } void rai::rpc_handler::payment_end () { - std::string id_text (request.get ("wallet")); - std::string account_text (request.get ("account")); - rai::uint256_union id; - if (!id.decode_hex (id_text)) + auto account (account_impl ()); + auto wallet (wallet_impl ()); + if (!ec) { rai::transaction transaction (node.store.environment, nullptr, false); - auto existing (node.wallets.items.find (id)); - if (existing != node.wallets.items.end ()) + auto existing (wallet->store.find (transaction, account)); + if (existing != wallet->store.end ()) { - auto wallet (existing->second); - rai::account account; - if (!account.decode_account (account_text)) + if (node.ledger.account_balance (transaction, account).is_zero ()) { - auto existing (wallet->store.find (transaction, account)); - if (existing != wallet->store.end ()) - { - if (node.ledger.account_balance (transaction, account).is_zero ()) - { - wallet->free_accounts.insert (account); - boost::property_tree::ptree response_l; - response (response_l); - } - else - { - error_response (response, "Account has non-zero balance"); - } - } - else - { - error_response (response, "Account not in wallet"); - } + wallet->free_accounts.insert (account); + response_l.put ("ended", "1"); } else { - error_response (response, "Invalid account number"); + ec = nano::error_rpc::payment_account_balance; } } else { - error_response (response, "Unable to find wallet"); + ec = nano::error_common::account_not_found_wallet; } } - else - { - error_response (response, "Bad wallet number"); - } + response_errors (); } void rai::rpc_handler::payment_wait () { - std::string account_text (request.get ("account")); - std::string amount_text (request.get ("amount")); std::string timeout_text (request.get ("timeout")); - rai::uint256_union account; - if (!account.decode_account (account_text)) + auto account (account_impl ()); + auto amount (amount_impl ()); + if (!ec) { - rai::uint128_union amount; - if (!amount.decode_dec (amount_text)) + uint64_t timeout; + if (!decode_unsigned (timeout_text, timeout)) { - uint64_t timeout; - if (!decode_unsigned (timeout_text, timeout)) { - { - auto observer (std::make_shared (response, rpc, account, amount)); - observer->start (timeout); - std::lock_guard lock (rpc.mutex); - assert (rpc.payment_observers.find (account) == rpc.payment_observers.end ()); - rpc.payment_observers[account] = observer; - } - rpc.observer_action (account); - } - else - { - error_response (response, "Bad timeout number"); + auto observer (std::make_shared (response, rpc, account, amount)); + observer->start (timeout); + std::lock_guard lock (rpc.mutex); + assert (rpc.payment_observers.find (account) == rpc.payment_observers.end ()); + rpc.payment_observers[account] = observer; } + rpc.observer_action (account); } else { - error_response (response, "Bad amount number"); + ec = nano::error_rpc::bad_timeout; } } - else + if (ec) { - error_response (response, "Bad account number"); + response_errors (); } } @@ -2649,40 +2188,48 @@ void rai::rpc_handler::process () { case rai::process_result::progress: { - boost::property_tree::ptree response_l; response_l.put ("hash", hash.to_string ()); - response (response_l); break; } case rai::process_result::gap_previous: { - error_response (response, "Gap previous block"); + ec = nano::error_process::gap_previous; break; } case rai::process_result::gap_source: { - error_response (response, "Gap source block"); + ec = nano::error_process::gap_source; break; } case rai::process_result::old: { - error_response (response, "Old block"); + ec = nano::error_process::old; break; } case rai::process_result::bad_signature: { - error_response (response, "Bad signature"); + ec = nano::error_process::bad_signature; break; } case rai::process_result::negative_spend: { // TODO once we get RPC versioning, this should be changed to "negative spend" - error_response (response, "Overspend"); + ec = nano::error_process::negative_spend; + break; + } + case rai::process_result::balance_mismatch: + { + ec = nano::error_process::balance_mismatch; break; } case rai::process_result::unreceivable: { - error_response (response, "Unreceivable"); + ec = nano::error_process::unreceivable; + break; + } + case rai::process_result::block_position: + { + ec = nano::error_process::block_position; break; } case rai::process_result::fork: @@ -2692,290 +2239,179 @@ void rai::rpc_handler::process () { node.active.erase (*block); node.block_processor.force (block); - boost::property_tree::ptree response_l; response_l.put ("hash", hash.to_string ()); - response (response_l); } else { - error_response (response, "Fork"); + ec = nano::error_process::fork; } break; } default: { - error_response (response, "Error processing block"); + ec = nano::error_process::other; break; } } } else { - error_response (response, "Block work is invalid"); + ec = nano::error_blocks::work_low; } } else { - error_response (response, "Block is invalid"); - } -} - -void rai::rpc_handler::rai_from_raw () -{ - std::string amount_text (request.get ("amount")); - rai::uint128_union amount; - if (!amount.decode_dec (amount_text)) - { - auto result (amount.number () / rai::xrb_ratio); - boost::property_tree::ptree response_l; - response_l.put ("amount", result.convert_to ()); - response (response_l); - } - else - { - error_response (response, "Bad amount number"); - } -} - -void rai::rpc_handler::rai_to_raw () -{ - std::string amount_text (request.get ("amount")); - rai::uint128_union amount; - if (!amount.decode_dec (amount_text)) - { - auto result (amount.number () * rai::xrb_ratio); - if (result > amount.number ()) - { - boost::property_tree::ptree response_l; - response_l.put ("amount", result.convert_to ()); - response (response_l); - } - else - { - error_response (response, "Amount too big"); - } - } - else - { - error_response (response, "Bad amount number"); + ec = nano::error_blocks::invalid_block; } + response_errors (); } void rai::rpc_handler::receive () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + auto account (account_impl ()); + auto hash (hash_impl ("block")); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + rai::transaction transaction (node.store.environment, nullptr, false); + if (wallet->store.valid_password (transaction)) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + if (wallet->store.find (transaction, account) != wallet->store.end ()) { - if (existing->second->valid_password ()) + auto block (node.store.block_get (transaction, hash)); + if (block != nullptr) { - std::string account_text (request.get ("account")); - rai::account account; - auto error (account.decode_account (account_text)); - if (!error) + if (node.store.pending_exists (transaction, rai::pending_key (account, hash))) { - rai::transaction transaction (node.store.environment, nullptr, false); - auto account_check (existing->second->store.find (transaction, account)); - if (account_check != existing->second->store.end ()) + auto work (work_optional_impl ()); + if (!ec && work) { - std::string hash_text (request.get ("block")); - rai::uint256_union hash; - auto error (hash.decode_hex (hash_text)); - if (!error) + rai::account_info info; + rai::uint256_union head; + if (!node.store.account_get (transaction, account, info)) { - auto block (node.store.block_get (transaction, hash)); - if (block != nullptr) - { - if (node.store.pending_exists (transaction, rai::pending_key (account, hash))) - { - uint64_t work (0); - boost::optional work_text (request.get_optional ("work")); - auto error (false); - if (work_text.is_initialized ()) - { - error = rai::from_string_hex (work_text.get (), work); - if (error) - { - error_response (response, "Bad work"); - } - } - if (work) - { - rai::account_info info; - rai::uint256_union head; - if (!node.store.account_get (transaction, account, info)) - { - head = info.head; - } - else - { - head = account; - } - if (!rai::work_validate (head, work)) - { - rai::transaction transaction_a (node.store.environment, nullptr, true); - existing->second->store.work_put (transaction_a, account, work); - } - else - { - error = true; - error_response (response, "Invalid work"); - } - } - if (!error) - { - auto response_a (response); - existing->second->receive_async (std::move (block), account, rai::genesis_amount, [response_a](std::shared_ptr block_a) { - rai::uint256_union hash_a (0); - if (block_a != nullptr) - { - hash_a = block_a->hash (); - } - boost::property_tree::ptree response_l; - response_l.put ("block", hash_a.to_string ()); - response_a (response_l); - }, - work == 0); - } - } - else - { - error_response (response, "Block is not available to receive"); - } - } - else - { - error_response (response, "Block not found"); - } + head = info.head; } else { - error_response (response, "Bad block number"); + head = account; + } + if (!rai::work_validate (head, work)) + { + rai::transaction transaction_a (node.store.environment, nullptr, true); + wallet->store.work_put (transaction_a, account, work); + } + else + { + ec = nano::error_common::invalid_work; } } - else + if (!ec) { - error_response (response, "Account not found in wallet"); + auto response_a (response); + wallet->receive_async (std::move (block), account, rai::genesis_amount, [response_a](std::shared_ptr block_a) { + rai::uint256_union hash_a (0); + if (block_a != nullptr) + { + hash_a = block_a->hash (); + } + boost::property_tree::ptree response_l; + response_l.put ("block", hash_a.to_string ()); + response_a (response_l); + }, + work == 0); } } else { - error_response (response, "Bad account number"); + ec = nano::error_process::unreceivable; } } else { - error_response (response, "Wallet locked"); + ec = nano::error_blocks::not_found; } } else { - error_response (response, "Wallet not found"); + ec = nano::error_common::account_not_found_wallet; } } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::wallet_locked; } } - else + // Because of receive_async + if (ec) { - error_response (response, "RPC control is disabled"); + response_errors (); } } void rai::rpc_handler::receive_minimum () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { - boost::property_tree::ptree response_l; response_l.put ("amount", node.config.receive_minimum.to_string_dec ()); - response (response_l); - } - else - { - error_response (response, "RPC control is disabled"); } + response_errors (); } void rai::rpc_handler::receive_minimum_set () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto amount (amount_impl ()); + if (!ec) { - std::string amount_text (request.get ("amount")); - rai::uint128_union amount; - if (!amount.decode_dec (amount_text)) - { - node.config.receive_minimum = amount; - boost::property_tree::ptree response_l; - response_l.put ("success", ""); - response (response_l); - } - else - { - error_response (response, "Bad amount number"); - } - } - else - { - error_response (response, "RPC control is disabled"); + node.config.receive_minimum = amount; + response_l.put ("success", ""); } + response_errors (); } void rai::rpc_handler::representatives () { - uint64_t count (std::numeric_limits::max ()); - boost::optional count_text (request.get_optional ("count")); - if (count_text.is_initialized ()) + auto count (count_optional_impl ()); + if (!ec) { - auto error (decode_unsigned (count_text.get (), count)); - if (error) + const bool sorting = request.get ("sorting", false); + boost::property_tree::ptree representatives; + rai::transaction transaction (node.store.environment, nullptr, false); + if (!sorting) // Simple { - error_response (response, "Invalid count limit"); + for (auto i (node.store.representation_begin (transaction)), n (node.store.representation_end ()); i != n && representatives.size () < count; ++i) + { + rai::account account (i->first.uint256 ()); + auto amount (node.store.representation_get (transaction, account)); + representatives.put (account.to_account (), amount.convert_to ()); + } } + else // Sorting + { + std::vector> representation; + for (auto i (node.store.representation_begin (transaction)), n (node.store.representation_end ()); i != n; ++i) + { + rai::account account (i->first.uint256 ()); + auto amount (node.store.representation_get (transaction, account)); + representation.push_back (std::make_pair (amount, account.to_account ())); + } + std::sort (representation.begin (), representation.end ()); + std::reverse (representation.begin (), representation.end ()); + for (auto i (representation.begin ()), n (representation.end ()); i != n && representatives.size () < count; ++i) + { + representatives.put (i->second, (i->first).number ().convert_to ()); + } + } + response_l.add_child ("representatives", representatives); } - const bool sorting = request.get ("sorting", false); - boost::property_tree::ptree response_l; - boost::property_tree::ptree representatives; - rai::transaction transaction (node.store.environment, nullptr, false); - if (!sorting) // Simple - { - for (auto i (node.store.representation_begin (transaction)), n (node.store.representation_end ()); i != n && representatives.size () < count; ++i) - { - rai::account account (i->first.uint256 ()); - auto amount (node.store.representation_get (transaction, account)); - representatives.put (account.to_account (), amount.convert_to ()); - } - } - else // Sorting - { - std::vector> representation; - for (auto i (node.store.representation_begin (transaction)), n (node.store.representation_end ()); i != n; ++i) - { - rai::account account (i->first.uint256 ()); - auto amount (node.store.representation_get (transaction, account)); - representation.push_back (std::make_pair (amount, account.to_account ())); - } - std::sort (representation.begin (), representation.end ()); - std::reverse (representation.begin (), representation.end ()); - for (auto i (representation.begin ()), n (representation.end ()); i != n && representatives.size () < count; ++i) - { - representatives.put (i->second, (i->first).number ().convert_to ()); - } - } - response_l.add_child ("representatives", representatives); - response (response_l); + response_errors (); } void rai::rpc_handler::representatives_online () { - boost::property_tree::ptree response_l; boost::property_tree::ptree representatives; auto reps (node.online_reps.list ()); for (auto & i : reps) @@ -2983,47 +2419,33 @@ void rai::rpc_handler::representatives_online () representatives.put (i.to_account (), ""); } response_l.add_child ("representatives", representatives); - response (response_l); + response_errors (); } void rai::rpc_handler::republish () { - uint64_t count (1024U); + auto count (count_optional_impl (1024U)); uint64_t sources (0); uint64_t destinations (0); - boost::optional count_text (request.get_optional ("count")); - if (count_text.is_initialized ()) - { - auto error (decode_unsigned (count_text.get (), count)); - if (error) - { - error_response (response, "Invalid count limit"); - } - } boost::optional sources_text (request.get_optional ("sources")); - if (sources_text.is_initialized ()) + if (!ec && sources_text.is_initialized ()) { - auto sources_error (decode_unsigned (sources_text.get (), sources)); - if (sources_error) + if (decode_unsigned (sources_text.get (), sources)) { - error_response (response, "Invalid sources number"); + ec = nano::error_rpc::invalid_sources; } } boost::optional destinations_text (request.get_optional ("destinations")); - if (destinations_text.is_initialized ()) + if (!ec && destinations_text.is_initialized ()) { - auto destinations_error (decode_unsigned (destinations_text.get (), destinations)); - if (destinations_error) + if (decode_unsigned (destinations_text.get (), destinations)) { - error_response (response, "Invalid destinations number"); + ec = nano::error_rpc::invalid_destinations; } } - std::string hash_text (request.get ("hash")); - rai::uint256_union hash; - auto error (hash.decode_hex (hash_text)); - if (!error) + auto hash (hash_impl ()); + if (!ec) { - boost::property_tree::ptree response_l; boost::property_tree::ptree blocks; rai::transaction transaction (node.store.environment, nullptr, false); auto block (node.store.block_get (transaction, hash)); @@ -3063,8 +2485,7 @@ void rai::rpc_handler::republish () auto destination (node.ledger.block_destination (transaction, *block_b)); if (!destination.is_zero ()) { - auto exists (node.store.pending_exists (transaction, rai::pending_key (destination, hash))); - if (!exists) + if (!node.store.pending_exists (transaction, rai::pending_key (destination, hash))) { rai::block_hash previous (node.ledger.latest (transaction, destination)); std::unique_ptr block_d (node.store.block_get (transaction, previous)); @@ -3097,196 +2518,133 @@ void rai::rpc_handler::republish () } response_l.put ("success", ""); // obsolete response_l.add_child ("blocks", blocks); - response (response_l); } else { - error_response (response, "Block not found"); + ec = nano::error_blocks::not_found; } } - else - { - error_response (response, "Bad hash number"); - } + response_errors (); } void rai::rpc_handler::search_pending () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) - { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - auto error (existing->second->search_pending ()); - boost::property_tree::ptree response_l; - response_l.put ("started", !error); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - } - else - { - error_response (response, "RPC control is disabled"); + auto error (wallet->search_pending ()); + response_l.put ("started", !error); } + response_errors (); } void rai::rpc_handler::search_pending_all () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { node.wallets.search_pending_all (); - boost::property_tree::ptree response_l; response_l.put ("success", ""); - response (response_l); - } - else - { - error_response (response, "RPC control is disabled"); } + response_errors (); } void rai::rpc_handler::send () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + auto amount (amount_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + if (wallet->valid_password ()) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + std::string source_text (request.get ("source")); + rai::account source; + if (!source.decode_account (source_text)) { - if (existing->second->valid_password ()) + std::string destination_text (request.get ("destination")); + rai::account destination; + if (!destination.decode_account (destination_text)) { - std::string source_text (request.get ("source")); - rai::account source; - auto error (source.decode_account (source_text)); - if (!error) + auto work (work_optional_impl ()); + rai::uint128_t balance (0); + if (!ec) { - std::string destination_text (request.get ("destination")); - rai::account destination; - auto error (destination.decode_account (destination_text)); - if (!error) + rai::transaction transaction (node.store.environment, nullptr, work != 0); // false if no "work" in request, true if work > 0 + rai::account_info info; + if (!node.store.account_get (transaction, source, info)) { - std::string amount_text (request.get ("amount")); - rai::amount amount; - auto error (amount.decode_dec (amount_text)); - if (!error) - { - uint64_t work (0); - boost::optional work_text (request.get_optional ("work")); - if (work_text.is_initialized ()) - { - error = rai::from_string_hex (work_text.get (), work); - if (error) - { - error_response (response, "Bad work"); - } - } - rai::uint128_t balance (0); - if (!error) - { - rai::transaction transaction (node.store.environment, nullptr, work != 0); // false if no "work" in request, true if work > 0 - rai::account_info info; - if (!node.store.account_get (transaction, source, info)) - { - balance = (info.balance).number (); - } - else - { - error = true; - error_response (response, "Account not found"); - } - if (!error && work) - { - if (!rai::work_validate (info.head, work)) - { - existing->second->store.work_put (transaction, source, work); - } - else - { - error = true; - error_response (response, "Invalid work"); - } - } - } - if (!error) - { - boost::optional send_id (request.get_optional ("id")); - if (balance >= amount.number ()) - { - auto rpc_l (shared_from_this ()); - auto response_a (response); - existing->second->send_async (source, destination, amount.number (), [response_a](std::shared_ptr block_a) { - if (block_a != nullptr) - { - rai::uint256_union hash (block_a->hash ()); - boost::property_tree::ptree response_l; - response_l.put ("block", hash.to_string ()); - response_a (response_l); - } - else - { - error_response (response_a, "Error generating block"); - } - }, - work == 0, send_id); - } - else - { - error_response (response, "Insufficient balance"); - } - } - } - else - { - error_response (response, "Bad amount format"); - } + balance = (info.balance).number (); } else { - error_response (response, "Bad destination account"); + ec = nano::error_common::account_not_found; + } + if (!ec && work) + { + if (!rai::work_validate (info.head, work)) + { + wallet->store.work_put (transaction, source, work); + } + else + { + ec = nano::error_common::invalid_work; + } } } - else + if (!ec) { - error_response (response, "Bad source account"); + boost::optional send_id (request.get_optional ("id")); + if (balance >= amount.number ()) + { + auto rpc_l (shared_from_this ()); + auto response_a (response); + wallet->send_async (source, destination, amount.number (), [response_a](std::shared_ptr block_a) { + if (block_a != nullptr) + { + rai::uint256_union hash (block_a->hash ()); + boost::property_tree::ptree response_l; + response_l.put ("block", hash.to_string ()); + response_a (response_l); + } + else + { + error_response (response_a, "Error generating block"); + } + }, + work == 0, send_id); + } + else + { + ec = nano::error_common::insufficient_balance; + } } } else { - error_response (response, "Wallet locked"); + ec = nano::error_rpc::bad_destination; } } else { - error_response (response, "Wallet not found"); + ec = nano::error_rpc::bad_source; } } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::wallet_locked; } } - else + // Because of send_async + if (ec) { - error_response (response, "RPC control is disabled"); + response_errors (); } } void rai::rpc_handler::stats () { - bool error = false; auto sink = node.stats.log_sink_json (); std::string type (request.get ("type", "")); if (type == "counters") @@ -3299,83 +2657,70 @@ void rai::rpc_handler::stats () } else { - error = true; - error_response (response, "Invalid or missing type argument"); + ec = nano::error_rpc::invalid_missing_type; } - - if (!error) + if (!ec) { response (*static_cast (sink->to_object ())); } + else + { + response_errors (); + } } void rai::rpc_handler::stop () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { - boost::property_tree::ptree response_l; response_l.put ("success", ""); - response (response_l); + } + response_errors (); + if (!ec) + { rpc.stop (); node.stop (); } - else - { - error_response (response, "RPC control is disabled"); - } } void rai::rpc_handler::unchecked () { - uint64_t count (std::numeric_limits::max ()); - boost::optional count_text (request.get_optional ("count")); - if (count_text.is_initialized ()) + auto count (count_optional_impl ()); + if (!ec) { - auto error (decode_unsigned (count_text.get (), count)); - if (error) + boost::property_tree::ptree unchecked; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (node.store.unchecked_begin (transaction)), n (node.store.unchecked_end ()); i != n && unchecked.size () < count; ++i) { - error_response (response, "Invalid count limit"); + rai::bufferstream stream (reinterpret_cast (i->second.data ()), i->second.size ()); + auto block (rai::deserialize_block (stream)); + std::string contents; + block->serialize_json (contents); + unchecked.put (block->hash ().to_string (), contents); } + response_l.add_child ("blocks", unchecked); } - boost::property_tree::ptree response_l; - boost::property_tree::ptree unchecked; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (node.store.unchecked_begin (transaction)), n (node.store.unchecked_end ()); i != n && unchecked.size () < count; ++i) - { - rai::bufferstream stream (reinterpret_cast (i->second.data ()), i->second.size ()); - auto block (rai::deserialize_block (stream)); - std::string contents; - block->serialize_json (contents); - unchecked.put (block->hash ().to_string (), contents); - } - response_l.add_child ("blocks", unchecked); - response (response_l); + response_errors (); } void rai::rpc_handler::unchecked_clear () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { rai::transaction transaction (node.store.environment, nullptr, true); node.store.unchecked_clear (transaction); - boost::property_tree::ptree response_l; response_l.put ("success", ""); - response (response_l); - } - else - { - error_response (response, "RPC control is disabled"); } + response_errors (); } void rai::rpc_handler::unchecked_get () { - std::string hash_text (request.get ("hash")); - rai::uint256_union hash; - auto error (hash.decode_hex (hash_text)); - if (!error) + auto hash (hash_impl ()); + if (!ec) { - boost::property_tree::ptree response_l; rai::transaction transaction (node.store.environment, nullptr, false); for (auto i (node.store.unchecked_begin (transaction)), n (node.store.unchecked_end ()); i != n; ++i) { @@ -3389,69 +2734,53 @@ void rai::rpc_handler::unchecked_get () break; } } - if (!response_l.empty ()) + if (response_l.empty ()) { - response (response_l); - } - else - { - error_response (response, "Unchecked block not found"); + ec = nano::error_blocks::not_found; } } - else - { - error_response (response, "Bad hash number"); - } + response_errors (); } void rai::rpc_handler::unchecked_keys () { - uint64_t count (std::numeric_limits::max ()); + auto count (count_optional_impl ()); rai::uint256_union key (0); - boost::optional count_text (request.get_optional ("count")); - if (count_text.is_initialized ()) - { - auto error (decode_unsigned (count_text.get (), count)); - if (error) - { - error_response (response, "Invalid count limit"); - } - } boost::optional hash_text (request.get_optional ("key")); - if (hash_text.is_initialized ()) + if (!ec && hash_text.is_initialized ()) { - auto error_hash (key.decode_hex (hash_text.get ())); - if (error_hash) + if (key.decode_hex (hash_text.get ())) { - error_response (response, "Bad key hash number"); + ec = nano::error_rpc::bad_key; } } - boost::property_tree::ptree response_l; - boost::property_tree::ptree unchecked; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (node.store.unchecked_begin (transaction, key)), n (node.store.unchecked_end ()); i != n && unchecked.size () < count; ++i) + if (!ec) { - boost::property_tree::ptree entry; - rai::bufferstream stream (reinterpret_cast (i->second.data ()), i->second.size ()); - auto block (rai::deserialize_block (stream)); - std::string contents; - block->serialize_json (contents); - entry.put ("key", rai::block_hash (i->first.uint256 ()).to_string ()); - entry.put ("hash", block->hash ().to_string ()); - entry.put ("contents", contents); - unchecked.push_back (std::make_pair ("", entry)); + boost::property_tree::ptree unchecked; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (node.store.unchecked_begin (transaction, key)), n (node.store.unchecked_end ()); i != n && unchecked.size () < count; ++i) + { + boost::property_tree::ptree entry; + rai::bufferstream stream (reinterpret_cast (i->second.data ()), i->second.size ()); + auto block (rai::deserialize_block (stream)); + std::string contents; + block->serialize_json (contents); + entry.put ("key", rai::block_hash (i->first.uint256 ()).to_string ()); + entry.put ("hash", block->hash ().to_string ()); + entry.put ("contents", contents); + unchecked.push_back (std::make_pair ("", entry)); + } + response_l.add_child ("unchecked", unchecked); } - response_l.add_child ("unchecked", unchecked); - response (response_l); + response_errors (); } void rai::rpc_handler::version () { - boost::property_tree::ptree response_l; response_l.put ("rpc_version", "1"); response_l.put ("store_version", std::to_string (node.store_version ())); response_l.put ("node_vendor", boost::str (boost::format ("RaiBlocks %1%.%2%") % RAIBLOCKS_VERSION_MAJOR % RAIBLOCKS_VERSION_MINOR)); - response (response_l); + response_errors (); } void rai::rpc_handler::validate_account_number () @@ -3459,303 +2788,158 @@ void rai::rpc_handler::validate_account_number () std::string account_text (request.get ("account")); rai::uint256_union account; auto error (account.decode_account (account_text)); - boost::property_tree::ptree response_l; response_l.put ("valid", error ? "0" : "1"); - response (response_l); + response_errors (); } void rai::rpc_handler::wallet_add () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { std::string key_text (request.get ("key")); - std::string wallet_text (request.get ("wallet")); rai::raw_key key; - auto error (key.data.decode_hex (key_text)); - if (!error) + if (!key.data.decode_hex (key_text)) { - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + const bool generate_work = request.get ("work", true); + auto pub (wallet->insert_adhoc (key, generate_work)); + if (!pub.is_zero ()) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - const bool generate_work = request.get ("work", true); - auto pub (existing->second->insert_adhoc (key, generate_work)); - if (!pub.is_zero ()) - { - boost::property_tree::ptree response_l; - response_l.put ("account", pub.to_account ()); - response (response_l); - } - else - { - error_response (response, "Wallet locked"); - } - } - else - { - error_response (response, "Wallet not found"); - } + response_l.put ("account", pub.to_account ()); } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::wallet_locked; } } else { - error_response (response, "Bad private key"); + ec = nano::error_common::bad_private_key; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::wallet_add_watch () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + rai::transaction transaction (node.store.environment, nullptr, true); + if (wallet->store.valid_password (transaction)) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + for (auto & accounts : request.get_child ("accounts")) { - rai::transaction transaction (node.store.environment, nullptr, true); - if (existing->second->store.valid_password (transaction)) + auto account (account_impl (accounts.second.data ())); + if (!ec) { - for (auto & accounts : request.get_child ("accounts")) - { - std::string account_text = accounts.second.data (); - rai::uint256_union account; - auto error (account.decode_account (account_text)); - if (!error) - { - existing->second->insert_watch (transaction, account); - } - else - { - error_response (response, "Bad account number"); - } - } - boost::property_tree::ptree response_l; - response_l.put ("success", ""); - response (response_l); - } - else - { - error_response (response, "Wallet locked"); + wallet->insert_watch (transaction, account); } } - else - { - error_response (response, "Wallet not found"); - } + response_l.put ("success", ""); } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::wallet_locked; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::wallet_balance_total () { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + rai::uint128_t balance (0); + rai::uint128_t pending (0); + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (wallet->store.begin (transaction)), n (wallet->store.end ()); i != n; ++i) { - rai::uint128_t balance (0); - rai::uint128_t pending (0); - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (existing->second->store.begin (transaction)), n (existing->second->store.end ()); i != n; ++i) - { - rai::account account (i->first.uint256 ()); - balance = balance + node.ledger.account_balance (transaction, account); - pending = pending + node.ledger.account_pending (transaction, account); - } - boost::property_tree::ptree response_l; - response_l.put ("balance", balance.convert_to ()); - response_l.put ("pending", pending.convert_to ()); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); + rai::account account (i->first.uint256 ()); + balance = balance + node.ledger.account_balance (transaction, account); + pending = pending + node.ledger.account_pending (transaction, account); } + response_l.put ("balance", balance.convert_to ()); + response_l.put ("pending", pending.convert_to ()); } - else - { - error_response (response, "Bad wallet number"); - } + response_errors (); } void rai::rpc_handler::wallet_balances () { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + auto threshold (threshold_optional_impl ()); + if (!ec) { - rai::uint128_union threshold (0); - boost::optional threshold_text (request.get_optional ("threshold")); - if (threshold_text.is_initialized ()) + boost::property_tree::ptree balances; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (wallet->store.begin (transaction)), n (wallet->store.end ()); i != n; ++i) { - auto error_threshold (threshold.decode_dec (threshold_text.get ())); - if (error_threshold) + rai::account account (i->first.uint256 ()); + rai::uint128_t balance = node.ledger.account_balance (transaction, account); + if (balance >= threshold.number ()) { - error_response (response, "Bad threshold number"); + boost::property_tree::ptree entry; + rai::uint128_t pending = node.ledger.account_pending (transaction, account); + entry.put ("balance", balance.convert_to ()); + entry.put ("pending", pending.convert_to ()); + balances.push_back (std::make_pair (account.to_account (), entry)); } } - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - boost::property_tree::ptree response_l; - boost::property_tree::ptree balances; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (existing->second->store.begin (transaction)), n (existing->second->store.end ()); i != n; ++i) - { - rai::account account (i->first.uint256 ()); - rai::uint128_t balance = node.ledger.account_balance (transaction, account); - if (threshold.is_zero ()) - { - boost::property_tree::ptree entry; - rai::uint128_t pending = node.ledger.account_pending (transaction, account); - entry.put ("balance", balance.convert_to ()); - entry.put ("pending", pending.convert_to ()); - balances.push_back (std::make_pair (account.to_account (), entry)); - } - else - { - if (balance >= threshold.number ()) - { - boost::property_tree::ptree entry; - rai::uint128_t pending = node.ledger.account_pending (transaction, account); - entry.put ("balance", balance.convert_to ()); - entry.put ("pending", pending.convert_to ()); - balances.push_back (std::make_pair (account.to_account (), entry)); - } - } - } - response_l.add_child ("balances", balances); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Bad wallet number"); + response_l.add_child ("balances", balances); } + response_errors (); } void rai::rpc_handler::wallet_change_seed () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { std::string seed_text (request.get ("seed")); - std::string wallet_text (request.get ("wallet")); rai::raw_key seed; - auto error (seed.data.decode_hex (seed_text)); - if (!error) + if (!seed.data.decode_hex (seed_text)) { - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + rai::transaction transaction (node.store.environment, nullptr, true); + if (wallet->store.valid_password (transaction)) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - rai::transaction transaction (node.store.environment, nullptr, true); - if (existing->second->store.valid_password (transaction)) - { - existing->second->change_seed (transaction, seed); - boost::property_tree::ptree response_l; - response_l.put ("success", ""); - response (response_l); - } - else - { - error_response (response, "Wallet locked"); - } - } - else - { - error_response (response, "Wallet not found"); - } + wallet->change_seed (transaction, seed); + response_l.put ("success", ""); } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::wallet_locked; } } else { - error_response (response, "Bad seed"); + ec = nano::error_common::bad_seed; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::wallet_contains () { - std::string account_text (request.get ("account")); - std::string wallet_text (request.get ("wallet")); - rai::uint256_union account; - auto error (account.decode_account (account_text)); - if (!error) + auto account (account_impl ()); + auto wallet (wallet_impl ()); + if (!ec) { - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) - { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - rai::transaction transaction (node.store.environment, nullptr, false); - auto exists (existing->second->store.find (transaction, account) != existing->second->store.end ()); - boost::property_tree::ptree response_l; - response_l.put ("exists", exists ? "1" : "0"); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Bad wallet number"); - } - } - else - { - error_response (response, "Bad account number"); + rai::transaction transaction (node.store.environment, nullptr, false); + auto exists (wallet->store.find (transaction, account) != wallet->store.end ()); + response_l.put ("exists", exists ? "1" : "0"); } + response_errors (); } void rai::rpc_handler::wallet_create () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { rai::keypair wallet_id; node.wallets.create (wallet_id.pub); @@ -3763,142 +2947,89 @@ void rai::rpc_handler::wallet_create () auto existing (node.wallets.items.find (wallet_id.pub)); if (existing != node.wallets.items.end ()) { - boost::property_tree::ptree response_l; response_l.put ("wallet", wallet_id.pub.to_string ()); - response (response_l); } else { - error_response (response, "Failed to create wallet. Increase lmdb_max_dbs in node config."); + ec = nano::error_common::wallet_lmdb_max_dbs; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::wallet_destroy () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { std::string wallet_text (request.get ("wallet")); rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + if (!wallet.decode_hex (wallet_text)) { auto existing (node.wallets.items.find (wallet)); if (existing != node.wallets.items.end ()) { node.wallets.destroy (wallet); - boost::property_tree::ptree response_l; - response (response_l); + bool destroyed (node.wallets.items.find (wallet) == node.wallets.items.end ()); + response_l.put ("destroyed", destroyed ? "1" : "0"); } else { - error_response (response, "Wallet not found"); + ec = nano::error_common::wallet_not_found; } } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::bad_wallet_number; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::wallet_export () { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - rai::transaction transaction (node.store.environment, nullptr, false); - std::string json; - existing->second->store.serialize_json (transaction, json); - boost::property_tree::ptree response_l; - response_l.put ("json", json); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Bad account number"); + rai::transaction transaction (node.store.environment, nullptr, false); + std::string json; + wallet->store.serialize_json (transaction, json); + response_l.put ("json", json); } + response_errors (); } void rai::rpc_handler::wallet_frontiers () { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + boost::property_tree::ptree frontiers; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (wallet->store.begin (transaction)), n (wallet->store.end ()); i != n; ++i) { - boost::property_tree::ptree response_l; - boost::property_tree::ptree frontiers; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (existing->second->store.begin (transaction)), n (existing->second->store.end ()); i != n; ++i) + rai::account account (i->first.uint256 ()); + auto latest (node.ledger.latest (transaction, account)); + if (!latest.is_zero ()) { - rai::account account (i->first.uint256 ()); - auto latest (node.ledger.latest (transaction, account)); - if (!latest.is_zero ()) - { - frontiers.put (account.to_account (), latest.to_string ()); - } + frontiers.put (account.to_account (), latest.to_string ()); } - response_l.add_child ("frontiers", frontiers); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); } + response_l.add_child ("frontiers", frontiers); } - else - { - error_response (response, "Bad wallet number"); - } + response_errors (); } void rai::rpc_handler::wallet_key_valid () { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - rai::transaction transaction (node.store.environment, nullptr, false); - auto valid (existing->second->store.valid_password (transaction)); - boost::property_tree::ptree response_l; - response_l.put ("valid", valid ? "1" : "0"); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Bad wallet number"); + rai::transaction transaction (node.store.environment, nullptr, false); + auto valid (wallet->store.valid_password (transaction)); + response_l.put ("valid", valid ? "1" : "0"); } + response_errors (); } void rai::rpc_handler::wallet_ledger () @@ -3912,588 +3043,324 @@ void rai::rpc_handler::wallet_ledger () { modified_since = strtoul (modified_since_text.get ().c_str (), NULL, 10); } - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + boost::property_tree::ptree accounts; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (wallet->store.begin (transaction)), n (wallet->store.end ()); i != n; ++i) { - boost::property_tree::ptree response_l; - boost::property_tree::ptree accounts; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (existing->second->store.begin (transaction)), n (existing->second->store.end ()); i != n; ++i) + rai::account account (i->first.uint256 ()); + rai::account_info info; + if (!node.store.account_get (transaction, account, info)) { - rai::account account (i->first.uint256 ()); - rai::account_info info; - if (!node.store.account_get (transaction, account, info)) + if (info.modified >= modified_since) { - if (info.modified >= modified_since) + boost::property_tree::ptree entry; + entry.put ("frontier", info.head.to_string ()); + entry.put ("open_block", info.open_block.to_string ()); + entry.put ("representative_block", info.rep_block.to_string ()); + std::string balance; + rai::uint128_union (info.balance).encode_dec (balance); + entry.put ("balance", balance); + entry.put ("modified_timestamp", std::to_string (info.modified)); + entry.put ("block_count", std::to_string (info.block_count)); + if (representative) { - boost::property_tree::ptree entry; - entry.put ("frontier", info.head.to_string ()); - entry.put ("open_block", info.open_block.to_string ()); - entry.put ("representative_block", info.rep_block.to_string ()); - std::string balance; - rai::uint128_union (info.balance).encode_dec (balance); - entry.put ("balance", balance); - entry.put ("modified_timestamp", std::to_string (info.modified)); - entry.put ("block_count", std::to_string (info.block_count)); - if (representative) - { - auto block (node.store.block_get (transaction, info.rep_block)); - assert (block != nullptr); - entry.put ("representative", block->representative ().to_account ()); - } - if (weight) - { - auto account_weight (node.ledger.weight (transaction, account)); - entry.put ("weight", account_weight.convert_to ()); - } - if (pending) - { - auto account_pending (node.ledger.account_pending (transaction, account)); - entry.put ("pending", account_pending.convert_to ()); - } - accounts.push_back (std::make_pair (account.to_account (), entry)); + auto block (node.store.block_get (transaction, info.rep_block)); + assert (block != nullptr); + entry.put ("representative", block->representative ().to_account ()); } + if (weight) + { + auto account_weight (node.ledger.weight (transaction, account)); + entry.put ("weight", account_weight.convert_to ()); + } + if (pending) + { + auto account_pending (node.ledger.account_pending (transaction, account)); + entry.put ("pending", account_pending.convert_to ()); + } + accounts.push_back (std::make_pair (account.to_account (), entry)); } } - response_l.add_child ("accounts", accounts); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); } + response_l.add_child ("accounts", accounts); } - else - { - error_response (response, "Bad wallet number"); - } + response_errors (); } void rai::rpc_handler::wallet_lock () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) - { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - boost::property_tree::ptree response_l; - rai::raw_key empty; - empty.data.clear (); - existing->second->store.password.value_set (empty); - response_l.put ("locked", "1"); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Bad wallet number"); - } - } - else - { - error_response (response, "RPC control is disabled"); + rai::raw_key empty; + empty.data.clear (); + wallet->store.password.value_set (empty); + response_l.put ("locked", "1"); } + response_errors (); } void rai::rpc_handler::wallet_pending () { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + auto count (count_optional_impl ()); + auto threshold (threshold_optional_impl ()); + const bool source = request.get ("source", false); + const bool min_version = request.get ("min_version", false); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + boost::property_tree::ptree pending; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (wallet->store.begin (transaction)), n (wallet->store.end ()); i != n; ++i) { - uint64_t count (std::numeric_limits::max ()); - rai::uint128_union threshold (0); - boost::optional count_text (request.get_optional ("count")); - if (count_text.is_initialized ()) + rai::account account (i->first.uint256 ()); + boost::property_tree::ptree peers_l; + rai::account end (account.number () + 1); + for (auto ii (node.store.pending_begin (transaction, rai::pending_key (account, 0))), nn (node.store.pending_begin (transaction, rai::pending_key (end, 0))); ii != nn && peers_l.size () < count; ++ii) { - auto error (decode_unsigned (count_text.get (), count)); - if (error) + rai::pending_key key (ii->first); + if (threshold.is_zero () && !source) { - error_response (response, "Invalid count limit"); + boost::property_tree::ptree entry; + entry.put ("", key.hash.to_string ()); + peers_l.push_back (std::make_pair ("", entry)); } - } - boost::optional threshold_text (request.get_optional ("threshold")); - if (threshold_text.is_initialized ()) - { - auto error_threshold (threshold.decode_dec (threshold_text.get ())); - if (error_threshold) + else { - error_response (response, "Bad threshold number"); - } - } - const bool source = request.get ("source", false); - const bool min_version = request.get ("min_version", false); - boost::property_tree::ptree response_l; - boost::property_tree::ptree pending; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (existing->second->store.begin (transaction)), n (existing->second->store.end ()); i != n; ++i) - { - rai::account account (i->first.uint256 ()); - boost::property_tree::ptree peers_l; - rai::account end (account.number () + 1); - for (auto ii (node.store.pending_begin (transaction, rai::pending_key (account, 0))), nn (node.store.pending_begin (transaction, rai::pending_key (end, 0))); ii != nn && peers_l.size () < count; ++ii) - { - rai::pending_key key (ii->first); - if (threshold.is_zero () && !source) + rai::pending_info info (ii->second, ii->from_secondary_store ? rai::epoch::epoch_1 : rai::epoch::epoch_0); + if (info.amount.number () >= threshold.number ()) { - boost::property_tree::ptree entry; - entry.put ("", key.hash.to_string ()); - peers_l.push_back (std::make_pair ("", entry)); - } - else - { - rai::pending_info info (ii->second, ii->from_secondary_store ? rai::epoch::epoch_1 : rai::epoch::epoch_0); - if (info.amount.number () >= threshold.number ()) + if (source || min_version) { - if (source || min_version) + boost::property_tree::ptree pending_tree; + pending_tree.put ("amount", info.amount.number ().convert_to ()); + if (source) { - boost::property_tree::ptree pending_tree; - pending_tree.put ("amount", info.amount.number ().convert_to ()); - if (source) - { - pending_tree.put ("source", info.source.to_account ()); - } - if (min_version) - { - pending_tree.put ("min_version", info.epoch == rai::epoch::epoch_1 ? "1" : "0"); - } - peers_l.add_child (key.hash.to_string (), pending_tree); + pending_tree.put ("source", info.source.to_account ()); } - else + if (min_version) { - peers_l.put (key.hash.to_string (), info.amount.number ().convert_to ()); + pending_tree.put ("min_version", info.epoch == rai::epoch::epoch_1 ? "1" : "0"); } + peers_l.add_child (key.hash.to_string (), pending_tree); + } + else + { + peers_l.put (key.hash.to_string (), info.amount.number ().convert_to ()); } } } - if (!peers_l.empty ()) - { - pending.add_child (account.to_account (), peers_l); - } } - response_l.add_child ("blocks", pending); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); + if (!peers_l.empty ()) + { + pending.add_child (account.to_account (), peers_l); + } } + response_l.add_child ("blocks", pending); } - else - { - error_response (response, "Bad wallet number"); - } + response_errors (); } void rai::rpc_handler::wallet_representative () { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + auto wallet (wallet_impl ()); + if (!ec) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - rai::transaction transaction (node.store.environment, nullptr, false); - boost::property_tree::ptree response_l; - response_l.put ("representative", existing->second->store.representative (transaction).to_account ()); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Bad account number"); + rai::transaction transaction (node.store.environment, nullptr, false); + response_l.put ("representative", wallet->store.representative (transaction).to_account ()); } + response_errors (); } void rai::rpc_handler::wallet_representative_set () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + std::string representative_text (request.get ("representative")); + rai::account representative; + if (!representative.decode_account (representative_text)) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - std::string representative_text (request.get ("representative")); - rai::account representative; - auto error (representative.decode_account (representative_text)); - if (!error) - { - rai::transaction transaction (node.store.environment, nullptr, true); - existing->second->store.representative_set (transaction, representative); - boost::property_tree::ptree response_l; - response_l.put ("set", "1"); - response (response_l); - } - else - { - error_response (response, "Invalid account number"); - } - } - else - { - error_response (response, "Wallet not found"); - } + rai::transaction transaction (node.store.environment, nullptr, true); + wallet->store.representative_set (transaction, representative); + response_l.put ("set", "1"); } else { - error_response (response, "Bad account number"); + ec = nano::error_rpc::bad_representative_number; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::wallet_republish () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + auto count (count_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + boost::property_tree::ptree blocks; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (wallet->store.begin (transaction)), n (wallet->store.end ()); i != n; ++i) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) + rai::account account (i->first.uint256 ()); + auto latest (node.ledger.latest (transaction, account)); + std::unique_ptr block; + std::vector hashes; + while (!latest.is_zero () && hashes.size () < count) { - uint64_t count; - std::string count_text (request.get ("count")); - auto error (decode_unsigned (count_text, count)); - if (!error) - { - boost::property_tree::ptree response_l; - boost::property_tree::ptree blocks; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (existing->second->store.begin (transaction)), n (existing->second->store.end ()); i != n; ++i) - { - rai::account account (i->first.uint256 ()); - auto latest (node.ledger.latest (transaction, account)); - std::unique_ptr block; - std::vector hashes; - while (!latest.is_zero () && hashes.size () < count) - { - hashes.push_back (latest); - block = node.store.block_get (transaction, latest); - latest = block->previous (); - } - std::reverse (hashes.begin (), hashes.end ()); - for (auto & hash : hashes) - { - block = node.store.block_get (transaction, hash); - node.network.republish_block (transaction, std::move (block)); - ; - boost::property_tree::ptree entry; - entry.put ("", hash.to_string ()); - blocks.push_back (std::make_pair ("", entry)); - } - } - response_l.add_child ("blocks", blocks); - response (response_l); - } - else - { - error_response (response, "Invalid count limit"); - } + hashes.push_back (latest); + block = node.store.block_get (transaction, latest); + latest = block->previous (); } - else + std::reverse (hashes.begin (), hashes.end ()); + for (auto & hash : hashes) { - error_response (response, "Wallet not found"); + block = node.store.block_get (transaction, hash); + node.network.republish_block (transaction, std::move (block)); + boost::property_tree::ptree entry; + entry.put ("", hash.to_string ()); + blocks.push_back (std::make_pair ("", entry)); } } - else - { - error_response (response, "Bad wallet number"); - } - } - else - { - error_response (response, "RPC control is disabled"); + response_l.add_child ("blocks", blocks); } + response_errors (); } void rai::rpc_handler::wallet_work_get () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + boost::property_tree::ptree works; + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (wallet->store.begin (transaction)), n (wallet->store.end ()); i != n; ++i) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - boost::property_tree::ptree response_l; - boost::property_tree::ptree works; - rai::transaction transaction (node.store.environment, nullptr, false); - for (auto i (existing->second->store.begin (transaction)), n (existing->second->store.end ()); i != n; ++i) - { - rai::account account (i->first.uint256 ()); - uint64_t work (0); - auto error_work (existing->second->store.work_get (transaction, account, work)); - works.put (account.to_account (), rai::to_string_hex (work)); - } - response_l.add_child ("works", works); - response (response_l); - } - else - { - error_response (response, "Wallet not found"); - } - } - else - { - error_response (response, "Bad wallet number"); + rai::account account (i->first.uint256 ()); + uint64_t work (0); + auto error_work (wallet->store.work_get (transaction, account, work)); + works.put (account.to_account (), rai::to_string_hex (work)); } + response_l.add_child ("works", works); } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::work_generate () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto hash (hash_impl ()); + if (!ec) { - std::string hash_text (request.get ("hash")); bool use_peers (request.get_optional ("use_peers") == true); - rai::block_hash hash; - auto error (hash.decode_hex (hash_text)); - if (!error) - { - auto rpc_l (shared_from_this ()); - auto callback = [rpc_l](boost::optional const & work_a) { - if (work_a) - { - boost::property_tree::ptree response_l; - response_l.put ("work", rai::to_string_hex (work_a.value ())); - rpc_l->response (response_l); - } - else - { - error_response (rpc_l->response, "Cancelled"); - } - }; - if (!use_peers) + auto rpc_l (shared_from_this ()); + auto callback = [rpc_l](boost::optional const & work_a) { + if (work_a) { - node.work.generate (hash, callback); + boost::property_tree::ptree response_l; + response_l.put ("work", rai::to_string_hex (work_a.value ())); + rpc_l->response (response_l); } else { - node.work_generate (hash, callback); + error_response (rpc_l->response, "Cancelled"); } + }; + if (!use_peers) + { + node.work.generate (hash, callback); } else { - error_response (response, "Bad block hash"); + node.work_generate (hash, callback); } } - else + // Because of callback + if (ec) { - error_response (response, "RPC control is disabled"); + response_errors (); } } void rai::rpc_handler::work_cancel () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto hash (hash_impl ()); + if (!ec) { - std::string hash_text (request.get ("hash")); - rai::block_hash hash; - auto error (hash.decode_hex (hash_text)); - if (!error) - { - node.work.cancel (hash); - boost::property_tree::ptree response_l; - response (response_l); - } - else - { - error_response (response, "Bad block hash"); - } - } - else - { - error_response (response, "RPC control is disabled"); + node.work.cancel (hash); } + response_errors (); } void rai::rpc_handler::work_get () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + auto account (account_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + rai::transaction transaction (node.store.environment, nullptr, false); + if (wallet->store.find (transaction, account) != wallet->store.end ()) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - std::string account_text (request.get ("account")); - rai::account account; - auto error (account.decode_account (account_text)); - if (!error) - { - rai::transaction transaction (node.store.environment, nullptr, false); - auto account_check (existing->second->store.find (transaction, account)); - if (account_check != existing->second->store.end ()) - { - uint64_t work (0); - auto error_work (existing->second->store.work_get (transaction, account, work)); - boost::property_tree::ptree response_l; - response_l.put ("work", rai::to_string_hex (work)); - response (response_l); - } - else - { - error_response (response, "Account not found in wallet"); - } - } - else - { - error_response (response, "Bad account number"); - } - } - else - { - error_response (response, "Wallet not found"); - } + uint64_t work (0); + auto error_work (wallet->store.work_get (transaction, account, work)); + response_l.put ("work", rai::to_string_hex (work)); } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::account_not_found_wallet; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::work_set () { - if (rpc.config.enable_control) + rpc_control_impl (); + auto wallet (wallet_impl ()); + auto account (account_impl ()); + auto work (work_optional_impl ()); + if (!ec) { - std::string wallet_text (request.get ("wallet")); - rai::uint256_union wallet; - auto error (wallet.decode_hex (wallet_text)); - if (!error) + rai::transaction transaction (node.store.environment, nullptr, true); + if (wallet->store.find (transaction, account) != wallet->store.end ()) { - auto existing (node.wallets.items.find (wallet)); - if (existing != node.wallets.items.end ()) - { - std::string account_text (request.get ("account")); - rai::account account; - auto error (account.decode_account (account_text)); - if (!error) - { - rai::transaction transaction (node.store.environment, nullptr, true); - auto account_check (existing->second->store.find (transaction, account)); - if (account_check != existing->second->store.end ()) - { - std::string work_text (request.get ("work")); - uint64_t work; - auto work_error (rai::from_string_hex (work_text, work)); - if (!work_error) - { - existing->second->store.work_put (transaction, account, work); - boost::property_tree::ptree response_l; - response_l.put ("success", ""); - response (response_l); - } - else - { - error_response (response, "Bad work"); - } - } - else - { - error_response (response, "Account not found in wallet"); - } - } - else - { - error_response (response, "Bad account number"); - } - } - else - { - error_response (response, "Wallet not found"); - } + wallet->store.work_put (transaction, account, work); + response_l.put ("success", ""); } else { - error_response (response, "Bad wallet number"); + ec = nano::error_common::account_not_found_wallet; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::work_validate () { - std::string hash_text (request.get ("hash")); - rai::block_hash hash; - auto error (hash.decode_hex (hash_text)); - if (!error) + auto hash (hash_impl ()); + auto work (work_optional_impl ()); + if (!ec) { - std::string work_text (request.get ("work")); - uint64_t work; - auto work_error (rai::from_string_hex (work_text, work)); - if (!work_error) - { - auto validate (rai::work_validate (hash, work)); - boost::property_tree::ptree response_l; - response_l.put ("valid", validate ? "0" : "1"); - response (response_l); - } - else - { - error_response (response, "Bad work"); - } - } - else - { - error_response (response, "Bad block hash"); + auto validate (rai::work_validate (hash, work)); + response_l.put ("valid", validate ? "0" : "1"); } + response_errors (); } void rai::rpc_handler::work_peer_add () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { std::string address_text = request.get ("address"); std::string port_text = request.get ("port"); @@ -4501,24 +3368,20 @@ void rai::rpc_handler::work_peer_add () if (!rai::parse_port (port_text, port)) { node.config.work_peers.push_back (std::make_pair (address_text, port)); - boost::property_tree::ptree response_l; response_l.put ("success", ""); - response (response_l); } else { - error_response (response, "Invalid port"); + ec = nano::error_common::invalid_port; } } - else - { - error_response (response, "RPC control is disabled"); - } + response_errors (); } void rai::rpc_handler::work_peers () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { boost::property_tree::ptree work_peers_l; for (auto i (node.config.work_peers.begin ()), n (node.config.work_peers.end ()); i != n; ++i) @@ -4527,29 +3390,20 @@ void rai::rpc_handler::work_peers () entry.put ("", boost::str (boost::format ("%1%:%2%") % i->first % i->second)); work_peers_l.push_back (std::make_pair ("", entry)); } - boost::property_tree::ptree response_l; response_l.add_child ("work_peers", work_peers_l); - response (response_l); - } - else - { - error_response (response, "RPC control is disabled"); } + response_errors (); } void rai::rpc_handler::work_peers_clear () { - if (rpc.config.enable_control) + rpc_control_impl (); + if (!ec) { node.config.work_peers.clear (); - boost::property_tree::ptree response_l; response_l.put ("success", ""); - response (response_l); - } - else - { - error_response (response, "RPC control is disabled"); } + response_errors (); } rai::rpc_connection::rpc_connection (rai::node & node_a, rai::rpc & rpc_a) : @@ -4780,7 +3634,7 @@ void rai::rpc_handler::process_request () } else if (action == "successors") { - successors (); + chain (true); } else if (action == "bootstrap") { @@ -4837,11 +3691,11 @@ void rai::rpc_handler::process_request () } else if (action == "krai_from_raw") { - krai_from_raw (); + mrai_from_raw (rai::kxrb_ratio); } else if (action == "krai_to_raw") { - krai_to_raw (); + mrai_to_raw (rai::kxrb_ratio); } else if (action == "ledger") { @@ -4901,11 +3755,11 @@ void rai::rpc_handler::process_request () } else if (action == "rai_from_raw") { - rai_from_raw (); + mrai_from_raw (rai::xrb_ratio); } else if (action == "rai_to_raw") { - rai_to_raw (); + mrai_to_raw (rai::xrb_ratio); } else if (action == "receive") { diff --git a/rai/node/rpc.hpp b/rai/node/rpc.hpp index d4bee17c..8d2a7a20 100644 --- a/rai/node/rpc.hpp +++ b/rai/node/rpc.hpp @@ -144,7 +144,7 @@ public: void block_hash (); void bootstrap (); void bootstrap_any (); - void chain (); + void chain (bool = false); void confirmation_history (); void delegators (); void delegators_count (); @@ -154,14 +154,12 @@ public: void keepalive (); void key_create (); void key_expand (); - void krai_to_raw (); - void krai_from_raw (); void ledger (); - void mrai_to_raw (); - void mrai_from_raw (); + void mrai_to_raw (rai::uint128_t = rai::Mxrb_ratio); + void mrai_from_raw (rai::uint128_t = rai::Mxrb_ratio); void password_change (); void password_enter (); - void password_valid (bool wallet_locked); + void password_valid (bool = false); void payment_begin (); void payment_init (); void payment_end (); @@ -170,8 +168,6 @@ public: void pending (); void pending_exists (); void process (); - void rai_to_raw (); - void rai_from_raw (); void receive (); void receive_minimum (); void receive_minimum_set (); @@ -183,7 +179,6 @@ public: void send (); void stats (); void stop (); - void successors (); void unchecked (); void unchecked_clear (); void unchecked_get (); @@ -222,6 +217,18 @@ public: rai::rpc & rpc; boost::property_tree::ptree request; std::function response; + void response_errors (); + std::error_code ec; + boost::property_tree::ptree response_l; + std::shared_ptr wallet_impl (); + rai::account account_impl (std::string = ""); + rai::amount amount_impl (); + rai::block_hash hash_impl (std::string = "hash"); + rai::amount threshold_optional_impl (); + uint64_t work_optional_impl (); + uint64_t count_impl (); + uint64_t count_optional_impl (uint64_t = std::numeric_limits::max ()); + bool rpc_control_impl (); }; /** Returns the correct RPC implementation based on TLS configuration */ std::unique_ptr get_rpc (boost::asio::io_service & service_a, rai::node & node_a, rai::rpc_config const & config_a);