Merge branch 'pending_accounts'

This commit is contained in:
clemahieu 2017-02-07 14:04:41 -06:00
commit 34eb45df1f
15 changed files with 451 additions and 161 deletions

View file

@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#include <rai/node/node.hpp>
#include <rai/versioning.hpp>
#include <fstream>
@ -107,16 +108,16 @@ TEST (block_store, add_pending)
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::keypair key1;
rai::block_hash hash1 (0);
rai::pending_key key2 (0, 0);
rai::pending_info pending1;
rai::transaction transaction (store.environment, nullptr, true);
ASSERT_TRUE (store.pending_get (transaction, hash1, pending1));
store.pending_put (transaction, hash1, pending1);
ASSERT_TRUE (store.pending_get (transaction, key2, pending1));
store.pending_put (transaction, key2, pending1);
rai::pending_info pending2;
ASSERT_FALSE (store.pending_get (transaction, hash1, pending2));
ASSERT_FALSE (store.pending_get (transaction, key2, pending2));
ASSERT_EQ (pending1, pending2);
store.pending_del (transaction, hash1);
ASSERT_TRUE (store.pending_get (transaction, hash1, pending2));
store.pending_del (transaction, key2);
ASSERT_TRUE (store.pending_get (transaction, key2, pending2));
}
TEST (block_store, pending_iterator)
@ -126,14 +127,15 @@ TEST (block_store, pending_iterator)
ASSERT_TRUE (!init);
rai::transaction transaction (store.environment, nullptr, true);
ASSERT_EQ (store.pending_end (), store.pending_begin (transaction));
store.pending_put (transaction, 1, {2, 3, 4});
store.pending_put (transaction, rai::pending_key (1, 2), {2, 3});
auto current (store.pending_begin (transaction));
ASSERT_NE (store.pending_end (), current);
ASSERT_EQ (rai::account (1), current->first);
rai::pending_key key1 (current->first);
ASSERT_EQ (rai::account (1), key1.account);
ASSERT_EQ (rai::block_hash (2), key1.hash);
rai::pending_info pending (current->second);
ASSERT_EQ (rai::account (2), pending.source);
ASSERT_EQ (rai::amount (3), pending.amount);
ASSERT_EQ (rai::account (4), pending.destination);
}
TEST (block_store, genesis)
@ -410,11 +412,11 @@ TEST (block_store, pending_exists)
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::block_hash two (2);
rai::pending_key two (2, 0);
rai::pending_info pending;
rai::transaction transaction (store.environment, nullptr, true);
store.pending_put (transaction, two, pending);
rai::block_hash one (1);
rai::pending_key one (1, 0);
ASSERT_FALSE (store.pending_exists (transaction, one));
}
@ -592,7 +594,6 @@ TEST (block_store, sequence_increment)
ASSERT_EQ (31, seq8);
}
TEST (block_store, upgrade_v2_v3)
{
rai::keypair key1;
@ -629,10 +630,40 @@ TEST (block_store, upgrade_v2_v3)
rai::ledger ledger (store);
rai::transaction transaction (store.environment, nullptr, true);
ASSERT_TRUE (!init);
ASSERT_EQ (3, store.version_get (transaction));
ASSERT_LT (2, store.version_get (transaction));
ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, key1.pub));
ASSERT_EQ (0, ledger.weight (transaction, key2.pub));
rai::account_info info;
ASSERT_FALSE (store.account_get (transaction, rai::test_genesis_key.pub, info));
ASSERT_EQ (change_hash, info.rep_block);
}
TEST (block_store, upgrade_v3_v4)
{
rai::keypair key1;
rai::keypair key2;
rai::keypair key3;
auto path (rai::unique_path ());
{
bool init (false);
rai::block_store store (init, path);
ASSERT_FALSE (init);
rai::transaction transaction (store.environment, nullptr, true);
store.version_put (transaction, 3);
rai::pending_info_v3 info (key1.pub, 100, key2.pub);
auto status (mdb_put (transaction, store.pending, key3.pub.val (), info.val (), 0));
ASSERT_EQ (0, status);
}
bool init (false);
rai::block_store store (init, path);
rai::ledger ledger (store);
rai::transaction transaction (store.environment, nullptr, true);
ASSERT_FALSE (init);
ASSERT_LT (3, store.version_get (transaction));
rai::pending_key key (key2.pub, key3.pub);
rai::pending_info info;
auto error (store.pending_get (transaction, key, info));
ASSERT_FALSE (error);
ASSERT_EQ (key1.pub, info.source);
ASSERT_EQ (rai::amount (100), info.amount);
}

View file

@ -109,6 +109,7 @@ TEST (ledger, process_send)
ASSERT_EQ (rai::test_genesis_key.pub, return1.account);
ASSERT_EQ (rai::genesis_amount - 50, return1.amount.number ());
ASSERT_EQ (50, ledger.account_balance (transaction, rai::test_genesis_key.pub));
ASSERT_EQ (rai::genesis_amount - 50, ledger.account_pending (transaction, key2.pub));
rai::account_info info2;
ASSERT_FALSE (store.account_get (transaction, rai::test_genesis_key.pub, info2));
auto latest6 (store.block_get (transaction, info2.head));
@ -127,6 +128,7 @@ TEST (ledger, process_send)
ASSERT_EQ (rai::genesis_amount - 50, return2.amount.number ());
ASSERT_EQ (key2.pub, store.frontier_get (transaction, hash2));
ASSERT_EQ (rai::genesis_amount - 50, ledger.account_balance (transaction, key2.pub));
ASSERT_EQ (0, ledger.account_pending (transaction, key2.pub));
ASSERT_EQ (50, ledger.weight (transaction, rai::test_genesis_key.pub));
ASSERT_EQ (rai::genesis_amount - 50, ledger.weight (transaction, key2.pub));
rai::account_info info3;
@ -148,11 +150,11 @@ TEST (ledger, process_send)
rai::account_info info5;
ASSERT_TRUE (ledger.store.account_get (transaction, key2.pub, info5));
rai::pending_info pending1;
ASSERT_FALSE (ledger.store.pending_get (transaction, hash1, pending1));
ASSERT_FALSE (ledger.store.pending_get (transaction, rai::pending_key (key2.pub, hash1), pending1));
ASSERT_EQ (rai::test_genesis_key.pub, pending1.source);
ASSERT_EQ (key2.pub, pending1.destination);
ASSERT_EQ (rai::genesis_amount - 50, pending1.amount.number ());
ASSERT_EQ (0, ledger.account_balance (transaction, key2.pub));
ASSERT_EQ (rai::genesis_amount - 50, ledger.account_pending (transaction, key2.pub));
ASSERT_EQ (50, ledger.account_balance (transaction, rai::test_genesis_key.pub));
ASSERT_EQ (50, ledger.weight (transaction, rai::test_genesis_key.pub));
ASSERT_EQ (0, ledger.weight (transaction, key2.pub));
@ -167,8 +169,9 @@ TEST (ledger, process_send)
ASSERT_FALSE (ledger.store.account_get (transaction, rai::test_genesis_key.pub, info7));
ASSERT_EQ (info1.head, info7.head);
rai::pending_info pending2;
ASSERT_TRUE (ledger.store.pending_get (transaction, hash1, pending2));
ASSERT_TRUE (ledger.store.pending_get (transaction, rai::pending_key (key2.pub, hash1), pending2));
ASSERT_EQ (rai::genesis_amount, ledger.account_balance (transaction, rai::test_genesis_key.pub));
ASSERT_EQ (0, ledger.account_pending (transaction, key2.pub));
}
TEST (ledger, process_receive)
@ -209,6 +212,7 @@ TEST (ledger, process_receive)
ASSERT_EQ (25, return2.amount.number ());
ASSERT_EQ (hash4, ledger.latest (transaction, key2.pub));
ASSERT_EQ (25, ledger.account_balance (transaction, rai::test_genesis_key.pub));
ASSERT_EQ (0, ledger.account_pending (transaction, key2.pub));
ASSERT_EQ (rai::genesis_amount - 25, ledger.account_balance (transaction, key2.pub));
ASSERT_EQ (rai::genesis_amount - 25, ledger.weight (transaction, key3.pub));
ledger.rollback (transaction, hash4);
@ -216,11 +220,12 @@ TEST (ledger, process_receive)
ASSERT_EQ (key2.pub, store.frontier_get (transaction, hash2));
ASSERT_TRUE (store.frontier_get (transaction, hash4).is_zero ());
ASSERT_EQ (25, ledger.account_balance (transaction, rai::test_genesis_key.pub));
ASSERT_EQ (25, ledger.account_pending (transaction, key2.pub));
ASSERT_EQ (rai::genesis_amount - 50, ledger.account_balance (transaction, key2.pub));
ASSERT_EQ (rai::genesis_amount - 50, ledger.weight (transaction, key3.pub));
ASSERT_EQ (hash2, ledger.latest (transaction, key2.pub));
rai::pending_info pending1;
ASSERT_FALSE (ledger.store.pending_get (transaction, hash3, pending1));
ASSERT_FALSE (ledger.store.pending_get (transaction, rai::pending_key (key2.pub, hash3), pending1));
ASSERT_EQ (rai::test_genesis_key.pub, pending1.source);
ASSERT_EQ (25, pending1.amount.number ());
}
@ -259,7 +264,7 @@ TEST (ledger, rollback_receiver)
rai::account_info info2;
ASSERT_TRUE (ledger.store.account_get (transaction, key2.pub, info2));
rai::pending_info pending1;
ASSERT_TRUE (ledger.store.pending_get (transaction, info2.head, pending1));
ASSERT_TRUE (ledger.store.pending_get (transaction, rai::pending_key (key2.pub, info2.head), pending1));
}
TEST (ledger, rollback_representation)
@ -1117,7 +1122,7 @@ TEST (ledger, fail_open_account_mismatch)
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, block1).code);
rai::keypair badkey;
rai::open_block block2 (block1.hash (), 1, badkey.pub, badkey.prv, badkey.pub, 0);
ASSERT_EQ (rai::process_result::account_mismatch, ledger.process (transaction, block2).code);
ASSERT_NE (rai::process_result::progress, ledger.process (transaction, block2).code);
}
TEST (ledger, fail_receive_old)

View file

@ -711,7 +711,7 @@ TEST (node, fork_keep)
auto & node1 (*system.nodes [0]);
auto & node2 (*system.nodes [1]);
ASSERT_EQ (1, node1.peers.size ());
system.wallet (0)->insert_adhoc ( rai::test_genesis_key.prv);
system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv);
rai::keypair key1;
rai::genesis genesis;
std::unique_ptr <rai::send_block> send1 (new rai::send_block (genesis.hash (), key1.pub, rai::genesis_amount - 100, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
@ -742,7 +742,7 @@ TEST (node, fork_keep)
{
system.poll ();
++iterations;
ASSERT_LT (iterations, 200);
ASSERT_LT (iterations, 2000);
}
rai::transaction transaction (system.nodes [0]->store.environment, nullptr, false);
auto winner (node1.ledger.winner (transaction, votes1->votes));

View file

@ -79,6 +79,8 @@ TEST (rpc, account_balance)
ASSERT_EQ (200, response.status);
std::string balance_text (response.json.get <std::string> ("balance"));
ASSERT_EQ ("340282366920938463463374607431768211455", balance_text);
std::string pending_text (response.json.get <std::string> ("pending"));
ASSERT_EQ ("0", pending_text);
}
TEST (rpc, account_create)
@ -1198,8 +1200,32 @@ TEST (rpc, peers)
system.poll ();
}
ASSERT_EQ (200, response.status);
auto & frontiers_node (response.json.get_child ("peers"));
ASSERT_EQ (1, frontiers_node.size ());
auto & peers_node (response.json.get_child ("peers"));
ASSERT_EQ (1, peers_node.size ());
}
TEST (rpc, pending)
{
rai::system system (24000, 1);
rai::keypair key1;
system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv);
auto block1 (system.wallet (0)->send_action (rai::test_genesis_key.pub, key1.pub, 100));
rai::rpc rpc (system.service, *system.nodes [0], rai::rpc_config (true));
rpc.start ();
boost::property_tree::ptree request;
request.put ("action", "pending");
request.put ("account", key1.pub.to_account ());
request.put ("count", "100");
test_response response (request, rpc, system.service);
while (response.status == 0)
{
system.poll ();
}
ASSERT_EQ (200, response.status);
auto & blocks_node (response.json.get_child ("blocks"));
ASSERT_EQ (1, blocks_node.size ());
rai::block_hash hash1 (blocks_node.begin ()->second.get <std::string> (""));
ASSERT_EQ (block1->hash (), hash1);
}
TEST (rpc_config, serialization)
@ -1273,7 +1299,7 @@ TEST (rpc, version)
ASSERT_EQ (200, response1.status);
ASSERT_EQ ("1", response1.json.get <std::string> ("rpc_version"));
ASSERT_EQ (200, response1.status);
ASSERT_EQ ("2", response1.json.get <std::string> ("store_version"));
ASSERT_EQ ("4", response1.json.get <std::string> ("store_version"));
ASSERT_EQ (boost::str (boost::format ("RaiBlocks %1%.%2%.%3%") % RAIBLOCKS_VERSION_MAJOR % RAIBLOCKS_VERSION_MINOR % RAIBLOCKS_VERSION_PATCH), response1.json.get <std::string> ("node_vendor"));
auto & headers (response1.headers);
auto access_control (std::find_if (headers.begin (), headers.end (), [] (decltype (*headers.begin ()) & header_a) { return boost::iequals (header_a.first, "Access-Control-Allow-Origin"); }));

View file

@ -1360,6 +1360,15 @@ rai::uint128_t rai::node::balance (rai::account const & account_a)
return ledger.account_balance (transaction, account_a);
}
std::pair <rai::uint128_t, rai::uint128_t> rai::node::balance_pending (rai::account const & account_a)
{
std::pair <rai::uint128_t, rai::uint128_t> result;
rai::transaction transaction (store.environment, nullptr, false);
result.first = ledger.account_balance (transaction, account_a);
result.second = ledger.account_pending (transaction, account_a);
return result;
}
rai::uint128_t rai::node::weight (rai::account const & account_a)
{
rai::transaction transaction (store.environment, nullptr, false);
@ -1640,7 +1649,7 @@ public:
rai::pending_info pending;
rai::transaction transaction (node.store.environment, nullptr, false);
representative = wallet->store.representative (transaction);
auto error (node.store.pending_get (transaction, block_a.hash (), pending));
auto error (node.store.pending_get (transaction, rai::pending_key (block_a.hashables.destination, block_a.hash ()), pending));
if (!error)
{
auto block_l (std::shared_ptr <rai::send_block> (static_cast <rai::send_block *> (block_a.clone ().release ())));

View file

@ -354,6 +354,7 @@ public:
void keepalive_preconfigured (std::vector <std::string> const &);
rai::block_hash latest (rai::account const &);
rai::uint128_t balance (rai::account const &);
std::pair <rai::uint128_t, rai::uint128_t> balance_pending (rai::account const &);
rai::uint128_t weight (rai::account const &);
rai::account representative (rai::account const &);
void ongoing_keepalive ();

View file

@ -141,9 +141,10 @@ void rai::rpc_handler::account_balance ()
auto error (account.decode_account (account_text));
if (!error)
{
auto balance (rpc.node.balance (account));
auto balance (rpc.node.balance_pending (account));
boost::property_tree::ptree response_l;
response_l.put ("balance", balance.convert_to <std::string> ());
response_l.put ("balance", balance.first.convert_to <std::string> ());
response_l.put ("pending", balance.second.convert_to <std::string> ());
rpc.send_response (response, response_l);
}
else
@ -846,6 +847,39 @@ void rai::rpc_handler::peers ()
rpc.send_response (response, response_l);
}
void rai::rpc_handler::pending ()
{
std::string account_text (request.get <std::string> ("account"));
rai::account account;
if (!account.decode_account(account_text))
{
std::string count_text (request.get <std::string> ("count"));
uint64_t count;
if (!rpc.decode_unsigned (count_text, count))
{
boost::property_tree::ptree response_l;
boost::property_tree::ptree peers_l;
{
rai::transaction transaction (rpc.node.store.environment, nullptr, false);
rai::account end (account.number () + 1);
for (auto i (rpc.node.store.pending_begin (transaction, rai::pending_key (account, 0))), n (rpc.node.store.pending_begin (transaction, rai::pending_key (end, 0))); i != n && peers_l.size ()< count; ++i)
{
rai::pending_key key (i->first);
boost::property_tree::ptree entry;
entry.put ("", key.hash.to_string ());
peers_l.push_back (std::make_pair ("", entry));
}
}
response_l.add_child ("blocks", peers_l);
rpc.send_response (response, response_l);
}
}
else
{
rpc.error_response (response, "Bad account number");
}
}
void rai::rpc_handler::payment_begin ()
{
std::string id_text (request.get <std::string> ("wallet"));
@ -1752,6 +1786,10 @@ void rai::rpc_handler::process_request ()
{
peers ();
}
else if (action == "pending")
{
pending ();
}
else if (action == "process")
{
process ();

View file

@ -109,6 +109,7 @@ public:
void payment_end ();
void payment_wait ();
void peers ();
void pending ();
void process ();
void rai_to_raw ();
void rai_from_raw ();

View file

@ -164,7 +164,7 @@ void rai::system::generate_receive (rai::node & node_a)
rai::transaction transaction (node_a.store.environment, nullptr, false);
rai::uint256_union random_block;
random_pool.GenerateBlock (random_block.bytes.data (), sizeof (random_block.bytes));
auto i (node_a.store.pending_begin (transaction, random_block));
auto i (node_a.store.pending_begin (transaction, rai::pending_key (random_block, 0)));
if (i != node_a.store.pending_end ())
{
rai::block_hash send_hash (i->first);

View file

@ -934,7 +934,7 @@ std::unique_ptr <rai::block> rai::wallet::receive_action (rai::send_block const
if (node.config.receive_minimum.number () <= amount_a.number ())
{
rai::transaction transaction (node.ledger.store.environment, nullptr, false);
if (node.ledger.store.pending_exists (transaction, hash))
if (node.ledger.store.pending_exists (transaction, rai::pending_key (send_a.hashables.destination, hash)))
{
rai::raw_key prv;
if (!store.fetch (transaction, send_a.hashables.destination, prv))
@ -1195,8 +1195,9 @@ public:
std::unordered_set <rai::account> already_searched;
for (auto i (wallet->node.store.pending_begin (transaction)), n (wallet->node.store.pending_end ()); i != n; ++i)
{
rai::pending_key key (i->first);
rai::pending_info pending (i->second);
auto existing (keys.find (pending.destination));
auto existing (keys.find (key.account));
if (existing != keys.end ())
{
rai::account_info info;
@ -1231,14 +1232,16 @@ public:
auto representative (wallet->store.representative (transaction));
for (auto i (wallet->node.store.pending_begin (transaction)), n (wallet->node.store.pending_end ()); i != n; ++i)
{
rai::pending_key key (i->first);
rai::pending_info pending (i->second);
if (pending.source == account_a)
{
if (wallet->store.exists (transaction, pending.destination))
if (wallet->store.exists (transaction, key.account))
{
if (wallet->store.valid_password (transaction))
{
auto block_l (wallet->node.store.block_get (transaction, i->first));
rai::pending_key key (i->first);
auto block_l (wallet->node.store.block_get (transaction, key.hash));
assert (dynamic_cast <rai::send_block *> (block_l.get ()) != nullptr);
std::shared_ptr <rai::send_block> block (static_cast <rai::send_block *> (block_l.release ()));
auto wallet_l (wallet);
@ -1254,7 +1257,7 @@ public:
}
else
{
BOOST_LOG (wallet->node.log) << boost::str (boost::format ("Unable to fetch key for: %1%, stopping pending search") % pending.destination.to_account ());
BOOST_LOG (wallet->node.log) << boost::str (boost::format ("Unable to fetch key for: %1%, stopping pending search") % key.account.to_account ());
}
}
}

View file

@ -1579,41 +1579,60 @@ void rai_qt::block_creation::create_receive ()
if (!error)
{
rai::transaction transaction (wallet.node.store.environment, nullptr, false);
rai::pending_info pending;
if (!wallet.node.store.pending_get (transaction, source_l, pending))
{
rai::account_info info;
auto error (wallet.node.store.account_get (transaction, pending.destination, info));
if (!error)
{
rai::raw_key key;
auto error (wallet.wallet_m->store.fetch (transaction, pending.destination, key));
if (!error)
{
rai::receive_block receive (info.head, source_l, key, pending.destination, wallet.wallet_m->work_fetch (transaction, pending.destination, info.head));
std::string block_l;
receive.serialize_json (block_l);
block->setPlainText (QString (block_l.c_str ()));
show_label_ok (*status);
status->setText ("Created block");
}
else
{
auto block_l (wallet.node.store.block_get (transaction, source_l));
if (block_l != nullptr)
{
auto send_block (dynamic_cast <rai::send_block *> (block_l.get ()));
if (send_block != nullptr)
{
rai::pending_key pending_key (send_block->hashables.destination, source_l);
rai::pending_info pending;
if (!wallet.node.store.pending_get (transaction, pending_key, pending))
{
rai::account_info info;
auto error (wallet.node.store.account_get (transaction, pending_key.account, info));
if (!error)
{
rai::raw_key key;
auto error (wallet.wallet_m->store.fetch (transaction, pending_key.account, key));
if (!error)
{
rai::receive_block receive (info.head, source_l, key, pending_key.account, wallet.wallet_m->work_fetch (transaction, pending_key.account, info.head));
std::string block_l;
receive.serialize_json (block_l);
block->setPlainText (QString (block_l.c_str ()));
show_label_ok (*status);
status->setText ("Created block");
}
else
{
show_label_error (*status);
status->setText ("Account is not in wallet");
}
}
else
{
show_label_error (*status);
status->setText ("Account not yet open");
}
}
else
{
show_label_error (*status);
status->setText ("Account is not in wallet");
}
}
else
{
status->setText ("Source block is not pending to receive");
}
}
else
{
show_label_error (*status);
status->setText ("Account not yet open");
}
}
else
{
status->setText("Source is not a send block");
}
}
else
{
show_label_error (*status);
status->setText ("Source block is not pending to receive");
}
status->setText("Source block not found");
}
}
else
{
@ -1684,41 +1703,60 @@ void rai_qt::block_creation::create_open ()
if (!error)
{
rai::transaction transaction (wallet.node.store.environment, nullptr, false);
rai::pending_info pending;
if (!wallet.node.store.pending_get (transaction, source_l, pending))
{
rai::account_info info;
auto error (wallet.node.store.account_get (transaction, pending.destination, info));
if (error)
{
rai::raw_key key;
auto error (wallet.wallet_m->store.fetch (transaction, pending.destination, key));
if (!error)
{
rai::open_block open (source_l, representative_l, pending.destination, key, pending.destination, wallet.wallet_m->work_fetch (transaction, pending.destination, pending.destination));
std::string block_l;
open.serialize_json (block_l);
block->setPlainText (QString (block_l.c_str ()));
show_label_ok (*status);
status->setText ("Created block");
}
else
{
auto block_l (wallet.node.store.block_get (transaction, source_l));
if (block_l != nullptr)
{
auto send_block (dynamic_cast <rai::send_block *> (block_l.get ()));
if (send_block != nullptr)
{
rai::pending_key pending_key (send_block->hashables.destination, source_l);
rai::pending_info pending;
if (!wallet.node.store.pending_get (transaction, pending_key, pending))
{
rai::account_info info;
auto error (wallet.node.store.account_get (transaction, pending_key.account, info));
if (error)
{
rai::raw_key key;
auto error (wallet.wallet_m->store.fetch (transaction, pending_key.account, key));
if (!error)
{
rai::open_block open (source_l, representative_l, pending_key.account, key, pending_key.account, wallet.wallet_m->work_fetch (transaction, pending_key.account, pending_key.account));
std::string block_l;
open.serialize_json (block_l);
block->setPlainText (QString (block_l.c_str ()));
show_label_ok (*status);
status->setText ("Created block");
}
else
{
show_label_error (*status);
status->setText ("Account is not in wallet");
}
}
else
{
show_label_error (*status);
status->setText ("Account already open");
}
}
else
{
show_label_error (*status);
status->setText ("Account is not in wallet");
}
}
else
{
status->setText ("Source block is not pending to receive");
}
}
else
{
show_label_error (*status);
status->setText ("Account already open");
}
}
else
{
status->setText("Source is not a send block");
}
}
else
{
show_label_error (*status);
status->setText ("Source block is not pending to receive");
}
status->setText("Source block not found");
}
}
else
{

View file

@ -9,6 +9,8 @@
#include <ed25519-donna/ed25519.h>
#include <queue>
// Genesis keys for network variants
namespace
{
@ -1562,12 +1564,12 @@ void rai::block_store::do_upgrades (MDB_txn * transaction_a)
{
case 1:
upgrade_v1_to_v2 (transaction_a);
break;
case 2:
upgrade_v2_to_v3 (transaction_a);
break;
case 3:
break;
upgrade_v3_to_v4 (transaction_a);
case 4:
break;
default:
assert (false);
}
@ -1666,6 +1668,24 @@ void rai::block_store::upgrade_v2_to_v3 (MDB_txn * transaction_a)
}
}
void rai::block_store::upgrade_v3_to_v4 (MDB_txn * transaction_a)
{
version_put (transaction_a, 4);
std::queue <std::pair <rai::pending_key, rai::pending_info>> items;
for (auto i (pending_begin (transaction_a)), n (pending_end ()); i != n; ++i)
{
rai::block_hash hash (i->first);
rai::pending_info_v3 info (i->second);
items.push (std::make_pair (rai::pending_key (info.destination, hash), rai::pending_info (info.source, info.amount)));
}
mdb_drop (transaction_a, pending, 0);
while (!items.empty ())
{
pending_put (transaction_a, items.front ().first, items.front ().second);
items.pop ();
}
}
void rai::block_store::clear (MDB_dbi db_a)
{
rai::transaction transaction (environment, nullptr, true);
@ -1981,35 +2001,34 @@ void rai::block_store::account_put (MDB_txn * transaction_a, rai::account const
assert (status == 0);
}
void rai::block_store::pending_put (MDB_txn * transaction_a, rai::block_hash const & hash_a, rai::pending_info const & pending_a)
void rai::block_store::pending_put (MDB_txn * transaction_a, rai::pending_key const & key_a, rai::pending_info const & pending_a)
{
std::vector <uint8_t> vector;
{
rai::vectorstream stream (vector);
rai::write (stream, pending_a.source);
rai::write (stream, pending_a.amount);
rai::write (stream, pending_a.destination);
}
auto status (mdb_put (transaction_a, pending, hash_a.val (), pending_a.val (), 0));
auto status (mdb_put (transaction_a, pending, key_a.val (), pending_a.val (), 0));
assert (status == 0);
}
void rai::block_store::pending_del (MDB_txn * transaction_a, rai::block_hash const & hash_a)
void rai::block_store::pending_del (MDB_txn * transaction_a, rai::pending_key const & key_a)
{
auto status (mdb_del (transaction_a, pending, hash_a.val (), nullptr));
auto status (mdb_del (transaction_a, pending, key_a.val (), nullptr));
assert (status == 0);
}
bool rai::block_store::pending_exists (MDB_txn * transaction_a, rai::block_hash const & hash_a)
bool rai::block_store::pending_exists (MDB_txn * transaction_a, rai::pending_key const & key_a)
{
auto iterator (pending_begin (transaction_a, hash_a));
return iterator != rai::store_iterator (nullptr) && rai::block_hash (iterator->first) == hash_a;
auto iterator (pending_begin (transaction_a, key_a));
return iterator != rai::store_iterator (nullptr) && rai::pending_key (iterator->first) == key_a;
}
bool rai::block_store::pending_get (MDB_txn * transaction_a, rai::block_hash const & hash_a, rai::pending_info & pending_a)
bool rai::block_store::pending_get (MDB_txn * transaction_a, rai::pending_key const & key_a, rai::pending_info & pending_a)
{
MDB_val value;
auto status (mdb_get (transaction_a, pending, hash_a.val (), &value));
auto status (mdb_get (transaction_a, pending, key_a.val (), &value));
assert (status == 0 || status == MDB_NOTFOUND);
bool result;
if (status == MDB_NOTFOUND)
@ -2019,21 +2038,19 @@ bool rai::block_store::pending_get (MDB_txn * transaction_a, rai::block_hash con
else
{
result = false;
assert (value.mv_size == sizeof (pending_a.source.bytes) + sizeof (pending_a.amount.bytes) + sizeof (pending_a.destination.bytes));
assert (value.mv_size == sizeof (pending_a.source.bytes) + sizeof (pending_a.amount.bytes));
rai::bufferstream stream (reinterpret_cast <uint8_t const *> (value.mv_data), value.mv_size);
auto error1 (rai::read (stream, pending_a.source));
assert (!error1);
auto error2 (rai::read (stream, pending_a.amount));
assert (!error2);
auto error3 (rai::read (stream, pending_a.destination));
assert (!error3);
}
return result;
}
rai::store_iterator rai::block_store::pending_begin (MDB_txn * transaction_a, rai::block_hash const & hash_a)
rai::store_iterator rai::block_store::pending_begin (MDB_txn * transaction_a, rai::pending_key const & key_a)
{
rai::store_iterator result (transaction_a, pending, hash_a.val ());
rai::store_iterator result (transaction_a, pending, key_a.val ());
return result;
}
@ -2051,22 +2068,20 @@ rai::store_iterator rai::block_store::pending_end ()
rai::pending_info::pending_info () :
source (0),
amount (0),
destination (0)
amount (0)
{
}
rai::pending_info::pending_info (MDB_val const & val_a)
{
assert(val_a.mv_size == sizeof (*this));
static_assert (sizeof (source) + sizeof (amount) + sizeof (destination) == sizeof (*this), "Packed class");
static_assert (sizeof (source) + sizeof (amount) == sizeof (*this), "Packed class");
std::copy (reinterpret_cast <uint8_t const *> (val_a.mv_data), reinterpret_cast <uint8_t const *> (val_a.mv_data) + sizeof (*this), reinterpret_cast <uint8_t *> (this));
}
rai::pending_info::pending_info (rai::account const & source_a, rai::amount const & amount_a, rai::account const & destination_a) :
rai::pending_info::pending_info (rai::account const & source_a, rai::amount const & amount_a) :
source (source_a),
amount (amount_a),
destination (destination_a)
amount (amount_a)
{
}
@ -2074,7 +2089,6 @@ void rai::pending_info::serialize (rai::stream & stream_a) const
{
rai::write (stream_a, source.bytes);
rai::write (stream_a, amount.bytes);
rai::write (stream_a, destination.bytes);
}
bool rai::pending_info::deserialize (rai::stream & stream_a)
@ -2083,17 +2097,13 @@ bool rai::pending_info::deserialize (rai::stream & stream_a)
if (!result)
{
result = rai::read (stream_a, amount.bytes);
if (!result)
{
result = rai::read (stream_a, destination.bytes);
}
}
return result;
}
bool rai::pending_info::operator == (rai::pending_info const & other_a) const
{
return source == other_a.source && amount == other_a.amount && destination == other_a.destination;
return source == other_a.source && amount == other_a.amount;
}
rai::mdb_val rai::pending_info::val () const
@ -2101,6 +2111,45 @@ rai::mdb_val rai::pending_info::val () const
return rai::mdb_val (sizeof (*this), const_cast <rai::pending_info *> (this));
}
rai::pending_key::pending_key (rai::account const & account_a, rai::block_hash const & hash_a) :
account (account_a),
hash (hash_a)
{
}
rai::pending_key::pending_key (MDB_val const & val_a)
{
assert(val_a.mv_size == sizeof (*this));
static_assert (sizeof (account) + sizeof (hash) == sizeof (*this), "Packed class");
std::copy (reinterpret_cast <uint8_t const *> (val_a.mv_data), reinterpret_cast <uint8_t const *> (val_a.mv_data) + sizeof (*this), reinterpret_cast <uint8_t *> (this));
}
void rai::pending_key::serialize (rai::stream & stream_a) const
{
rai::write (stream_a, account.bytes);
rai::write (stream_a, hash.bytes);
}
bool rai::pending_key::deserialize (rai::stream & stream_a)
{
auto result (rai::read (stream_a, account.bytes));
if (!result)
{
result = rai::read (stream_a, hash.bytes);
}
return result;
}
bool rai::pending_key::operator == (rai::pending_key const & other_a) const
{
return account == other_a.account && hash == other_a.hash;
}
rai::mdb_val rai::pending_key::val () const
{
return rai::mdb_val (sizeof (*this), const_cast <rai::pending_key *> (this));
}
rai::uint128_t rai::block_store::representation_get (MDB_txn * transaction_a, rai::account const & account_a)
{
MDB_val value;
@ -2529,7 +2578,8 @@ public:
{
auto hash (block_a.hash ());
rai::pending_info pending;
while (ledger.store.pending_get (transaction, hash, pending) && !error)
rai::pending_key key (block_a.hashables.destination, hash);
while (ledger.store.pending_get (transaction, key, pending) && !error)
{
error = ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.destination));
}
@ -2538,7 +2588,7 @@ public:
rai::account_info info;
auto error (ledger.store.account_get (transaction, pending.source, info));
assert (!error);
ledger.store.pending_del (transaction, hash);
ledger.store.pending_del (transaction, key);
ledger.store.representation_add (transaction, ledger.representative (transaction, hash), pending.amount.number ());
ledger.change_latest (transaction, pending.source, block_a.hashables.previous, info.rep_block, ledger.balance (transaction, block_a.hashables.previous));
ledger.store.block_del (transaction, hash);
@ -2563,7 +2613,7 @@ public:
ledger.store.representation_add (transaction, ledger.representative (transaction, hash), 0 - amount);
ledger.change_latest (transaction, destination_account, block_a.hashables.previous, representative, ledger.balance (transaction, block_a.hashables.previous));
ledger.store.block_del (transaction, hash);
ledger.store.pending_put (transaction, block_a.hashables.source, {ledger.account (transaction, block_a.hashables.source), amount, destination_account});
ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), {ledger.account (transaction, block_a.hashables.source), amount});
ledger.store.frontier_del (transaction, hash);
ledger.store.frontier_put (transaction, block_a.hashables.previous, destination_account);
ledger.store.block_successor_clear (transaction, block_a.hashables.previous);
@ -2584,7 +2634,7 @@ public:
ledger.store.representation_add (transaction, ledger.representative (transaction, hash), 0 - amount);
ledger.change_latest (transaction, destination_account, 0, representative, 0);
ledger.store.block_del (transaction, hash);
ledger.store.pending_put (transaction, block_a.hashables.source, {ledger.account (transaction, block_a.hashables.source), amount, destination_account});
ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), {ledger.account (transaction, block_a.hashables.source), amount});
ledger.store.frontier_del (transaction, hash);
}
else
@ -2675,6 +2725,18 @@ rai::uint128_t rai::ledger::account_balance (MDB_txn * transaction_a, rai::accou
return result;
}
rai::uint128_t rai::ledger::account_pending (MDB_txn * transaction_a, rai::account const & account_a)
{
rai::uint128_t result (0);
rai::account end (account_a.number () + 1);
for (auto i (store.pending_begin (transaction_a, rai::pending_key (account_a, 0))), n (store.pending_begin (transaction_a, rai::pending_key (end, 0))); i != n; ++i)
{
rai::pending_info info (i->second);
result += info.amount.number ();
}
return result;
}
rai::process_return rai::ledger::process (MDB_txn * transaction_a, rai::block const & block_a)
{
ledger_processor processor (*this, transaction_a);
@ -2977,7 +3039,7 @@ void ledger_processor::send_block (rai::send_block const & block_a)
ledger.store.representation_add (transaction, info.rep_block, 0 - amount);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, account, hash, info.rep_block, block_a.hashables.balance);
ledger.store.pending_put (transaction, hash, {account, amount, block_a.hashables.destination});
ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.destination, hash), {account, amount});
ledger.store.frontier_del (transaction, block_a.hashables.previous);
ledger.store.frontier_put (transaction, hash, account);
result.account = account;
@ -3011,22 +3073,22 @@ void ledger_processor::receive_block (rai::receive_block const & block_a)
result.code = info.head == block_a.hashables.previous ? rai::process_result::progress : rai::process_result::gap_previous; // Block doesn't immediately follow latest block (Harmless)
if (result.code == rai::process_result::progress)
{
rai::pending_key key (account, block_a.hashables.source);
rai::pending_info pending;
result.code = ledger.store.pending_get (transaction, block_a.hashables.source, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed)
result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed)
if (result.code == rai::process_result::progress)
{
assert (ledger.store.frontier_get (transaction, block_a.hashables.previous) == pending.destination);
auto new_balance (info.balance.number () + pending.amount.number ());
rai::account_info source_info;
auto error (ledger.store.account_get (transaction, pending.source, source_info));
assert (!error);
ledger.store.pending_del (transaction, block_a.hashables.source);
ledger.store.pending_del (transaction, key);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, pending.destination, hash, info.rep_block, new_balance);
ledger.change_latest (transaction, account, hash, info.rep_block, new_balance);
ledger.store.representation_add (transaction, info.rep_block, pending.amount.number ());
ledger.store.frontier_del (transaction, block_a.hashables.previous);
ledger.store.frontier_put (transaction, hash, pending.destination);
result.account = pending.destination;
ledger.store.frontier_put (transaction, hash, account);
result.account = account;
result.amount = pending.amount;
}
}
@ -3058,24 +3120,21 @@ void ledger_processor::open_block (rai::open_block const & block_a)
result.code = ledger.store.account_get (transaction, block_a.hashables.account, info) ? rai::process_result::progress : rai::process_result::fork; // Has this account already been opened? (Malicious)
if (result.code == rai::process_result::progress)
{
rai::pending_key key (block_a.hashables.account, block_a.hashables.source);
rai::pending_info pending;
result.code = ledger.store.pending_get (transaction, block_a.hashables.source, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed)
result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed)
if (result.code == rai::process_result::progress)
{
result.code = pending.destination == block_a.hashables.account ? rai::process_result::progress : rai::process_result::account_mismatch; // Does the account listed in the open block match the one named in the send block? (Malformed)
if (result.code == rai::process_result::progress)
{
rai::account_info source_info;
auto error (ledger.store.account_get (transaction, pending.source, source_info));
assert (!error);
ledger.store.pending_del (transaction, block_a.hashables.source);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, pending.destination, hash, hash, pending.amount.number ());
ledger.store.representation_add (transaction, hash, pending.amount.number ());
ledger.store.frontier_put (transaction, hash, pending.destination);
result.account = pending.destination;
result.amount = pending.amount;
}
rai::account_info source_info;
auto error (ledger.store.account_get (transaction, pending.source, source_info));
assert (!error);
ledger.store.pending_del (transaction, key);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, block_a.hashables.account, hash, hash, pending.amount.number ());
ledger.store.representation_add (transaction, hash, pending.amount.number ());
ledger.store.frontier_put (transaction, hash, block_a.hashables.account);
result.account = block_a.hashables.account;
result.amount = pending.amount;
}
}
}

View file

@ -286,14 +286,25 @@ class pending_info
public:
pending_info ();
pending_info (MDB_val const &);
pending_info (rai::account const &, rai::amount const &, rai::account const &);
pending_info (rai::account const &, rai::amount const &);
void serialize (rai::stream &) const;
bool deserialize (rai::stream &);
bool operator == (rai::pending_info const &) const;
rai::mdb_val val () const;
rai::account source;
rai::amount amount;
rai::account destination;
};
class pending_key
{
public:
pending_key (rai::account const &, rai::block_hash const &);
pending_key (MDB_val const &);
void serialize (rai::stream &) const;
bool deserialize (rai::stream &);
bool operator == (rai::pending_key const &) const;
rai::mdb_val val () const;
rai::account account;
rai::block_hash hash;
};
class block_store
{
@ -325,11 +336,11 @@ public:
rai::store_iterator latest_begin (MDB_txn *);
rai::store_iterator latest_end ();
void pending_put (MDB_txn *, rai::block_hash const &, rai::pending_info const &);
void pending_del (MDB_txn *, rai::block_hash const &);
bool pending_get (MDB_txn *, rai::block_hash const &, rai::pending_info &);
bool pending_exists (MDB_txn *, rai::block_hash const &);
rai::store_iterator pending_begin (MDB_txn *, rai::block_hash const &);
void pending_put (MDB_txn *, rai::pending_key const &, rai::pending_info const &);
void pending_del (MDB_txn *, rai::pending_key const &);
bool pending_get (MDB_txn *, rai::pending_key const &, rai::pending_info &);
bool pending_exists (MDB_txn *, rai::pending_key const &);
rai::store_iterator pending_begin (MDB_txn *, rai::pending_key const &);
rai::store_iterator pending_begin (MDB_txn *);
rai::store_iterator pending_end ();
@ -369,6 +380,7 @@ public:
void do_upgrades (MDB_txn *);
void upgrade_v1_to_v2 (MDB_txn *);
void upgrade_v2_to_v3 (MDB_txn *);
void upgrade_v3_to_v4 (MDB_txn *);
void clear (MDB_dbi);
@ -457,6 +469,7 @@ public:
rai::uint128_t amount (MDB_txn *, rai::block_hash const &);
rai::uint128_t balance (MDB_txn *, rai::block_hash const &);
rai::uint128_t account_balance (MDB_txn *, rai::account const &);
rai::uint128_t account_pending (MDB_txn *, rai::account const &);
rai::uint128_t weight (MDB_txn *, rai::account const &);
std::unique_ptr <rai::block> successor (MDB_txn *, rai::block_hash const &);
std::unique_ptr <rai::block> forked_block (MDB_txn *, rai::block const &);

View file

@ -53,3 +53,55 @@ rai::mdb_val rai::account_info_v1::val () const
{
return rai::mdb_val (sizeof (*this), const_cast <rai::account_info_v1 *> (this));
}
rai::pending_info_v3::pending_info_v3 () :
source (0),
amount (0),
destination (0)
{
}
rai::pending_info_v3::pending_info_v3 (MDB_val const & val_a)
{
assert(val_a.mv_size == sizeof (*this));
static_assert (sizeof (source) + sizeof (amount) + sizeof (destination) == sizeof (*this), "Packed class");
std::copy (reinterpret_cast <uint8_t const *> (val_a.mv_data), reinterpret_cast <uint8_t const *> (val_a.mv_data) + sizeof (*this), reinterpret_cast <uint8_t *> (this));
}
rai::pending_info_v3::pending_info_v3 (rai::account const & source_a, rai::amount const & amount_a, rai::account const & destination_a) :
source (source_a),
amount (amount_a),
destination (destination_a)
{
}
void rai::pending_info_v3::serialize (rai::stream & stream_a) const
{
rai::write (stream_a, source.bytes);
rai::write (stream_a, amount.bytes);
rai::write (stream_a, destination.bytes);
}
bool rai::pending_info_v3::deserialize (rai::stream & stream_a)
{
auto result (rai::read (stream_a, source.bytes));
if (!result)
{
result = rai::read (stream_a, amount.bytes);
if (!result)
{
result = rai::read (stream_a, destination.bytes);
}
}
return result;
}
bool rai::pending_info_v3::operator == (rai::pending_info_v3 const & other_a) const
{
return source == other_a.source && amount == other_a.amount && destination == other_a.destination;
}
rai::mdb_val rai::pending_info_v3::val () const
{
return rai::mdb_val (sizeof (*this), const_cast <rai::pending_info_v3 *> (this));
}

View file

@ -19,4 +19,18 @@ public:
rai::amount balance;
uint64_t modified;
};
}
class pending_info_v3
{
public:
pending_info_v3 ();
pending_info_v3 (MDB_val const &);
pending_info_v3 (rai::account const &, rai::amount const &, rai::account const &);
void serialize (rai::stream &) const;
bool deserialize (rai::stream &);
bool operator == (rai::pending_info_v3 const &) const;
rai::mdb_val val () const;
rai::account source;
rai::amount amount;
rai::account destination;
};
}