From 2143fa99c448018e5fd3b44c8c409c5ada26dfcc Mon Sep 17 00:00:00 2001 From: SergiySW Date: Sat, 24 Feb 2018 19:29:58 +0300 Subject: [PATCH] Watch only accounts * Adding basic watch-only accounts without private keys * RPC wallet_ledger * Simplifying optional bool request values * Adding "modified_since" option to RPC ledger --- rai/node/rpc.cpp | 289 ++++++++++++++++++++++++++++---------------- rai/node/rpc.hpp | 2 + rai/node/wallet.cpp | 16 ++- rai/node/wallet.hpp | 2 + 4 files changed, 205 insertions(+), 104 deletions(-) diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index bb8290b5..88250a5b 100644 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -340,24 +340,9 @@ void rai::rpc_handler::account_info () auto error (account.decode_account (account_text)); if (!error) { - bool representative (false); - boost::optional representative_optional (request.get_optional ("representative")); - if (representative_optional.is_initialized ()) - { - representative = representative_optional.get (); - } - bool weight (false); - boost::optional weight_optional (request.get_optional ("weight")); - if (weight_optional.is_initialized ()) - { - weight = weight_optional.get (); - } - bool pending (false); - boost::optional pending_optional (request.get_optional ("pending")); - if (pending_optional.is_initialized ()) - { - pending = pending_optional.get (); - } + const bool representative = *(request.get_optional ("representative")); + const bool weight = *(request.get_optional ("weight")); + const bool pending = *(request.get_optional ("pending")); rai::transaction transaction (node.store.environment, nullptr, false); rai::account_info info; if (!node.store.account_get (transaction, account, info)) @@ -815,7 +800,6 @@ void rai::rpc_handler::accounts_pending () { uint64_t count (std::numeric_limits::max ()); rai::uint128_union threshold (0); - bool source (false); boost::optional count_text (request.get_optional ("count")); if (count_text.is_initialized ()) { @@ -834,11 +818,7 @@ void rai::rpc_handler::accounts_pending () error_response (response, "Bad threshold number"); } } - boost::optional source_optional (request.get_optional ("source")); - if (source_optional.is_initialized ()) - { - source = source_optional.get (); - } + const bool source = *(request.get_optional ("source")); boost::property_tree::ptree response_l; boost::property_tree::ptree pending; rai::transaction transaction (node.store.environment, nullptr, false); @@ -965,18 +945,8 @@ void rai::rpc_handler::blocks () void rai::rpc_handler::blocks_info () { - bool pending (false); - boost::optional pending_optional (request.get_optional ("pending")); - if (pending_optional.is_initialized ()) - { - pending = pending_optional.get (); - } - bool source (false); - boost::optional source_optional (request.get_optional ("source")); - if (source_optional.is_initialized ()) - { - source = source_optional.get (); - } + const bool pending = *(request.get_optional ("pending")); + const bool source = *(request.get_optional ("source")); std::vector hashes; boost::property_tree::ptree response_l; boost::property_tree::ptree blocks; @@ -1792,7 +1762,6 @@ void rai::rpc_handler::ledger () { rai::account start (0); uint64_t count (std::numeric_limits::max ()); - bool sorting (false); boost::optional account_text (request.get_optional ("account")); if (account_text.is_initialized ()) { @@ -1811,29 +1780,16 @@ void rai::rpc_handler::ledger () error_response (response, "Invalid count limit"); } } - boost::optional sorting_optional (request.get_optional ("sorting")); - if (sorting_optional.is_initialized ()) + uint64_t modified_since (0); + boost::optional modified_since_text (request.get_optional ("modified_since")); + if (modified_since_text.is_initialized ()) { - sorting = sorting_optional.get (); - } - bool representative (false); - boost::optional representative_optional (request.get_optional ("representative")); - if (representative_optional.is_initialized ()) - { - representative = representative_optional.get (); - } - bool weight (false); - boost::optional weight_optional (request.get_optional ("weight")); - if (weight_optional.is_initialized ()) - { - weight = weight_optional.get (); - } - bool pending (false); - boost::optional pending_optional (request.get_optional ("pending")); - if (pending_optional.is_initialized ()) - { - pending = pending_optional.get (); + modified_since = strtoul (modified_since_text.get ().c_str (), NULL, 10); } + const bool sorting = *(request.get_optional ("sorting")); + const bool representative = *(request.get_optional ("representative")); + const bool weight = *(request.get_optional ("weight")); + const bool pending = *(request.get_optional ("pending")); boost::property_tree::ptree response_a; boost::property_tree::ptree response_l; boost::property_tree::ptree accounts; @@ -1843,33 +1799,36 @@ void rai::rpc_handler::ledger () for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n && accounts.size () < count; ++i) { rai::account_info info (i->second); - 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 ()); - 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)); - if (representative) + if (info.modified >= modified_since) { - auto block (node.store.block_get (transaction, info.rep_block)); - assert (block != nullptr); - response_l.put ("representative", block->representative ().to_account ()); + 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 ()); + 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)); + if (representative) + { + auto block (node.store.block_get (transaction, info.rep_block)); + assert (block != nullptr); + response_l.put ("representative", block->representative ().to_account ()); + } + if (weight) + { + auto account_weight (node.ledger.weight (transaction, account)); + response_l.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 ()); + } + accounts.push_back (std::make_pair (account.to_account (), response_l)); } - if (weight) - { - auto account_weight (node.ledger.weight (transaction, account)); - response_l.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 ()); - } - accounts.push_back (std::make_pair (account.to_account (), response_l)); } } else // Sorting @@ -1877,8 +1836,12 @@ void rai::rpc_handler::ledger () std::vector> ledger_l; for (auto i (node.store.latest_begin (transaction, start)), n (node.store.latest_end ()); i != n; ++i) { - rai::uint128_union balance (rai::account_info (i->second).balance); - ledger_l.push_back (std::make_pair (balance, rai::account (i->first.uint256 ()))); + rai::account_info info (i->second); + rai::uint128_union balance (info.balance); + if (info.modified >= modified_since) + { + ledger_l.push_back (std::make_pair (balance, rai::account (i->first.uint256 ()))); + } } std::sort (ledger_l.begin (), ledger_l.end ()); std::reverse (ledger_l.begin (), ledger_l.end ()); @@ -2124,7 +2087,6 @@ void rai::rpc_handler::pending () { uint64_t count (std::numeric_limits::max ()); rai::uint128_union threshold (0); - bool source (false); boost::optional count_text (request.get_optional ("count")); if (count_text.is_initialized ()) { @@ -2143,11 +2105,7 @@ void rai::rpc_handler::pending () error_response (response, "Bad threshold number"); } } - boost::optional source_optional (request.get_optional ("source")); - if (source_optional.is_initialized ()) - { - source = source_optional.get (); - } + const bool source = *(request.get_optional ("source")); boost::property_tree::ptree response_l; boost::property_tree::ptree peers_l; { @@ -2711,7 +2669,6 @@ void rai::rpc_handler::receive_minimum_set () void rai::rpc_handler::representatives () { uint64_t count (std::numeric_limits::max ()); - bool sorting (false); boost::optional count_text (request.get_optional ("count")); if (count_text.is_initialized ()) { @@ -2721,11 +2678,7 @@ void rai::rpc_handler::representatives () error_response (response, "Invalid count limit"); } } - boost::optional sorting_optional (request.get_optional ("sorting")); - if (sorting_optional.is_initialized ()) - { - sorting = sorting_optional.get (); - } + const bool sorting = *(request.get_optional ("sorting")); boost::property_tree::ptree response_l; boost::property_tree::ptree representatives; rai::transaction transaction (node.store.environment, nullptr, false); @@ -3255,6 +3208,60 @@ void rai::rpc_handler::wallet_add () } } +void rai::rpc_handler::wallet_add_watch () +{ + if (rpc.config.enable_control) + { + 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); + if (existing->second->store.valid_password (transaction)) + { + 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"); + } + } + else + { + error_response (response, "Wallet not found"); + } + } + else + { + error_response (response, "Bad wallet number"); + } + } + else + { + error_response (response, "RPC control is disabled"); + } +} + void rai::rpc_handler::wallet_balance_total () { std::string wallet_text (request.get ("wallet")); @@ -3587,6 +3594,79 @@ void rai::rpc_handler::wallet_key_valid () } } +void rai::rpc_handler::wallet_ledger () +{ + const bool representative = *(request.get_optional ("representative")); + const bool weight = *(request.get_optional ("weight")); + const bool pending = *(request.get_optional ("pending")); + uint64_t modified_since (0); + boost::optional modified_since_text (request.get_optional ("modified_since")); + if (modified_since_text.is_initialized ()) + { + 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 existing (node.wallets.items.find (wallet)); + if (existing != node.wallets.items.end ()) + { + 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)) + { + 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) + { + 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"); + } + } + else + { + error_response (response, "Bad wallet number"); + } +} + void rai::rpc_handler::wallet_lock () { if (rpc.config.enable_control) @@ -3634,7 +3714,6 @@ void rai::rpc_handler::wallet_pending () { uint64_t count (std::numeric_limits::max ()); rai::uint128_union threshold (0); - bool source (false); boost::optional count_text (request.get_optional ("count")); if (count_text.is_initialized ()) { @@ -3653,11 +3732,7 @@ void rai::rpc_handler::wallet_pending () error_response (response, "Bad threshold number"); } } - boost::optional source_optional (request.get_optional ("source")); - if (source_optional.is_initialized ()) - { - source = source_optional.get (); - } + const bool source = *(request.get_optional ("source")); boost::property_tree::ptree response_l; boost::property_tree::ptree pending; rai::transaction transaction (node.store.environment, nullptr, false); @@ -4554,6 +4629,10 @@ void rai::rpc_handler::process_request () { wallet_add (); } + else if (action == "wallet_add_watch") + { + wallet_add_watch (); + } else if (action == "wallet_balance_total") { wallet_balance_total (); @@ -4590,6 +4669,10 @@ void rai::rpc_handler::process_request () { wallet_key_valid (); } + else if (action == "wallet_ledger") + { + wallet_ledger (); + } else if (action == "wallet_lock") { wallet_lock (); diff --git a/rai/node/rpc.hpp b/rai/node/rpc.hpp index 2bf0b6f9..91ca8a39 100644 --- a/rai/node/rpc.hpp +++ b/rai/node/rpc.hpp @@ -185,6 +185,7 @@ public: void validate_account_number (); void version (); void wallet_add (); + void wallet_add_watch (); void wallet_balance_total (); void wallet_balances (); void wallet_change_seed (); @@ -194,6 +195,7 @@ public: void wallet_export (); void wallet_frontiers (); void wallet_key_valid (); + void wallet_ledger (); void wallet_lock (); void wallet_pending (); void wallet_representative (); diff --git a/rai/node/wallet.cpp b/rai/node/wallet.cpp index b128427f..58bd7a1a 100644 --- a/rai/node/wallet.cpp +++ b/rai/node/wallet.cpp @@ -420,6 +420,11 @@ rai::public_key rai::wallet_store::insert_adhoc (MDB_txn * transaction_a, rai::r return pub; } +void rai::wallet_store::insert_watch (MDB_txn * transaction_a, rai::public_key const & pub) +{ + entry_put_raw (transaction_a, pub, rai::wallet_value (rai::uint256_union (0), 0)); +} + void rai::wallet_store::erase (MDB_txn * transaction_a, rai::public_key const & pub) { auto status (mdb_del (transaction_a, handle, rai::mdb_val (pub), nullptr)); @@ -790,6 +795,11 @@ rai::public_key rai::wallet::insert_adhoc (rai::raw_key const & account_a, bool return result; } +void rai::wallet::insert_watch (MDB_txn * transaction_a, rai::public_key const & pub_a) +{ + store.insert_watch (transaction_a, pub_a); +} + bool rai::wallet::exists (rai::public_key const & account_a) { rai::transaction transaction (store.environment, nullptr, false); @@ -1118,7 +1128,11 @@ public: { for (auto i (wallet_a->store.begin (transaction_a)), n (wallet_a->store.end ()); i != n; ++i) { - keys.insert (i->first.uint256 ()); + // Don't search pending for watch-only accounts + if (!rai::wallet_value (i->second).key.is_zero ()) + { + keys.insert (i->first.uint256 ()); + } } } void run () diff --git a/rai/node/wallet.hpp b/rai/node/wallet.hpp index 0bcc7d8a..3de60d60 100644 --- a/rai/node/wallet.hpp +++ b/rai/node/wallet.hpp @@ -74,6 +74,7 @@ public: rai::account representative (MDB_txn *); void representative_set (MDB_txn *, rai::account const &); rai::public_key insert_adhoc (MDB_txn *, rai::raw_key const &); + void insert_watch (MDB_txn *, rai::public_key const &); void erase (MDB_txn *, rai::public_key const &); rai::wallet_value entry_get_raw (MDB_txn *, rai::public_key const &); void entry_put_raw (MDB_txn *, rai::public_key const &, rai::wallet_value const &); @@ -132,6 +133,7 @@ public: bool enter_password (std::string const &); rai::public_key insert_adhoc (rai::raw_key const &, bool = true); rai::public_key insert_adhoc (MDB_txn *, rai::raw_key const &, bool = true); + void insert_watch (MDB_txn *, rai::public_key const &); rai::public_key deterministic_insert (MDB_txn *, bool = true); rai::public_key deterministic_insert (bool = true); bool exists (rai::public_key const &);