Block uniquer (#1358)

* Changing references to shared_ptr instead of unique_ptr in preparation for global uniquing.

* More returning of shared_ptr instead of unique_ptr.

* Removing unused declaration.

* Converting more unique_ptr<rai::block> to shared_ptr<rai::block>

* Removing unique_ptr cruft from when we handled blocks by unique_ptr instead of shared_ptr.

* Adding block-uniquing class to reduce memory usage for blocks.

* Using block_uniquer when deserializing messages.

* Adding rai::block function full_hash which produces a hash covering every member of a block, including parts that are not represented in the block hash, such as the signature or block work.

* Creating vote_uniquer class to save memory storing votes.

* Hooking up vote uniquer.

* Performing block-uniquing on local copy instead of a potentially shared copy at the end of the function.
This commit is contained in:
clemahieu 2018-11-07 15:07:56 -06:00 committed by GitHub
commit 376a80d3b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 492 additions and 173 deletions

View file

@ -294,8 +294,8 @@ TEST (block, publish_req_serialization)
{
rai::keypair key1;
rai::keypair key2;
auto block (std::unique_ptr<rai::send_block> (new rai::send_block (0, key2.pub, 200, rai::keypair ().prv, 2, 3)));
rai::publish req (std::move (block));
auto block (std::make_shared<rai::send_block> (0, key2.pub, 200, rai::keypair ().prv, 2, 3));
rai::publish req (block);
std::vector<uint8_t> bytes;
{
rai::vectorstream stream (bytes);
@ -315,8 +315,8 @@ TEST (block, confirm_req_serialization)
{
rai::keypair key1;
rai::keypair key2;
auto block (std::unique_ptr<rai::send_block> (new rai::send_block (0, key2.pub, 200, rai::keypair ().prv, 2, 3)));
rai::confirm_req req (std::move (block));
auto block (std::make_shared<rai::send_block> (0, key2.pub, 200, rai::keypair ().prv, 2, 3));
rai::confirm_req req (block);
std::vector<uint8_t> bytes;
{
rai::vectorstream stream (bytes);
@ -409,3 +409,44 @@ TEST (state_block, hashing)
block.hashables.link.bytes[0] ^= 0x1;
ASSERT_EQ (hash, block.hash ());
}
TEST (block_uniquer, null)
{
rai::block_uniquer uniquer;
ASSERT_EQ (nullptr, uniquer.unique (nullptr));
}
TEST (block_uniquer, single)
{
rai::keypair key;
auto block1 (std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 0));
auto block2 (std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 0));
std::weak_ptr<rai::state_block> block3 (block2);
ASSERT_NE (nullptr, block3.lock ());
rai::block_uniquer uniquer;
auto block4 (uniquer.unique (block1));
ASSERT_EQ (block1, block4);
auto block5 (uniquer.unique (block2));
ASSERT_EQ (block1, block5);
block2.reset ();
ASSERT_EQ (nullptr, block3.lock ());
}
TEST (block_uniquer, cleanup)
{
rai::keypair key;
auto block1 (std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 0));
auto block2 (std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 1));
rai::block_uniquer uniquer;
auto block3 (uniquer.unique (block1));
auto block4 (uniquer.unique (block2));
block2.reset ();
block4.reset ();
ASSERT_EQ (2, uniquer.size ());
auto iterations (0);
while (uniquer.size () == 2)
{
auto block5 (uniquer.unique (block1));
ASSERT_LT (iterations++, 200);
}
}

View file

@ -60,3 +60,88 @@ TEST (conflicts, add_two)
node1.active.start (send2);
ASSERT_EQ (2, node1.active.roots.size ());
}
TEST (vote_uniquer, null)
{
rai::block_uniquer block_uniquer;
rai::vote_uniquer uniquer (block_uniquer);
ASSERT_EQ (nullptr, uniquer.unique (nullptr));
}
// Show that an identical vote can be uniqued
TEST (vote_uniquer, same_vote)
{
rai::block_uniquer block_uniquer;
rai::vote_uniquer uniquer (block_uniquer);
rai::keypair key;
auto vote1 (std::make_shared<rai::vote> (key.pub, key.prv, 0, std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 0)));
auto vote2 (std::make_shared<rai::vote> (key.pub, key.prv, 0, std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 0)));
ASSERT_EQ (vote1, uniquer.unique (vote1));
ASSERT_EQ (vote1, uniquer.unique (vote2));
}
// Show that a different vote for the same block will have the block uniqued
TEST (vote_uniquer, same_block)
{
rai::block_uniquer block_uniquer;
rai::vote_uniquer uniquer (block_uniquer);
rai::keypair key1;
rai::keypair key2;
auto vote1 (std::make_shared<rai::vote> (key1.pub, key1.prv, 0, std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key1.prv, key1.pub, 0)));
auto vote2 (std::make_shared<rai::vote> (key2.pub, key2.prv, 0, std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key1.prv, key1.pub, 0)));
ASSERT_EQ (vote1, uniquer.unique (vote1));
ASSERT_EQ (vote2, uniquer.unique (vote2));
ASSERT_NE (vote1, vote2);
ASSERT_EQ (boost::get<std::shared_ptr<rai::block>> (vote1->blocks[0]), boost::get<std::shared_ptr<rai::block>> (vote2->blocks[0]));
}
TEST (vote_uniquer, vbh_one)
{
rai::block_uniquer block_uniquer;
rai::vote_uniquer uniquer (block_uniquer);
rai::keypair key;
auto block (std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 0));
std::vector<rai::block_hash> hashes;
hashes.push_back (block->hash ());
auto vote1 (std::make_shared<rai::vote> (key.pub, key.prv, 0, hashes));
auto vote2 (std::make_shared<rai::vote> (key.pub, key.prv, 0, hashes));
ASSERT_EQ (vote1, uniquer.unique (vote1));
ASSERT_EQ (vote1, uniquer.unique (vote2));
}
TEST (vote_uniquer, vbh_two)
{
rai::block_uniquer block_uniquer;
rai::vote_uniquer uniquer (block_uniquer);
rai::keypair key;
auto block1 (std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 0));
std::vector<rai::block_hash> hashes1;
hashes1.push_back (block1->hash ());
auto block2 (std::make_shared<rai::state_block> (1, 0, 0, 0, 0, key.prv, key.pub, 0));
std::vector<rai::block_hash> hashes2;
hashes2.push_back (block2->hash ());
auto vote1 (std::make_shared<rai::vote> (key.pub, key.prv, 0, hashes1));
auto vote2 (std::make_shared<rai::vote> (key.pub, key.prv, 0, hashes2));
ASSERT_EQ (vote1, uniquer.unique (vote1));
ASSERT_EQ (vote2, uniquer.unique (vote2));
}
TEST (vote_uniquer, cleanup)
{
rai::block_uniquer block_uniquer;
rai::vote_uniquer uniquer (block_uniquer);
rai::keypair key;
auto vote1 (std::make_shared<rai::vote> (key.pub, key.prv, 0, std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 0)));
auto vote2 (std::make_shared<rai::vote> (key.pub, key.prv, 1, std::make_shared<rai::state_block> (0, 0, 0, 0, 0, key.prv, key.pub, 0)));
auto vote3 (uniquer.unique (vote1));
auto vote4 (uniquer.unique (vote2));
vote2.reset ();
vote4.reset ();
ASSERT_EQ (2, uniquer.size ());
auto iterations (0);
while (uniquer.size () == 2)
{
auto vote5 (uniquer.unique (vote1));
ASSERT_LT (iterations++, 200);
}
}

View file

@ -40,7 +40,7 @@ TEST (message, keepalive_deserialize)
TEST (message, publish_serialization)
{
rai::publish publish (std::unique_ptr<rai::block> (new rai::send_block (0, 1, 2, rai::keypair ().prv, 4, 5)));
rai::publish publish (std::make_shared<rai::send_block> (0, 1, 2, rai::keypair ().prv, 4, 5));
ASSERT_EQ (rai::block_type::send, publish.header.block_type ());
ASSERT_FALSE (publish.header.ipv4_only ());
publish.header.ipv4_only_set (true);
@ -72,7 +72,7 @@ TEST (message, publish_serialization)
TEST (message, confirm_ack_serialization)
{
rai::keypair key1;
auto vote (std::make_shared<rai::vote> (key1.pub, key1.prv, 0, std::unique_ptr<rai::block> (new rai::send_block (0, 1, 2, key1.prv, 4, 5))));
auto vote (std::make_shared<rai::vote> (key1.pub, key1.prv, 0, std::make_shared<rai::send_block> (0, 1, 2, key1.prv, 4, 5)));
rai::confirm_ack con1 (vote);
std::vector<uint8_t> bytes;
{

View file

@ -75,8 +75,10 @@ TEST (message_parser, exact_confirm_ack_size)
{
rai::system system (24000, 1);
test_visitor visitor;
rai::message_parser parser (visitor, system.work);
auto block (std::unique_ptr<rai::send_block> (new rai::send_block (1, 1, 2, rai::keypair ().prv, 4, system.work.generate (1))));
rai::block_uniquer block_uniquer;
rai::vote_uniquer vote_uniquer (block_uniquer);
rai::message_parser parser (block_uniquer, vote_uniquer, visitor, system.work);
auto block (std::make_shared<rai::send_block> (1, 1, 2, rai::keypair ().prv, 4, system.work.generate (1)));
auto vote (std::make_shared<rai::vote> (0, rai::keypair ().prv, 0, std::move (block)));
rai::confirm_ack message (vote);
std::vector<uint8_t> bytes;
@ -106,8 +108,10 @@ TEST (message_parser, exact_confirm_req_size)
{
rai::system system (24000, 1);
test_visitor visitor;
rai::message_parser parser (visitor, system.work);
auto block (std::unique_ptr<rai::send_block> (new rai::send_block (1, 1, 2, rai::keypair ().prv, 4, system.work.generate (1))));
rai::block_uniquer block_uniquer;
rai::vote_uniquer vote_uniquer (block_uniquer);
rai::message_parser parser (block_uniquer, vote_uniquer, visitor, system.work);
auto block (std::make_shared<rai::send_block> (1, 1, 2, rai::keypair ().prv, 4, system.work.generate (1)));
rai::confirm_req message (std::move (block));
std::vector<uint8_t> bytes;
{
@ -136,8 +140,10 @@ TEST (message_parser, exact_publish_size)
{
rai::system system (24000, 1);
test_visitor visitor;
rai::message_parser parser (visitor, system.work);
auto block (std::unique_ptr<rai::send_block> (new rai::send_block (1, 1, 2, rai::keypair ().prv, 4, system.work.generate (1))));
rai::block_uniquer block_uniquer;
rai::vote_uniquer vote_uniquer (block_uniquer);
rai::message_parser parser (block_uniquer, vote_uniquer, visitor, system.work);
auto block (std::make_shared<rai::send_block> (1, 1, 2, rai::keypair ().prv, 4, system.work.generate (1)));
rai::publish message (std::move (block));
std::vector<uint8_t> bytes;
{
@ -166,7 +172,9 @@ TEST (message_parser, exact_keepalive_size)
{
rai::system system (24000, 1);
test_visitor visitor;
rai::message_parser parser (visitor, system.work);
rai::block_uniquer block_uniquer;
rai::vote_uniquer vote_uniquer (block_uniquer);
rai::message_parser parser (block_uniquer, vote_uniquer, visitor, system.work);
rai::keepalive message;
std::vector<uint8_t> bytes;
{

View file

@ -201,7 +201,7 @@ TEST (network, send_valid_confirm_ack)
rai::block_hash latest1 (system.nodes[0]->latest (rai::test_genesis_key.pub));
rai::send_block block2 (latest1, key2.pub, 50, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (latest1));
rai::block_hash latest2 (system.nodes[1]->latest (rai::test_genesis_key.pub));
system.nodes[0]->process_active (std::unique_ptr<rai::block> (new rai::send_block (block2)));
system.nodes[0]->process_active (std::make_shared<rai::send_block> (block2));
system.deadline_set (10s);
// Keep polling until latest block changes
while (system.nodes[1]->latest (rai::test_genesis_key.pub) == latest2)
@ -224,7 +224,7 @@ TEST (network, send_valid_publish)
rai::send_block block2 (latest1, key2.pub, 50, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (latest1));
auto hash2 (block2.hash ());
rai::block_hash latest2 (system.nodes[1]->latest (rai::test_genesis_key.pub));
system.nodes[1]->process_active (std::unique_ptr<rai::block> (new rai::send_block (block2)));
system.nodes[1]->process_active (std::make_shared<rai::send_block> (block2));
system.deadline_set (10s);
while (system.nodes[0]->stats.count (rai::stat::type::message, rai::stat::detail::publish, rai::stat::dir::in) == 0)
{
@ -242,7 +242,7 @@ TEST (network, send_valid_publish)
TEST (network, send_insufficient_work)
{
rai::system system (24000, 2);
std::unique_ptr<rai::send_block> block (new rai::send_block (0, 1, 20, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0));
auto block (std::make_shared<rai::send_block> (0, 1, 20, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0));
rai::publish publish (std::move (block));
std::shared_ptr<std::vector<uint8_t>> bytes (new std::vector<uint8_t>);
{
@ -584,8 +584,8 @@ TEST (bootstrap_processor, process_state)
rai::genesis genesis;
system.wallet (0)->insert_adhoc (rai::test_genesis_key.prv);
auto node0 (system.nodes[0]);
std::unique_ptr<rai::block> block1 (new rai::state_block (rai::test_genesis_key.pub, node0->latest (rai::test_genesis_key.pub), rai::test_genesis_key.pub, rai::genesis_amount - 100, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0));
std::unique_ptr<rai::block> block2 (new rai::state_block (rai::test_genesis_key.pub, block1->hash (), rai::test_genesis_key.pub, rai::genesis_amount, block1->hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0));
auto block1 (std::make_shared<rai::state_block> (rai::test_genesis_key.pub, node0->latest (rai::test_genesis_key.pub), rai::test_genesis_key.pub, rai::genesis_amount - 100, rai::test_genesis_key.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0));
auto block2 (std::make_shared<rai::state_block> (rai::test_genesis_key.pub, block1->hash (), rai::test_genesis_key.pub, rai::genesis_amount, block1->hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0));
node0->work_generate_blocking (*block1);
node0->work_generate_blocking (*block2);
node0->process (*block1);
@ -636,13 +636,13 @@ TEST (bootstrap_processor, pull_diamond)
{
rai::system system (24000, 1);
rai::keypair key;
std::unique_ptr<rai::send_block> send1 (new rai::send_block (system.nodes[0]->latest (rai::test_genesis_key.pub), key.pub, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (system.nodes[0]->latest (rai::test_genesis_key.pub))));
auto send1 (std::make_shared<rai::send_block> (system.nodes[0]->latest (rai::test_genesis_key.pub), key.pub, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (system.nodes[0]->latest (rai::test_genesis_key.pub))));
ASSERT_EQ (rai::process_result::progress, system.nodes[0]->process (*send1).code);
std::unique_ptr<rai::open_block> open (new rai::open_block (send1->hash (), 1, key.pub, key.prv, key.pub, system.work.generate (key.pub)));
auto open (std::make_shared<rai::open_block> (send1->hash (), 1, key.pub, key.prv, key.pub, system.work.generate (key.pub)));
ASSERT_EQ (rai::process_result::progress, system.nodes[0]->process (*open).code);
std::unique_ptr<rai::send_block> send2 (new rai::send_block (open->hash (), rai::test_genesis_key.pub, std::numeric_limits<rai::uint128_t>::max () - 100, key.prv, key.pub, system.work.generate (open->hash ())));
auto send2 (std::make_shared<rai::send_block> (open->hash (), rai::test_genesis_key.pub, std::numeric_limits<rai::uint128_t>::max () - 100, key.prv, key.pub, system.work.generate (open->hash ())));
ASSERT_EQ (rai::process_result::progress, system.nodes[0]->process (*send2).code);
std::unique_ptr<rai::receive_block> receive (new rai::receive_block (send1->hash (), send2->hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (send1->hash ())));
auto receive (std::make_shared<rai::receive_block> (send1->hash (), send2->hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (send1->hash ())));
ASSERT_EQ (rai::process_result::progress, system.nodes[0]->process (*receive).code);
rai::node_init init1;
auto node1 (std::make_shared<rai::node> (init1, system.service, 24002, rai::unique_path (), system.alarm, system.logging, system.work));
@ -667,13 +667,13 @@ TEST (bootstrap_processor, push_diamond)
auto wallet1 (node1->wallets.create (100));
wallet1->insert_adhoc (rai::test_genesis_key.prv);
wallet1->insert_adhoc (key.prv);
std::unique_ptr<rai::send_block> send1 (new rai::send_block (system.nodes[0]->latest (rai::test_genesis_key.pub), key.pub, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (system.nodes[0]->latest (rai::test_genesis_key.pub))));
auto send1 (std::make_shared<rai::send_block> (system.nodes[0]->latest (rai::test_genesis_key.pub), key.pub, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (system.nodes[0]->latest (rai::test_genesis_key.pub))));
ASSERT_EQ (rai::process_result::progress, node1->process (*send1).code);
std::unique_ptr<rai::open_block> open (new rai::open_block (send1->hash (), 1, key.pub, key.prv, key.pub, system.work.generate (key.pub)));
auto open (std::make_shared<rai::open_block> (send1->hash (), 1, key.pub, key.prv, key.pub, system.work.generate (key.pub)));
ASSERT_EQ (rai::process_result::progress, node1->process (*open).code);
std::unique_ptr<rai::send_block> send2 (new rai::send_block (open->hash (), rai::test_genesis_key.pub, std::numeric_limits<rai::uint128_t>::max () - 100, key.prv, key.pub, system.work.generate (open->hash ())));
auto send2 (std::make_shared<rai::send_block> (open->hash (), rai::test_genesis_key.pub, std::numeric_limits<rai::uint128_t>::max () - 100, key.prv, key.pub, system.work.generate (open->hash ())));
ASSERT_EQ (rai::process_result::progress, node1->process (*send2).code);
std::unique_ptr<rai::receive_block> receive (new rai::receive_block (send1->hash (), send2->hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (send1->hash ())));
auto receive (std::make_shared<rai::receive_block> (send1->hash (), send2->hash (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (send1->hash ())));
ASSERT_EQ (rai::process_result::progress, node1->process (*receive).code);
node1->bootstrap_initiator.bootstrap (system.nodes[0]->network.endpoint ());
system.deadline_set (10s);

View file

@ -148,9 +148,9 @@ TEST (node, send_out_of_order)
rai::send_block send1 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
rai::send_block send2 (send1.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 2, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (send1.hash ()));
rai::send_block send3 (send2.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 3, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (send2.hash ()));
system.nodes[0]->process_active (std::unique_ptr<rai::block> (new rai::send_block (send3)));
system.nodes[0]->process_active (std::unique_ptr<rai::block> (new rai::send_block (send2)));
system.nodes[0]->process_active (std::unique_ptr<rai::block> (new rai::send_block (send1)));
system.nodes[0]->process_active (std::make_shared<rai::send_block> (send3));
system.nodes[0]->process_active (std::make_shared<rai::send_block> (send2));
system.nodes[0]->process_active (std::make_shared<rai::send_block> (send1));
system.deadline_set (10s);
while (std::any_of (system.nodes.begin (), system.nodes.end (), [&](std::shared_ptr<rai::node> const & node_a) { return node_a->balance (rai::test_genesis_key.pub) != rai::genesis_amount - system.nodes[0]->config.receive_minimum.number () * 3; }))
{
@ -1658,29 +1658,29 @@ TEST (node, vote_republish)
rai::keypair key2;
system.wallet (1)->insert_adhoc (key2.prv);
rai::genesis genesis;
rai::send_block send1 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
rai::send_block send2 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 2, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
system.nodes[0]->process_active (std::unique_ptr<rai::block> (new rai::send_block (send1)));
auto send1 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
auto send2 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 2, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
system.nodes[0]->process_active (send1);
system.deadline_set (5s);
while (!system.nodes[1]->block (send1.hash ()))
while (!system.nodes[1]->block (send1->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
system.nodes[0]->active.publish (std::unique_ptr<rai::block> (new rai::send_block (send2)));
auto vote (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 0, std::unique_ptr<rai::block> (new rai::send_block (send2))));
ASSERT_TRUE (system.nodes[0]->active.active (send1));
ASSERT_TRUE (system.nodes[1]->active.active (send1));
system.nodes[0]->active.publish (send2);
auto vote (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 0, send2));
ASSERT_TRUE (system.nodes[0]->active.active (*send1));
ASSERT_TRUE (system.nodes[1]->active.active (*send1));
system.nodes[0]->vote_processor.vote (vote, system.nodes[0]->network.endpoint ());
while (!system.nodes[0]->block (send2.hash ()))
while (!system.nodes[0]->block (send2->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
while (!system.nodes[1]->block (send2.hash ()))
while (!system.nodes[1]->block (send2->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_FALSE (system.nodes[0]->block (send1.hash ()));
ASSERT_FALSE (system.nodes[1]->block (send1.hash ()));
ASSERT_FALSE (system.nodes[0]->block (send1->hash ()));
ASSERT_FALSE (system.nodes[1]->block (send1->hash ()));
system.deadline_set (5s);
while (system.nodes[1]->balance (key2.pub) != system.nodes[0]->config.receive_minimum.number () * 2)
{
@ -1698,31 +1698,31 @@ TEST (node, vote_by_hash_republish)
rai::keypair key2;
system.wallet (1)->insert_adhoc (key2.prv);
rai::genesis genesis;
rai::send_block send1 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
rai::send_block send2 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 2, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
system.nodes[0]->process_active (std::unique_ptr<rai::block> (new rai::send_block (send1)));
auto send1 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
auto send2 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 2, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
system.nodes[0]->process_active (send1);
system.deadline_set (5s);
while (!system.nodes[1]->block (send1.hash ()))
while (!system.nodes[1]->block (send1->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
system.nodes[0]->active.publish (std::unique_ptr<rai::block> (new rai::send_block (send2)));
system.nodes[0]->active.publish (send2);
std::vector<rai::block_hash> vote_blocks;
vote_blocks.push_back (send2.hash ());
vote_blocks.push_back (send2->hash ());
auto vote (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 0, vote_blocks));
ASSERT_TRUE (system.nodes[0]->active.active (send1));
ASSERT_TRUE (system.nodes[1]->active.active (send1));
ASSERT_TRUE (system.nodes[0]->active.active (*send1));
ASSERT_TRUE (system.nodes[1]->active.active (*send1));
system.nodes[0]->vote_processor.vote (vote, system.nodes[0]->network.endpoint ());
while (!system.nodes[0]->block (send2.hash ()))
while (!system.nodes[0]->block (send2->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
while (!system.nodes[1]->block (send2.hash ()))
while (!system.nodes[1]->block (send2->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_FALSE (system.nodes[0]->block (send1.hash ()));
ASSERT_FALSE (system.nodes[1]->block (send1.hash ()));
ASSERT_FALSE (system.nodes[0]->block (send1->hash ()));
ASSERT_FALSE (system.nodes[1]->block (send1->hash ()));
system.deadline_set (5s);
while (system.nodes[1]->balance (key2.pub) != system.nodes[0]->config.receive_minimum.number () * 2)
{
@ -1743,31 +1743,31 @@ TEST (node, vote_by_hash_epoch_block_republish)
system.nodes[0]->ledger.epoch_signer = epoch_signer.pub;
system.nodes[1]->ledger.epoch_signer = epoch_signer.pub;
rai::genesis genesis;
rai::send_block send1 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
rai::state_block epoch1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount, system.nodes[0]->ledger.epoch_link, epoch_signer.prv, epoch_signer.pub, system.work.generate (genesis.hash ()));
system.nodes[0]->process_active (std::unique_ptr<rai::block> (new rai::send_block (send1)));
auto send1 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
auto epoch1 (std::make_shared<rai::state_block> (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount, system.nodes[0]->ledger.epoch_link, epoch_signer.prv, epoch_signer.pub, system.work.generate (genesis.hash ())));
system.nodes[0]->process_active (send1);
system.deadline_set (5s);
while (!system.nodes[1]->block (send1.hash ()))
while (!system.nodes[1]->block (send1->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
system.nodes[0]->active.publish (std::unique_ptr<rai::block> (new rai::state_block (epoch1)));
system.nodes[0]->active.publish (epoch1);
std::vector<rai::block_hash> vote_blocks;
vote_blocks.push_back (epoch1.hash ());
vote_blocks.push_back (epoch1->hash ());
auto vote (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 0, vote_blocks));
ASSERT_TRUE (system.nodes[0]->active.active (send1));
ASSERT_TRUE (system.nodes[1]->active.active (send1));
ASSERT_TRUE (system.nodes[0]->active.active (*send1));
ASSERT_TRUE (system.nodes[1]->active.active (*send1));
system.nodes[0]->vote_processor.vote (vote, system.nodes[0]->network.endpoint ());
while (!system.nodes[0]->block (epoch1.hash ()))
while (!system.nodes[0]->block (epoch1->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
while (!system.nodes[1]->block (epoch1.hash ()))
while (!system.nodes[1]->block (epoch1->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_FALSE (system.nodes[0]->block (send1.hash ()));
ASSERT_FALSE (system.nodes[1]->block (send1.hash ()));
ASSERT_FALSE (system.nodes[0]->block (send1->hash ()));
ASSERT_FALSE (system.nodes[1]->block (send1->hash ()));
}
TEST (node, fork_invalid_block_signature)
@ -1775,30 +1775,30 @@ TEST (node, fork_invalid_block_signature)
rai::system system (24000, 2);
rai::keypair key2;
rai::genesis genesis;
rai::send_block send1 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
rai::send_block send2 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 2, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
rai::send_block send2_corrupt (send2);
send2_corrupt.signature = rai::signature (123);
system.nodes[0]->process_active (std::unique_ptr<rai::block> (new rai::send_block (send1)));
auto send1 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
auto send2 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 2, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
auto send2_corrupt (std::make_shared<rai::send_block> (*send2));
send2_corrupt->signature = rai::signature (123);
system.nodes[0]->process_active (send1);
system.deadline_set (5s);
while (!system.nodes[0]->block (send1.hash ()))
while (!system.nodes[0]->block (send1->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
auto vote (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 0, std::make_unique<rai::send_block> (send2)));
auto vote_corrupt (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 0, std::make_unique<rai::send_block> (send2_corrupt)));
auto vote (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 0, send2));
auto vote_corrupt (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 0, send2_corrupt));
system.nodes[1]->network.republish_vote (vote_corrupt);
ASSERT_NO_ERROR (system.poll ());
system.nodes[1]->network.republish_vote (vote);
while (system.nodes[0]->block (send1.hash ()))
while (system.nodes[0]->block (send1->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
while (!system.nodes[0]->block (send2.hash ()))
while (!system.nodes[0]->block (send2->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (system.nodes[0]->block (send2.hash ())->block_signature (), send2.block_signature ());
ASSERT_EQ (system.nodes[0]->block (send2->hash ())->block_signature (), send2->block_signature ());
}
TEST (node, fork_invalid_block_signature_vote_by_hash)
@ -1806,35 +1806,35 @@ TEST (node, fork_invalid_block_signature_vote_by_hash)
rai::system system (24000, 1);
rai::keypair key2;
rai::genesis genesis;
rai::send_block send1 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
rai::send_block send2 (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 2, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ()));
rai::send_block send2_corrupt (send2);
send2_corrupt.signature = rai::signature (123);
system.nodes[0]->process_active (std::unique_ptr<rai::block> (new rai::send_block (send1)));
auto send1 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number (), rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
auto send2 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, std::numeric_limits<rai::uint128_t>::max () - system.nodes[0]->config.receive_minimum.number () * 2, rai::test_genesis_key.prv, rai::test_genesis_key.pub, system.work.generate (genesis.hash ())));
auto send2_corrupt (std::make_shared<rai::send_block> (*send2));
send2_corrupt->signature = rai::signature (123);
system.nodes[0]->process_active (send1);
system.deadline_set (5s);
while (!system.nodes[0]->block (send1.hash ()))
while (!system.nodes[0]->block (send1->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
system.nodes[0]->active.publish (std::make_unique<rai::send_block> (send2_corrupt));
system.nodes[0]->active.publish (send2_corrupt);
ASSERT_NO_ERROR (system.poll ());
system.nodes[0]->active.publish (std::make_unique<rai::send_block> (send2));
system.nodes[0]->active.publish (send2);
std::vector<rai::block_hash> vote_blocks;
vote_blocks.push_back (send2.hash ());
vote_blocks.push_back (send2->hash ());
auto vote (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 0, vote_blocks));
{
auto transaction (system.nodes[0]->store.tx_begin_read ());
system.nodes[0]->vote_processor.vote_blocking (transaction, vote, system.nodes[0]->network.endpoint ());
}
while (system.nodes[0]->block (send1.hash ()))
while (system.nodes[0]->block (send1->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
while (!system.nodes[0]->block (send2.hash ()))
while (!system.nodes[0]->block (send2->hash ()))
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (system.nodes[0]->block (send2.hash ())->block_signature (), send2.block_signature ());
ASSERT_EQ (system.nodes[0]->block (send2->hash ())->block_signature (), send2->block_signature ());
}
TEST (node, block_processor_signatures)

View file

@ -2,6 +2,8 @@
#include <boost/endian/conversion.hpp>
#include <xxhash/xxhash.h>
/** Compare blocks, first by type, then content. This is an optimization over dynamic_cast, which is very slow on some platforms. */
namespace
{
@ -69,6 +71,20 @@ rai::block_hash rai::block::hash () const
return result;
}
rai::block_hash rai::block::full_hash () const
{
rai::block_hash result;
blake2b_state state;
blake2b_init (&state, sizeof (result.bytes));
blake2b_update (&state, hash ().bytes.data (), sizeof (hash ()));
auto signature (block_signature ());
blake2b_update (&state, signature.bytes.data (), sizeof (signature));
auto work (block_work ());
blake2b_update (&state, &work, sizeof (work));
blake2b_final (&state, result.bytes.data (), sizeof (result.bytes));
return result;
}
void rai::send_block::visit (rai::block_visitor & visitor_a) const
{
visitor_a.send_block (*this);
@ -1145,9 +1161,9 @@ void rai::state_block::signature_set (rai::uint512_union const & signature_a)
signature = signature_a;
}
std::unique_ptr<rai::block> rai::deserialize_block_json (boost::property_tree::ptree const & tree_a)
std::shared_ptr<rai::block> rai::deserialize_block_json (boost::property_tree::ptree const & tree_a, rai::block_uniquer * uniquer_a)
{
std::unique_ptr<rai::block> result;
std::shared_ptr<rai::block> result;
try
{
auto type (tree_a.get<std::string> ("type"));
@ -1200,14 +1216,18 @@ std::unique_ptr<rai::block> rai::deserialize_block_json (boost::property_tree::p
catch (std::runtime_error const &)
{
}
if (uniquer_a != nullptr)
{
result = uniquer_a->unique (result);
}
return result;
}
std::unique_ptr<rai::block> rai::deserialize_block (rai::stream & stream_a)
std::shared_ptr<rai::block> rai::deserialize_block (rai::stream & stream_a, rai::block_uniquer * uniquer_a)
{
rai::block_type type;
auto error (read (stream_a, type));
std::unique_ptr<rai::block> result;
std::shared_ptr<rai::block> result;
if (!error)
{
result = rai::deserialize_block (stream_a, type);
@ -1215,9 +1235,9 @@ std::unique_ptr<rai::block> rai::deserialize_block (rai::stream & stream_a)
return result;
}
std::unique_ptr<rai::block> rai::deserialize_block (rai::stream & stream_a, rai::block_type type_a)
std::shared_ptr<rai::block> rai::deserialize_block (rai::stream & stream_a, rai::block_type type_a, rai::block_uniquer * uniquer_a)
{
std::unique_ptr<rai::block> result;
std::shared_ptr<rai::block> result;
switch (type_a)
{
case rai::block_type::receive:
@ -1274,6 +1294,10 @@ std::unique_ptr<rai::block> rai::deserialize_block (rai::stream & stream_a, rai:
assert (false);
break;
}
if (uniquer_a != nullptr)
{
result = uniquer_a->unique (result);
}
return result;
}
@ -1523,3 +1547,50 @@ void rai::receive_hashables::hash (blake2b_state & hash_a) const
blake2b_update (&hash_a, previous.bytes.data (), sizeof (previous.bytes));
blake2b_update (&hash_a, source.bytes.data (), sizeof (source.bytes));
}
std::shared_ptr<rai::block> rai::block_uniquer::unique (std::shared_ptr<rai::block> block_a)
{
auto result (block_a);
if (result != nullptr)
{
rai::uint256_union key (block_a->full_hash ());
std::lock_guard<std::mutex> lock (mutex);
auto & existing (blocks[key]);
if (auto block_l = existing.lock ())
{
result = block_l;
}
else
{
existing = block_a;
}
for (auto i (0); i < cleanup_count; ++i)
{
rai::uint256_union random;
rai::random_pool.GenerateBlock (random.bytes.data (), random.bytes.size ());
auto existing (blocks.find (random));
if (existing == blocks.end ())
{
existing = blocks.begin ();
}
if (existing != blocks.end ())
{
if (auto block_l = existing->second.lock ())
{
// Still live
}
else
{
blocks.erase (existing);
}
}
}
}
return result;
}
size_t rai::block_uniquer::size ()
{
std::lock_guard<std::mutex> lock (mutex);
return blocks.size ();
}

View file

@ -6,6 +6,7 @@
#include <blake2/blake2.h>
#include <boost/property_tree/json_parser.hpp>
#include <streambuf>
#include <unordered_map>
namespace rai
{
@ -44,6 +45,8 @@ class block
public:
// Return a digest of the hashables in this block.
rai::block_hash hash () const;
// Return a digest of hashables and non-hashables in this block.
rai::block_hash full_hash () const;
std::string to_json ();
virtual void hash (blake2b_state &) const = 0;
virtual uint64_t block_work () const = 0;
@ -302,8 +305,22 @@ public:
virtual void state_block (rai::state_block const &) = 0;
virtual ~block_visitor () = default;
};
std::unique_ptr<rai::block> deserialize_block (rai::stream &);
std::unique_ptr<rai::block> deserialize_block (rai::stream &, rai::block_type);
std::unique_ptr<rai::block> deserialize_block_json (boost::property_tree::ptree const &);
/**
* This class serves to find and return unique variants of a block in order to minimize memory usage
*/
class block_uniquer
{
public:
std::shared_ptr<rai::block> unique (std::shared_ptr<rai::block>);
size_t size ();
private:
std::mutex mutex;
std::unordered_map<rai::uint256_union, std::weak_ptr<rai::block>> blocks;
static unsigned constexpr cleanup_count = 2;
};
std::shared_ptr<rai::block> deserialize_block (rai::stream &, rai::block_uniquer * = nullptr);
std::shared_ptr<rai::block> deserialize_block (rai::stream &, rai::block_type, rai::block_uniquer * = nullptr);
std::shared_ptr<rai::block> deserialize_block_json (boost::property_tree::ptree const &, rai::block_uniquer * = nullptr);
void serialize_block (rai::stream &, rai::block const &);
}

View file

@ -604,7 +604,7 @@ void rai::bulk_push_client::start ()
void rai::bulk_push_client::push (rai::transaction const & transaction_a)
{
std::unique_ptr<rai::block> block;
std::shared_ptr<rai::block> block;
bool finished (false);
while (block == nullptr && !finished)
{
@ -1652,7 +1652,7 @@ void rai::bulk_pull_server::set_current_end ()
void rai::bulk_pull_server::send_next ()
{
std::unique_ptr<rai::block> block (get_next ());
auto block (get_next ());
if (block != nullptr)
{
{
@ -1675,9 +1675,9 @@ void rai::bulk_pull_server::send_next ()
}
}
std::unique_ptr<rai::block> rai::bulk_pull_server::get_next ()
std::shared_ptr<rai::block> rai::bulk_pull_server::get_next ()
{
std::unique_ptr<rai::block> result;
std::shared_ptr<rai::block> result;
bool send_current = false, set_current_to_end = false;
/*

View file

@ -238,7 +238,7 @@ class bulk_pull_server : public std::enable_shared_from_this<rai::bulk_pull_serv
public:
bulk_pull_server (std::shared_ptr<rai::bootstrap_server> const &, std::unique_ptr<rai::bulk_pull>);
void set_current_end ();
std::unique_ptr<rai::block> get_next ();
std::shared_ptr<rai::block> get_next ();
void send_next ();
void sent_action (boost::system::error_code const &, size_t);
void send_finished ();
@ -276,7 +276,7 @@ class bulk_pull_blocks_server : public std::enable_shared_from_this<rai::bulk_pu
public:
bulk_pull_blocks_server (std::shared_ptr<rai::bootstrap_server> const &, std::unique_ptr<rai::bulk_pull_blocks>);
void set_params ();
std::unique_ptr<rai::block> get_next ();
std::shared_ptr<rai::block> get_next ();
void send_next ();
void send_finished ();
void no_block_sent (boost::system::error_code const &, size_t);

View file

@ -146,7 +146,9 @@ std::string rai::message_parser::status_string ()
return "[unknown parse_status]";
}
rai::message_parser::message_parser (rai::message_visitor & visitor_a, rai::work_pool & pool_a) :
rai::message_parser::message_parser (rai::block_uniquer & block_uniquer_a, rai::vote_uniquer & vote_uniquer_a, rai::message_visitor & visitor_a, rai::work_pool & pool_a) :
block_uniquer (block_uniquer_a),
vote_uniquer (vote_uniquer_a),
visitor (visitor_a),
pool (pool_a),
status (parse_status::success)
@ -237,7 +239,7 @@ void rai::message_parser::deserialize_keepalive (rai::stream & stream_a, rai::me
void rai::message_parser::deserialize_publish (rai::stream & stream_a, rai::message_header const & header_a)
{
auto error (false);
rai::publish incoming (error, stream_a, header_a);
rai::publish incoming (error, stream_a, header_a, &block_uniquer);
if (!error && at_end (stream_a))
{
if (!rai::work_validate (*incoming.block))
@ -258,7 +260,7 @@ void rai::message_parser::deserialize_publish (rai::stream & stream_a, rai::mess
void rai::message_parser::deserialize_confirm_req (rai::stream & stream_a, rai::message_header const & header_a)
{
auto error (false);
rai::confirm_req incoming (error, stream_a, header_a);
rai::confirm_req incoming (error, stream_a, header_a, &block_uniquer);
if (!error && at_end (stream_a))
{
if (!rai::work_validate (*incoming.block))
@ -279,7 +281,7 @@ void rai::message_parser::deserialize_confirm_req (rai::stream & stream_a, rai::
void rai::message_parser::deserialize_confirm_ack (rai::stream & stream_a, rai::message_header const & header_a)
{
auto error (false);
rai::confirm_ack incoming (error, stream_a, header_a);
rai::confirm_ack incoming (error, stream_a, header_a, &vote_uniquer);
if (!error && at_end (stream_a))
{
for (auto & vote_block : incoming.vote->blocks)
@ -387,12 +389,12 @@ bool rai::keepalive::operator== (rai::keepalive const & other_a) const
return peers == other_a.peers;
}
rai::publish::publish (bool & error_a, rai::stream & stream_a, rai::message_header const & header_a) :
rai::publish::publish (bool & error_a, rai::stream & stream_a, rai::message_header const & header_a, rai::block_uniquer * uniquer_a) :
message (header_a)
{
if (!error_a)
{
error_a = deserialize (stream_a);
error_a = deserialize (stream_a, uniquer_a);
}
}
@ -403,10 +405,10 @@ block (block_a)
header.block_type_set (block->type ());
}
bool rai::publish::deserialize (rai::stream & stream_a)
bool rai::publish::deserialize (rai::stream & stream_a, rai::block_uniquer * uniquer_a)
{
assert (header.type == rai::message_type::publish);
block = rai::deserialize_block (stream_a, header.block_type ());
block = rai::deserialize_block (stream_a, header.block_type (), uniquer_a);
auto result (block == nullptr);
return result;
}
@ -428,12 +430,12 @@ bool rai::publish::operator== (rai::publish const & other_a) const
return *block == *other_a.block;
}
rai::confirm_req::confirm_req (bool & error_a, rai::stream & stream_a, rai::message_header const & header_a) :
rai::confirm_req::confirm_req (bool & error_a, rai::stream & stream_a, rai::message_header const & header_a, rai::block_uniquer * uniquer_a) :
message (header_a)
{
if (!error_a)
{
error_a = deserialize (stream_a);
error_a = deserialize (stream_a, uniquer_a);
}
}
@ -444,10 +446,10 @@ block (block_a)
header.block_type_set (block->type ());
}
bool rai::confirm_req::deserialize (rai::stream & stream_a)
bool rai::confirm_req::deserialize (rai::stream & stream_a, rai::block_uniquer * uniquer_a)
{
assert (header.type == rai::message_type::confirm_req);
block = rai::deserialize_block (stream_a, header.block_type ());
block = rai::deserialize_block (stream_a, header.block_type (), uniquer_a);
auto result (block == nullptr);
return result;
}
@ -469,10 +471,14 @@ bool rai::confirm_req::operator== (rai::confirm_req const & other_a) const
return *block == *other_a.block;
}
rai::confirm_ack::confirm_ack (bool & error_a, rai::stream & stream_a, rai::message_header const & header_a) :
rai::confirm_ack::confirm_ack (bool & error_a, rai::stream & stream_a, rai::message_header const & header_a, rai::vote_uniquer * uniquer_a) :
message (header_a),
vote (std::make_shared<rai::vote> (error_a, stream_a, header.block_type ()))
{
if (uniquer_a)
{
vote = uniquer_a->unique (vote);
}
}
rai::confirm_ack::confirm_ack (std::shared_ptr<rai::vote> vote_a) :
@ -490,10 +496,14 @@ vote (vote_a)
}
}
bool rai::confirm_ack::deserialize (rai::stream & stream_a)
bool rai::confirm_ack::deserialize (rai::stream & stream_a, rai::vote_uniquer * uniquer_a)
{
assert (header.type == rai::message_type::confirm_ack);
auto result (vote->deserialize (stream_a));
if (uniquer_a)
{
vote = uniquer_a->unique (vote);
}
return result;
}

View file

@ -191,7 +191,6 @@ public:
message (rai::message_header const &);
virtual ~message () = default;
virtual void serialize (rai::stream &) = 0;
virtual bool deserialize (rai::stream &) = 0;
virtual void visit (rai::message_visitor &) const = 0;
rai::message_header header;
};
@ -214,7 +213,7 @@ public:
invalid_magic,
invalid_network
};
message_parser (rai::message_visitor &, rai::work_pool &);
message_parser (rai::block_uniquer &, rai::vote_uniquer &, rai::message_visitor &, rai::work_pool &);
void deserialize_buffer (uint8_t const *, size_t);
void deserialize_keepalive (rai::stream &, rai::message_header const &);
void deserialize_publish (rai::stream &, rai::message_header const &);
@ -222,6 +221,8 @@ public:
void deserialize_confirm_ack (rai::stream &, rai::message_header const &);
void deserialize_node_id_handshake (rai::stream &, rai::message_header const &);
bool at_end (rai::stream &);
rai::block_uniquer & block_uniquer;
rai::vote_uniquer & vote_uniquer;
rai::message_visitor & visitor;
rai::work_pool & pool;
parse_status status;
@ -234,7 +235,7 @@ public:
keepalive (bool &, rai::stream &, rai::message_header const &);
keepalive ();
void visit (rai::message_visitor &) const override;
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &);
void serialize (rai::stream &) override;
bool operator== (rai::keepalive const &) const;
std::array<rai::endpoint, 8> peers;
@ -242,10 +243,10 @@ public:
class publish : public message
{
public:
publish (bool &, rai::stream &, rai::message_header const &);
publish (bool &, rai::stream &, rai::message_header const &, rai::block_uniquer * = nullptr);
publish (std::shared_ptr<rai::block>);
void visit (rai::message_visitor &) const override;
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &, rai::block_uniquer * = nullptr);
void serialize (rai::stream &) override;
bool operator== (rai::publish const &) const;
std::shared_ptr<rai::block> block;
@ -253,9 +254,9 @@ public:
class confirm_req : public message
{
public:
confirm_req (bool &, rai::stream &, rai::message_header const &);
confirm_req (bool &, rai::stream &, rai::message_header const &, rai::block_uniquer * = nullptr);
confirm_req (std::shared_ptr<rai::block>);
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &, rai::block_uniquer * = nullptr);
void serialize (rai::stream &) override;
void visit (rai::message_visitor &) const override;
bool operator== (rai::confirm_req const &) const;
@ -264,9 +265,9 @@ public:
class confirm_ack : public message
{
public:
confirm_ack (bool &, rai::stream &, rai::message_header const &);
confirm_ack (bool &, rai::stream &, rai::message_header const &, rai::vote_uniquer * = nullptr);
confirm_ack (std::shared_ptr<rai::vote>);
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &, rai::vote_uniquer * = nullptr);
void serialize (rai::stream &) override;
void visit (rai::message_visitor &) const override;
bool operator== (rai::confirm_ack const &) const;
@ -277,7 +278,7 @@ class frontier_req : public message
public:
frontier_req ();
frontier_req (bool &, rai::stream &, rai::message_header const &);
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &);
void serialize (rai::stream &) override;
void visit (rai::message_visitor &) const override;
bool operator== (rai::frontier_req const &) const;
@ -290,7 +291,7 @@ class bulk_pull : public message
public:
bulk_pull ();
bulk_pull (bool &, rai::stream &, rai::message_header const &);
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &);
void serialize (rai::stream &) override;
void visit (rai::message_visitor &) const override;
rai::uint256_union start;
@ -301,7 +302,7 @@ class bulk_pull_account : public message
public:
bulk_pull_account ();
bulk_pull_account (bool &, rai::stream &, rai::message_header const &);
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &);
void serialize (rai::stream &) override;
void visit (rai::message_visitor &) const override;
rai::uint256_union account;
@ -313,7 +314,7 @@ class bulk_pull_blocks : public message
public:
bulk_pull_blocks ();
bulk_pull_blocks (bool &, rai::stream &, rai::message_header const &);
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &);
void serialize (rai::stream &) override;
void visit (rai::message_visitor &) const override;
rai::block_hash min_hash;
@ -326,7 +327,7 @@ class bulk_push : public message
public:
bulk_push ();
bulk_push (rai::message_header const &);
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &);
void serialize (rai::stream &) override;
void visit (rai::message_visitor &) const override;
};
@ -335,7 +336,7 @@ class node_id_handshake : public message
public:
node_id_handshake (bool &, rai::stream &, rai::message_header const &);
node_id_handshake (boost::optional<rai::block_hash>, boost::optional<std::pair<rai::account, rai::signature>>);
bool deserialize (rai::stream &) override;
bool deserialize (rai::stream &);
void serialize (rai::stream &) override;
void visit (rai::message_visitor &) const override;
bool operator== (rai::node_id_handshake const &) const;

View file

@ -1226,7 +1226,7 @@ MDB_val rai::mdb_store::block_raw_get (rai::transaction const & transaction_a, r
}
template <typename T>
std::unique_ptr<rai::block> rai::mdb_store::block_random (rai::transaction const & transaction_a, MDB_dbi database)
std::shared_ptr<rai::block> rai::mdb_store::block_random (rai::transaction const & transaction_a, MDB_dbi database)
{
rai::block_hash hash;
rai::random_pool.GenerateBlock (hash.bytes.data (), hash.bytes.size ());
@ -1240,11 +1240,11 @@ std::unique_ptr<rai::block> rai::mdb_store::block_random (rai::transaction const
return block_get (transaction_a, rai::block_hash (existing->first));
}
std::unique_ptr<rai::block> rai::mdb_store::block_random (rai::transaction const & transaction_a)
std::shared_ptr<rai::block> rai::mdb_store::block_random (rai::transaction const & transaction_a)
{
auto count (block_count (transaction_a));
auto region (rai::random_pool.GenerateWord32 (0, count.sum () - 1));
std::unique_ptr<rai::block> result;
std::shared_ptr<rai::block> result;
if (region < count.send)
{
result = block_random<rai::send_block> (transaction_a, send_blocks);
@ -1315,11 +1315,11 @@ void rai::mdb_store::block_successor_clear (rai::transaction const & transaction
block_put (transaction_a, hash_a, *block, 0, version);
}
std::unique_ptr<rai::block> rai::mdb_store::block_get (rai::transaction const & transaction_a, rai::block_hash const & hash_a)
std::shared_ptr<rai::block> rai::mdb_store::block_get (rai::transaction const & transaction_a, rai::block_hash const & hash_a)
{
rai::block_type type;
auto value (block_raw_get (transaction_a, hash_a, type));
std::unique_ptr<rai::block> result;
std::shared_ptr<rai::block> result;
if (value.mv_size != 0)
{
rai::bufferstream stream (reinterpret_cast<uint8_t const *> (value.mv_data), value.mv_size);

View file

@ -155,8 +155,8 @@ public:
void block_put (rai::transaction const &, rai::block_hash const &, rai::block const &, rai::block_hash const & = rai::block_hash (0), rai::epoch version = rai::epoch::epoch_0) override;
rai::block_hash block_successor (rai::transaction const &, rai::block_hash const &) override;
void block_successor_clear (rai::transaction const &, rai::block_hash const &) override;
std::unique_ptr<rai::block> block_get (rai::transaction const &, rai::block_hash const &) override;
std::unique_ptr<rai::block> block_random (rai::transaction const &) override;
std::shared_ptr<rai::block> block_get (rai::transaction const &, rai::block_hash const &) override;
std::shared_ptr<rai::block> block_random (rai::transaction const &) override;
void block_del (rai::transaction const &, rai::block_hash const &) override;
bool block_exists (rai::transaction const &, rai::block_hash const &) override;
rai::block_counts block_count (rai::transaction const &) override;
@ -367,7 +367,7 @@ public:
private:
MDB_dbi block_database (rai::block_type, rai::epoch);
template <typename T>
std::unique_ptr<rai::block> block_random (rai::transaction const &, MDB_dbi);
std::shared_ptr<rai::block> block_random (rai::transaction const &, MDB_dbi);
MDB_val block_raw_get (rai::transaction const &, rai::block_hash const &, rai::block_type &);
void block_raw_put (rai::transaction const &, MDB_dbi, rai::block_hash const &, MDB_val);
void clear (MDB_dbi);

View file

@ -608,7 +608,7 @@ void rai::network::receive_action (rai::udp_data * data_a)
if (!rai::reserved_address (data_a->endpoint, false) && data_a->endpoint != endpoint ())
{
network_message_visitor visitor (node, data_a->endpoint);
rai::message_parser parser (visitor, node.work);
rai::message_parser parser (node.block_uniquer, node.vote_uniquer, visitor, node.work);
parser.deserialize_buffer (data_a->buffer, data_a->size);
if (parser.status != rai::message_parser::parse_status::success)
{
@ -1287,7 +1287,8 @@ block_processor_thread ([this]() {
this->block_processor.process_blocks ();
}),
online_reps (*this),
stats (config.stat_config)
stats (config.stat_config),
vote_uniquer (block_uniquer)
{
wallets.observer = [this](bool active) {
observers.wallet.notify (active);
@ -1725,7 +1726,7 @@ rai::uint128_t rai::node::balance (rai::account const & account_a)
return ledger.account_balance (transaction, account_a);
}
std::unique_ptr<rai::block> rai::node::block (rai::block_hash const & hash_a)
std::shared_ptr<rai::block> rai::node::block (rai::block_hash const & hash_a)
{
auto transaction (store.tx_begin_read ());
return store.block_get (transaction, hash_a);
@ -2869,7 +2870,7 @@ void rai::active_transactions::announce_votes (std::unique_lock<std::mutex> & lo
if there are less than 100 active elections */
if (i->announcements % announcement_long == 1 && roots_size < 100)
{
std::unique_ptr<rai::block> previous (nullptr);
std::shared_ptr<rai::block> previous;
auto previous_hash (election_l->status.winner->previous ());
if (!previous_hash.is_zero ())
{

View file

@ -297,7 +297,6 @@ public:
static unsigned const broadcast_interval_ms = (rai::rai_network == rai::rai_networks::rai_test_network) ? 10 : 50;
void republish_block_batch (std::deque<std::shared_ptr<rai::block>>, unsigned = broadcast_interval_ms);
void republish (rai::block_hash const &, std::shared_ptr<std::vector<uint8_t>>, rai::endpoint);
void publish_broadcast (std::vector<rai::peer_information> &, std::unique_ptr<rai::block>);
void confirm_send (rai::confirm_ack const &, std::shared_ptr<std::vector<uint8_t>>, rai::endpoint const &);
void merge_peers (std::array<rai::endpoint, 8> const &);
void send_keepalive (rai::endpoint const &);
@ -425,7 +424,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::unique_ptr<rai::block> block (rai::block_hash const &);
std::shared_ptr<rai::block> block (rai::block_hash 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 &);
@ -472,6 +471,8 @@ public:
rai::online_reps online_reps;
rai::stat stats;
rai::keypair node_id;
rai::block_uniquer block_uniquer;
rai::vote_uniquer vote_uniquer;
static double constexpr price_max = 16.0;
static double constexpr free_cutoff = 1024.0;
static std::chrono::seconds constexpr period = std::chrono::seconds (60);

View file

@ -935,7 +935,7 @@ void rai::rpc_handler::blocks_info ()
if (source)
{
rai::block_hash source_hash (node.ledger.block_source (transaction, *block));
std::unique_ptr<rai::block> block_a (node.store.block_get (transaction, source_hash));
auto block_a (node.store.block_get (transaction, source_hash));
if (block_a != nullptr)
{
auto source_account (node.ledger.account (transaction, source_hash));
@ -2649,7 +2649,7 @@ void rai::rpc_handler::republish ()
if (sources != 0) // Republish source chain
{
rai::block_hash source (node.ledger.block_source (transaction, *block));
std::unique_ptr<rai::block> block_a (node.store.block_get (transaction, source));
auto block_a (node.store.block_get (transaction, source));
std::vector<rai::block_hash> hashes;
while (block_a != nullptr && hashes.size () < sources)
{
@ -2680,7 +2680,7 @@ void rai::rpc_handler::republish ()
if (!node.store.pending_exists (transaction, rai::pending_key (destination, hash)))
{
rai::block_hash previous (node.ledger.latest (transaction, destination));
std::unique_ptr<rai::block> block_d (node.store.block_get (transaction, previous));
auto block_d (node.store.block_get (transaction, previous));
rai::block_hash source;
std::vector<rai::block_hash> hashes;
while (block_d != nullptr && hash != source)
@ -3426,7 +3426,7 @@ void rai::rpc_handler::wallet_republish ()
{
rai::account account (i->first);
auto latest (node.ledger.latest (transaction, account));
std::unique_ptr<rai::block> block;
std::shared_ptr<rai::block> block;
std::vector<rai::block_hash> hashes;
while (!latest.is_zero () && hashes.size () < count)
{

View file

@ -139,7 +139,7 @@ int main (int argc, char * const * argv)
{
rai::account_info info (i->second);
rai::block_hash rep_block (node.node->ledger.representative_calculated (transaction, info.head));
std::unique_ptr<rai::block> block (node.node->store.block_get (transaction, rep_block));
auto block (node.node->store.block_get (transaction, rep_block));
calculated[block->representative ()] += info.balance.number ();
}
total = 0;

View file

@ -166,8 +166,8 @@ public:
virtual void block_put (rai::transaction const &, rai::block_hash const &, rai::block const &, rai::block_hash const & = rai::block_hash (0), rai::epoch version = rai::epoch::epoch_0) = 0;
virtual rai::block_hash block_successor (rai::transaction const &, rai::block_hash const &) = 0;
virtual void block_successor_clear (rai::transaction const &, rai::block_hash const &) = 0;
virtual std::unique_ptr<rai::block> block_get (rai::transaction const &, rai::block_hash const &) = 0;
virtual std::unique_ptr<rai::block> block_random (rai::transaction const &) = 0;
virtual std::shared_ptr<rai::block> block_get (rai::transaction const &, rai::block_hash const &) = 0;
virtual std::shared_ptr<rai::block> block_random (rai::transaction const &) = 0;
virtual void block_del (rai::transaction const &, rai::block_hash const &) = 0;
virtual bool block_exists (rai::transaction const &, rai::block_hash const &) = 0;
virtual rai::block_counts block_count (rai::transaction const &) = 0;

View file

@ -404,12 +404,12 @@ signature (other_a.signature)
{
}
rai::vote::vote (bool & error_a, rai::stream & stream_a)
rai::vote::vote (bool & error_a, rai::stream & stream_a, rai::block_uniquer * uniquer_a)
{
error_a = deserialize (stream_a);
error_a = deserialize (stream_a, uniquer_a);
}
rai::vote::vote (bool & error_a, rai::stream & stream_a, rai::block_type type_a)
rai::vote::vote (bool & error_a, rai::stream & stream_a, rai::block_type type_a, rai::block_uniquer * uniquer_a)
{
if (!error_a)
{
@ -435,7 +435,7 @@ rai::vote::vote (bool & error_a, rai::stream & stream_a, rai::block_type type_a)
}
else
{
std::shared_ptr<rai::block> block (rai::deserialize_block (stream_a, type_a));
std::shared_ptr<rai::block> block (rai::deserialize_block (stream_a, type_a, uniquer_a));
error_a = block == nullptr;
if (!error_a)
{
@ -511,6 +511,18 @@ rai::uint256_union rai::vote::hash () const
return result;
}
rai::uint256_union rai::vote::full_hash () const
{
rai::uint256_union result;
blake2b_state state;
blake2b_init (&state, sizeof (result.bytes));
blake2b_update (&state, hash ().bytes.data (), sizeof (hash ().bytes));
blake2b_update (&state, account.bytes.data (), sizeof (account.bytes.data ()));
blake2b_update (&state, signature.bytes.data (), sizeof (signature.bytes.data ()));
blake2b_final (&state, result.bytes.data (), sizeof (result.bytes));
return result;
}
void rai::vote::serialize (rai::stream & stream_a, rai::block_type type)
{
write (stream_a, account);
@ -556,7 +568,7 @@ void rai::vote::serialize (rai::stream & stream_a)
}
}
bool rai::vote::deserialize (rai::stream & stream_a)
bool rai::vote::deserialize (rai::stream & stream_a, rai::block_uniquer * uniquer_a)
{
auto result (read (stream_a, account));
if (!result)
@ -591,7 +603,7 @@ bool rai::vote::deserialize (rai::stream & stream_a)
}
else
{
std::shared_ptr<rai::block> block (rai::deserialize_block (stream_a, type));
std::shared_ptr<rai::block> block (rai::deserialize_block (stream_a, type, uniquer_a));
result = block == nullptr;
if (!result)
{
@ -636,14 +648,69 @@ boost::transform_iterator<rai::iterate_vote_blocks_as_hash, rai::vote_blocks_vec
return boost::transform_iterator<rai::iterate_vote_blocks_as_hash, rai::vote_blocks_vec_iter> (blocks.end (), rai::iterate_vote_blocks_as_hash ());
}
rai::vote_uniquer::vote_uniquer (rai::block_uniquer & uniquer_a) :
uniquer (uniquer_a)
{
}
std::shared_ptr<rai::vote> rai::vote_uniquer::unique (std::shared_ptr<rai::vote> vote_a)
{
auto result (vote_a);
if (result != nullptr)
{
if (!result->blocks[0].which ())
{
result->blocks[0] = uniquer.unique (boost::get<std::shared_ptr<rai::block>> (result->blocks[0]));
}
rai::uint256_union key (vote_a->full_hash ());
std::lock_guard<std::mutex> lock (mutex);
auto & existing (votes[key]);
if (auto block_l = existing.lock ())
{
result = block_l;
}
else
{
existing = vote_a;
}
for (auto i (0); i < cleanup_count; ++i)
{
rai::uint256_union random;
rai::random_pool.GenerateBlock (random.bytes.data (), random.bytes.size ());
auto existing (votes.find (random));
if (existing == votes.end ())
{
existing = votes.begin ();
}
if (existing != votes.end ())
{
if (auto block_l = existing->second.lock ())
{
// Still live
}
else
{
votes.erase (existing);
}
}
}
}
return result;
}
size_t rai::vote_uniquer::size ()
{
std::lock_guard<std::mutex> lock (mutex);
return votes.size ();
}
rai::genesis::genesis ()
{
boost::property_tree::ptree tree;
std::stringstream istream (rai::genesis_block);
boost::property_tree::read_json (istream, tree);
auto block (rai::deserialize_block_json (tree));
assert (dynamic_cast<rai::open_block *> (block.get ()) != nullptr);
open.reset (static_cast<rai::open_block *> (block.release ()));
open = rai::deserialize_block_json (tree);
assert (open != nullptr);
}
rai::block_hash rai::genesis::hash () const

View file

@ -146,17 +146,18 @@ class vote
public:
vote () = default;
vote (rai::vote const &);
vote (bool &, rai::stream &);
vote (bool &, rai::stream &, rai::block_type);
vote (bool &, rai::stream &, rai::block_uniquer * = nullptr);
vote (bool &, rai::stream &, rai::block_type, rai::block_uniquer * = nullptr);
vote (rai::account const &, rai::raw_key const &, uint64_t, std::shared_ptr<rai::block>);
vote (rai::account const &, rai::raw_key const &, uint64_t, std::vector<rai::block_hash>);
std::string hashes_string () const;
rai::uint256_union hash () const;
rai::uint256_union full_hash () const;
bool operator== (rai::vote const &) const;
bool operator!= (rai::vote const &) const;
void serialize (rai::stream &, rai::block_type);
void serialize (rai::stream &);
bool deserialize (rai::stream &);
bool deserialize (rai::stream &, rai::block_uniquer * = nullptr);
bool validate ();
boost::transform_iterator<rai::iterate_vote_blocks_as_hash, rai::vote_blocks_vec_iter> begin () const;
boost::transform_iterator<rai::iterate_vote_blocks_as_hash, rai::vote_blocks_vec_iter> end () const;
@ -171,6 +172,22 @@ public:
rai::signature signature;
static const std::string hash_prefix;
};
/**
* This class serves to find and return unique variants of a vote in order to minimize memory usage
*/
class vote_uniquer
{
public:
vote_uniquer (rai::block_uniquer &);
std::shared_ptr<rai::vote> unique (std::shared_ptr<rai::vote>);
size_t size ();
private:
rai::block_uniquer & uniquer;
std::mutex mutex;
std::unordered_map<rai::uint256_union, std::weak_ptr<rai::vote>> votes;
static unsigned constexpr cleanup_count = 2;
};
enum class vote_code
{
invalid, // Vote is not signed correctly
@ -229,6 +246,6 @@ class genesis
public:
explicit genesis ();
rai::block_hash hash () const;
std::unique_ptr<rai::open_block> open;
std::shared_ptr<rai::block> open;
};
}

View file

@ -798,7 +798,7 @@ rai::account rai::ledger::account (rai::transaction const & transaction_a, rai::
auto hash (hash_a);
rai::block_hash successor (1);
rai::block_info block_info;
std::unique_ptr<rai::block> block (store.block_get (transaction_a, hash));
auto block (store.block_get (transaction_a, hash));
while (!successor.is_zero () && block->type () != rai::block_type::state && store.block_info_get (transaction_a, successor, block_info))
{
successor = store.block_successor (transaction_a, hash);
@ -981,7 +981,7 @@ void rai::ledger::change_latest (rai::transaction const & transaction_a, rai::ac
}
}
std::unique_ptr<rai::block> rai::ledger::successor (rai::transaction const & transaction_a, rai::uint256_union const & root_a)
std::shared_ptr<rai::block> rai::ledger::successor (rai::transaction const & transaction_a, rai::uint256_union const & root_a)
{
rai::block_hash successor (0);
if (store.account_exists (transaction_a, root_a))
@ -995,7 +995,7 @@ std::unique_ptr<rai::block> rai::ledger::successor (rai::transaction const & tra
{
successor = store.block_successor (transaction_a, root_a);
}
std::unique_ptr<rai::block> result;
std::shared_ptr<rai::block> result;
if (!successor.is_zero ())
{
result = store.block_get (transaction_a, successor);
@ -1004,12 +1004,12 @@ std::unique_ptr<rai::block> rai::ledger::successor (rai::transaction const & tra
return result;
}
std::unique_ptr<rai::block> rai::ledger::forked_block (rai::transaction const & transaction_a, rai::block const & block_a)
std::shared_ptr<rai::block> rai::ledger::forked_block (rai::transaction const & transaction_a, rai::block const & block_a)
{
assert (!store.block_exists (transaction_a, block_a.hash ()));
auto root (block_a.root ());
assert (store.block_exists (transaction_a, root) || store.account_exists (transaction_a, root));
std::unique_ptr<rai::block> result (store.block_get (transaction_a, store.block_successor (transaction_a, root)));
auto result (store.block_get (transaction_a, store.block_successor (transaction_a, root)));
if (result == nullptr)
{
rai::account_info info;

View file

@ -25,8 +25,8 @@ public:
rai::uint128_t account_balance (rai::transaction const &, rai::account const &);
rai::uint128_t account_pending (rai::transaction const &, rai::account const &);
rai::uint128_t weight (rai::transaction const &, rai::account const &);
std::unique_ptr<rai::block> successor (rai::transaction const &, rai::block_hash const &);
std::unique_ptr<rai::block> forked_block (rai::transaction const &, rai::block const &);
std::shared_ptr<rai::block> successor (rai::transaction const &, rai::block_hash const &);
std::shared_ptr<rai::block> forked_block (rai::transaction const &, rai::block const &);
rai::block_hash latest (rai::transaction const &, rai::account const &);
rai::block_hash latest_root (rai::transaction const &, rai::account const &);
rai::block_hash representative (rai::transaction const &, rai::block_hash const &);