From d7bc9f9d9d979c1128124c946926cf01867a9d2b Mon Sep 17 00:00:00 2001 From: SergiySW Date: Sun, 23 Jul 2017 21:44:08 +0300 Subject: [PATCH 1/5] RPC delegators & delegators_count --- rai/node/rpc.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ rai/node/rpc.hpp | 2 ++ 2 files changed, 68 insertions(+) diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 7764a4b9..945c94c9 100755 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -852,6 +852,64 @@ void rai::rpc_handler::chain () } } +void rai::rpc_handler::delegators () +{ + std::string account_text (request.get ("account")); + rai::account account; + auto error (account.decode_account (account_text)); + if (!error) + { + 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) + { + rai::account_info info (i->second); + auto block (node.store.block_get (transaction, info.rep_block)); + assert (block != nullptr); + if (block->representative() == account) { + rai::account account_l (i->first); + auto balance (node.ledger.account_balance (transaction, account_l)); + delegators.put (account_l.to_account (), balance.convert_to ()); + } + } + response_l.add_child ("delegators", delegators); + response (response_l); + } + else + { + error_response (response, "Bad account number"); + } +} + +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) + { + uint64_t count (0); + rai::transaction transaction (node.store.environment, nullptr, false); + for (auto i (node.store.latest_begin (transaction)), n (node.store.latest_end ()); i != n; ++i) + { + rai::account_info info (i->second); + auto block (node.store.block_get (transaction, info.rep_block)); + assert (block != nullptr); + if (block->representative() == account) { + ++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"); + } +} + void rai::rpc_handler::deterministic_key () { std::string seed_text (request.get ("seed")); @@ -2558,6 +2616,14 @@ void rai::rpc_handler::process_request () { chain (); } + else if (action == "delegators") + { + delegators (); + } + else if (action == "delegators_count") + { + delegators_count (); + } else if (action == "deterministic_key") { deterministic_key (); diff --git a/rai/node/rpc.hpp b/rai/node/rpc.hpp index 7cc8d98d..a39557af 100644 --- a/rai/node/rpc.hpp +++ b/rai/node/rpc.hpp @@ -112,6 +112,8 @@ public: void bootstrap (); void bootstrap_any (); void chain (); + void delegators (); + void delegators_count (); void deterministic_key (); void frontiers (); void frontier_count (); From 70e6f93f22eb37539d66a1a2e71036f6a152a956 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Mon, 24 Jul 2017 10:03:54 +0300 Subject: [PATCH 2/5] Tests for RPC delegators, delegators_count --- rai/core_test/rpc.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++ rai/node/rpc.cpp | 6 ++--- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index fb3d2ce0..30dae4e7 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -2162,3 +2162,64 @@ TEST (rpc, wallet_balances) ASSERT_EQ ("0", pending_text); } } + +TEST (rpc, delegators) +{ + rai::system system (24000, 1); + rai::keypair key; + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + system.wallet (0)->insert_adhoc (key.prv); + auto & node1 (*system.nodes [0]); + auto latest (system.nodes [0]->latest (rai::test_genesis_key.pub)); + rai::send_block send (latest, key.pub, 100, rai::test_genesis_key.prv, rai::test_genesis_key.pub, node1.generate_work (latest)); + system.nodes [0]->process (send); + rai::open_block open (send.hash (), rai::test_genesis_key.pub, key.pub, key.prv, key.pub, node1.generate_work (key.pub)); + ASSERT_EQ (rai::process_result::progress, system.nodes [0]->process (open).code); + rai::rpc rpc (system.service, *system.nodes [0], rai::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "delegators"); + request.put ("account", rai::test_genesis_key.pub.to_account ()); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + auto & delegators_node (response.json.get_child ("delegators")); + boost::property_tree::ptree delegators; + for (auto i (delegators_node.begin ()), n (delegators_node.end ()); i != n; ++i) + { + delegators.put ((i->first), (i->second.get (""))); + } + ASSERT_EQ (2, delegators.size ()); + ASSERT_EQ ("100", delegators.get (rai::test_genesis_key.pub.to_account ())); + ASSERT_EQ ("340282366920938463463374607431768211355", delegators.get (key.pub.to_account ())); +} + +TEST (rpc, delegators_count) +{ + rai::system system (24000, 1); + rai::keypair key; + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + system.wallet (0)->insert_adhoc (key.prv); + auto & node1 (*system.nodes [0]); + auto latest (system.nodes [0]->latest (rai::test_genesis_key.pub)); + rai::send_block send (latest, key.pub, 100, rai::test_genesis_key.prv, rai::test_genesis_key.pub, node1.generate_work (latest)); + system.nodes [0]->process (send); + rai::open_block open (send.hash (), rai::test_genesis_key.pub, key.pub, key.prv, key.pub, node1.generate_work (key.pub)); + ASSERT_EQ (rai::process_result::progress, system.nodes [0]->process (open).code); + rai::rpc rpc (system.service, *system.nodes [0], rai::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "delegators_count"); + request.put ("account", rai::test_genesis_key.pub.to_account ()); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + std::string count (response.json.get ("count")); + ASSERT_EQ ("2", count); +} diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 945c94c9..66ad1247 100755 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -868,9 +868,9 @@ void rai::rpc_handler::delegators () auto block (node.store.block_get (transaction, info.rep_block)); assert (block != nullptr); if (block->representative() == account) { - rai::account account_l (i->first); - auto balance (node.ledger.account_balance (transaction, account_l)); - delegators.put (account_l.to_account (), balance.convert_to ()); + std::string balance; + rai::uint128_union (info.balance).encode_dec (balance); + delegators.put (rai::account (i->first).to_account (), balance); } } response_l.add_child ("delegators", delegators); From d361b726c1d838886969e9d4365da363d698c349 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Wed, 26 Jul 2017 21:52:39 +0300 Subject: [PATCH 3/5] RPC account_info & blocks_info blocks_info - blocks with amount & containing account --- rai/node/rpc.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ rai/node/rpc.hpp | 2 ++ 2 files changed, 83 insertions(+) diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 66ad1247..41d81d50 100755 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -263,6 +263,39 @@ void rai::rpc_handler::account_get () } } +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) + { + 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 ("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)); + response (response_l); + } + else + { + error_response (response, "Account not found"); + } + } + else + { + error_response (response, "Bad account number"); + } +} + void rai::rpc_handler::account_key () { std::string account_text (request.get ("account")); @@ -699,6 +732,46 @@ void rai::rpc_handler::blocks () response (response_l); } +void rai::rpc_handler::blocks_info () +{ + 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) + { + auto block (node.store.block_get (transaction, hash)); + if (block != nullptr) + { + 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); + blocks.push_back (std::make_pair (hash_text, entry)); + } + else + { + error_response (response, "Block not found"); + } + } + else + { + error_response (response, "Bad hash number"); + } + } + response_l.add_child ("blocks", blocks); + response (response_l); +} + void rai::rpc_handler::block_account () { std::string hash_text (request.get ("hash")); @@ -2540,6 +2613,10 @@ void rai::rpc_handler::process_request () { account_history (); } + else if (action == "account_info") + { + account_info (); + } else if (action == "account_key") { account_key (); @@ -2592,6 +2669,10 @@ void rai::rpc_handler::process_request () { blocks (); } + else if (action == "blocks_info") + { + blocks_info (); + } else if (action == "block_account") { block_account (); diff --git a/rai/node/rpc.hpp b/rai/node/rpc.hpp index a39557af..e300427f 100644 --- a/rai/node/rpc.hpp +++ b/rai/node/rpc.hpp @@ -94,6 +94,7 @@ public: void account_create (); void account_get (); void account_history (); + void account_info (); void account_key (); void account_list (); void account_move (); @@ -107,6 +108,7 @@ public: void available_supply (); void block (); void blocks (); + void blocks_info (); void block_account (); void block_count (); void bootstrap (); From 5fdbedcc7f81bdd8823ee47c61281c35e2bc197b Mon Sep 17 00:00:00 2001 From: SergiySW Date: Thu, 27 Jul 2017 09:33:51 +0300 Subject: [PATCH 4/5] RPC work_peer_add, work_peers, work_peers_clear --- rai/node/rpc.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ rai/node/rpc.hpp | 3 ++ 2 files changed, 85 insertions(+) diff --git a/rai/node/rpc.cpp b/rai/node/rpc.cpp index 41d81d50..1f1bbc4d 100755 --- a/rai/node/rpc.cpp +++ b/rai/node/rpc.cpp @@ -2508,6 +2508,76 @@ void rai::rpc_handler::work_validate () } } +void rai::rpc_handler::work_peer_add () +{ + if (rpc.config.enable_control) + { + 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) + { + uint16_t port; + if (!rai::parse_port (port_text, port)) + { + node.config.work_peers.push_back (std::make_pair (address, port)); + boost::property_tree::ptree response_l; + response_l.put ("success", ""); + response (response_l); + } + else + { + error_response (response, "Invalid port"); + } + } + else + { + error_response (response, "Invalid address"); + } + } + else + { + error_response (response, "RPC control is disabled"); + } +} + +void rai::rpc_handler::work_peers () +{ + if (rpc.config.enable_control) + { + boost::property_tree::ptree work_peers_l; + for (auto i (node.config.work_peers.begin ()), n (node.config.work_peers.end ()); i != n; ++i) + { + boost::property_tree::ptree entry; + 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"); + } +} + +void rai::rpc_handler::work_peers_clear () +{ + if (rpc.config.enable_control) + { + 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"); + } +} + rai::rpc_connection::rpc_connection (rai::node & node_a, rai::rpc & rpc_a) : node (node_a.shared ()), rpc (rpc_a), @@ -2889,6 +2959,18 @@ void rai::rpc_handler::process_request () { work_validate (); } + else if (action == "work_peer_add") + { + work_peer_add (); + } + else if (action == "work_peers") + { + work_peers (); + } + else if (action == "work_peers_clear") + { + work_peers_clear (); + } else { error_response (response, "Unknown command"); diff --git a/rai/node/rpc.hpp b/rai/node/rpc.hpp index e300427f..98416433 100644 --- a/rai/node/rpc.hpp +++ b/rai/node/rpc.hpp @@ -163,6 +163,9 @@ public: void work_generate (); void work_cancel (); void work_validate (); + void work_peer_add (); + void work_peers (); + void work_peers_clear (); std::string body; rai::node & node; rai::rpc & rpc; From 308e3d04469607e71c159e2220a3f1e2cb7cf4a0 Mon Sep 17 00:00:00 2001 From: SergiySW Date: Thu, 27 Jul 2017 13:47:15 +0300 Subject: [PATCH 5/5] Tests for RPC account_info, blocks_info, work_peer_add, work_peers, work_peers_clear --- rai/core_test/rpc.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/rai/core_test/rpc.cpp b/rai/core_test/rpc.cpp index 30dae4e7..effcb2f5 100644 --- a/rai/core_test/rpc.cpp +++ b/rai/core_test/rpc.cpp @@ -2223,3 +2223,127 @@ TEST (rpc, delegators_count) std::string count (response.json.get ("count")); ASSERT_EQ ("2", count); } + +TEST (rpc, account_info) +{ + rai::system system (24000, 1); + rai::keypair key; + rai::genesis genesis; + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + system.wallet (0)->insert_adhoc (key.prv); + auto & node1 (*system.nodes [0]); + auto latest (system.nodes [0]->latest (rai::test_genesis_key.pub)); + rai::send_block send (latest, key.pub, 100, rai::test_genesis_key.prv, rai::test_genesis_key.pub, node1.generate_work (latest)); + system.nodes [0]->process (send); + auto time (std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); + rai::rpc rpc (system.service, *system.nodes [0], rai::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "account_info"); + request.put ("account", rai::test_genesis_key.pub.to_account ()); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + std::string frontier (response.json.get ("frontier")); + ASSERT_EQ (send.hash ().to_string (), frontier); + std::string open_block (response.json.get ("open_block")); + ASSERT_EQ (genesis.hash ().to_string (), open_block); + std::string representative_block (response.json.get ("representative_block")); + ASSERT_EQ (genesis.hash ().to_string (), representative_block); + std::string balance (response.json.get ("balance")); + ASSERT_EQ ("100", balance); + std::string modified_timestamp (response.json.get ("modified_timestamp")); + ASSERT_EQ (std::to_string (time), modified_timestamp); + std::string block_count (response.json.get ("block_count")); + ASSERT_EQ ("2", block_count); +} + +TEST (rpc, blocks_info) +{ + rai::system system (24000, 1); + rai::rpc rpc (system.service, *system.nodes [0], rai::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "blocks_info"); + boost::property_tree::ptree entry; + boost::property_tree::ptree peers_l; + entry.put ("", system.nodes [0]->latest (rai::genesis_account).to_string ()); + peers_l.push_back (std::make_pair ("", entry)); + request.add_child ("hashes", peers_l); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + for (auto & blocks : response.json.get_child ("blocks")) + { + std::string hash_text (blocks.first); + ASSERT_EQ (system.nodes [0]->latest (rai::genesis_account).to_string (), hash_text); + std::string account_text (blocks.second.get ("block_account")); + ASSERT_EQ (rai::test_genesis_key.pub.to_account (), account_text); + std::string amount_text (blocks.second.get ("amount")); + ASSERT_EQ (rai::genesis_amount.convert_to (), amount_text); + std::string blocks_text (blocks.second.get ("contents")); + ASSERT_FALSE (blocks_text.empty ()); + } +} + +TEST (rpc, work_peers_all) +{ + rai::system system (24000, 1); + rai::node_init init1; + auto & node1 (*system.nodes [0]); + system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv); + rai::rpc rpc (system.service, node1, rai::rpc_config (true)); + rpc.start (); + boost::property_tree::ptree request; + request.put ("action", "work_peer_add"); + request.put ("address", "::1"); + request.put ("port", "0"); + test_response response (request, rpc, system.service); + while (response.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response.status); + std::string success (response.json.get ("success")); + ASSERT_TRUE (success.empty()); + boost::property_tree::ptree request1; + request1.put ("action", "work_peers"); + test_response response1 (request1, rpc, system.service); + while (response1.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response1.status); + auto & peers_node (response1.json.get_child ("work_peers")); + std::vector peers; + for (auto i (peers_node.begin ()), n (peers_node.end ()); i != n; ++i) + { + peers.push_back (i->second.get ("")); + } + ASSERT_EQ (1, peers.size ()); + ASSERT_EQ ("::1:0", peers[0]); + boost::property_tree::ptree request2; + request2.put ("action", "work_peers_clear"); + test_response response2 (request2, rpc, system.service); + while (response2.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response2.status); + success = response2.json.get ("success"); + ASSERT_TRUE (success.empty()); + test_response response3 (request1, rpc, system.service); + while (response3.status == 0) + { + system.poll (); + } + ASSERT_EQ (200, response3.status); + peers_node = response3.json.get_child ("work_peers"); + ASSERT_EQ (0, peers_node.size ()); +}