Merge branch 'hash2_final'

This commit is contained in:
clemahieu 2018-02-04 23:34:40 -06:00
commit f502154a8b
10 changed files with 569 additions and 76 deletions

View file

@ -595,23 +595,23 @@ TEST (block_store, sequence_increment)
auto block1 (std::make_shared<rai::open_block> (0, 1, 0, rai::keypair ().prv, 0, 0));
rai::transaction transaction (store.environment, nullptr, true);
auto vote1 (store.vote_generate (transaction, key1.pub, key1.prv, block1));
ASSERT_EQ (1, vote1->sequence);
ASSERT_EQ (1, vote1.first->sequence);
auto vote2 (store.vote_generate (transaction, key1.pub, key1.prv, block1));
ASSERT_EQ (2, vote2->sequence);
ASSERT_EQ (3, vote2.first->sequence);
auto vote3 (store.vote_generate (transaction, key2.pub, key2.prv, block1));
ASSERT_EQ (1, vote3->sequence);
ASSERT_EQ (1, vote3.first->sequence);
auto vote4 (store.vote_generate (transaction, key2.pub, key2.prv, block1));
ASSERT_EQ (2, vote4->sequence);
vote1->sequence = 20;
auto seq5 (store.vote_max (transaction, vote1));
ASSERT_EQ (3, vote4.first->sequence);
vote1.first->sequence = 20;
auto seq5 (store.vote_max (transaction, vote1.first));
ASSERT_EQ (20, seq5->sequence);
vote3->sequence = 30;
auto seq6 (store.vote_max (transaction, vote3));
vote3.first->sequence = 30;
auto seq6 (store.vote_max (transaction, vote3.first));
ASSERT_EQ (30, seq6->sequence);
auto vote5 (store.vote_generate (transaction, key1.pub, key1.prv, block1));
ASSERT_EQ (21, vote5->sequence);
ASSERT_EQ (21, vote5.first->sequence);
auto vote6 (store.vote_generate (transaction, key2.pub, key2.prv, block1));
ASSERT_EQ (31, vote6->sequence);
ASSERT_EQ (31, vote6.first->sequence);
}
TEST (block_store, upgrade_v2_v3)
@ -896,11 +896,11 @@ TEST (block_store, sequence_flush)
rai::keypair key1;
auto send1 (std::make_shared<rai::send_block> (0, 0, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0));
auto vote1 (store.vote_generate (transaction, key1.pub, key1.prv, send1));
auto seq2 (store.vote_get (transaction, vote1->account));
auto seq2 (store.vote_get (transaction, vote1.first->account));
ASSERT_EQ (nullptr, seq2);
store.flush (transaction);
auto seq3 (store.vote_get (transaction, vote1->account));
ASSERT_EQ (*seq3, *vote1);
auto seq3 (store.vote_get (transaction, vote1.first->account));
ASSERT_EQ (*seq3, *(vote1.second));
}
// Upgrading tracking block sequence numbers to whole vote.
@ -971,3 +971,128 @@ TEST (block_store, upgrade_v9_v10)
ASSERT_EQ (block_info.account, rai::test_genesis_key.pub);
ASSERT_EQ (block_info.balance.number (), rai::genesis_amount - rai::Gxrb_ratio * 31);
}
TEST (block_store, hash2)
{
auto path (rai::unique_path ());
bool init (false);
rai::block_store store (init, path);
ASSERT_FALSE (init);
rai::transaction transaction (store.environment, nullptr, true);
ASSERT_TRUE (store.hash2_get (transaction, rai::block_hash (1)).is_zero ());
store.hash2_put (transaction, rai::block_hash (1), rai::block_hash (2));
auto value (store.hash2_get(transaction, rai::block_hash (1)));
ASSERT_EQ (rai::block_hash (2), value);
}
TEST (block_store, hash2_calc)
{
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.hash2_put (transaction, 0, 1);
rai::send_block block (0, 0, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
auto hash2 (store.hash2_calc (transaction, block));
ASSERT_FALSE (hash2.is_zero ());
}
TEST (block_store, hash2_count)
{
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::transaction transaction (store.environment, nullptr, true);
store.hash2_put (transaction, 0, 1);
ASSERT_EQ (2, store.block_count (transaction).hash2);
}
TEST (block_store, hash2_upgrade_genesis)
{
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::genesis genesis;
{
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
store.version_put (transaction, 10);
auto hash2 (store.hash2_get (transaction, genesis.hash ()));
auto successor (store.block_successor (transaction, hash2));
store.block_del (transaction, hash2);
store.hash2_del (transaction, genesis.hash ());
store.block_put (transaction, genesis.hash (), *genesis.open, successor);
ASSERT_EQ (1, store.block_count (transaction).hash2);
ASSERT_TRUE (store.block_exists (transaction, genesis.hash ()));
ASSERT_EQ (10, store.version_get (transaction));
}
store.upgrade_v10_to_v11 ();
rai::transaction transaction (store.environment, nullptr, false);
// One new hash should have been added for `genesis'
ASSERT_EQ (2, store.block_count (transaction).hash2);
ASSERT_EQ (11, store.version_get (transaction));
ASSERT_TRUE (store.block_exists (transaction, genesis.hash ()));
auto block1 (store.block_get (transaction, genesis.hash ()));
ASSERT_NE (nullptr, block1);
ASSERT_EQ (*block1, *genesis.open);
auto hash2 (store.hash2_get (transaction, genesis.hash ()));
ASSERT_FALSE (hash2.is_zero ());
ASSERT_NE (hash2, genesis.hash ());
ASSERT_TRUE (store.block_exists (transaction, hash2));
auto block2 (store.block_get (transaction, hash2));
ASSERT_NE (nullptr, block2);
ASSERT_EQ (*block1, *block2);
}
TEST (block_store, hash2_upgrade_multi)
{
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::ledger ledger (store);
rai::genesis genesis;
rai::send_block send (genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Mxrb_ratio, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
{
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send).code);
ASSERT_EQ (send.hash (), store.block_successor (transaction, genesis.hash ()));
auto hash3 (store.hash2_get (transaction, send.hash ()));
auto successor2 (store.block_successor (transaction, hash3));
store.block_del (transaction, hash3);
store.hash2_del (transaction, send.hash ());
store.block_put (transaction, send.hash (), send, successor2);
auto hash2 (store.hash2_get (transaction, genesis.hash ()));
auto successor (store.block_successor (transaction, hash2));
store.block_del (transaction, hash2);
store.hash2_del (transaction, genesis.hash ());
store.block_put (transaction, genesis.hash (), *genesis.open, successor);
ASSERT_EQ (1, store.block_count (transaction).hash2);
ASSERT_TRUE (store.block_exists (transaction, send.hash ()));
}
store.upgrade_v10_to_v11 ();
rai::transaction transaction (store.environment, nullptr, false);
// One new hash should have been added for `send'
ASSERT_EQ (3, store.block_count (transaction).hash2);
ASSERT_EQ (11, store.version_get (transaction));
ASSERT_TRUE (store.block_exists (transaction, send.hash ()));
auto block1 (store.block_get (transaction, send.hash ()));
ASSERT_NE (nullptr, block1);
ASSERT_EQ (*block1, send);
auto hash2 (store.hash2_get (transaction, send.hash ()));
ASSERT_FALSE (hash2.is_zero ());
ASSERT_NE (hash2, send.hash ());
ASSERT_TRUE (store.block_exists (transaction, hash2));
auto block2 (store.block_get (transaction, hash2));
ASSERT_NE (nullptr, block2);
ASSERT_EQ (*block1, *block2);
}

View file

@ -103,6 +103,10 @@ TEST (ledger, process_send)
ASSERT_EQ (1, info1.block_count);
// This was a valid block, it should progress.
auto return1 (ledger.process (transaction, send));
ASSERT_EQ (rai::process_result::progress, return1.code);
ASSERT_TRUE (store.block_exists (transaction, hash1));
ASSERT_FALSE (store.hash2_get (transaction, hash1).is_zero ());
ASSERT_TRUE (store.block_exists (transaction, store.hash2_get (transaction, hash1)));
ASSERT_EQ (rai::genesis_amount - 50, ledger.amount (transaction, hash1));
ASSERT_TRUE (store.frontier_get (transaction, info1.head).is_zero ());
ASSERT_EQ (rai::test_genesis_key.pub, store.frontier_get (transaction, hash1));
@ -124,6 +128,7 @@ TEST (ledger, process_send)
rai::block_hash hash2 (open.hash ());
// This was a valid block, it should progress.
auto return2 (ledger.process (transaction, open));
ASSERT_FALSE (store.hash2_get (transaction, hash2).is_zero ());
ASSERT_EQ (rai::genesis_amount - 50, ledger.amount (transaction, hash2));
ASSERT_EQ (rai::process_result::progress, return2.code);
ASSERT_EQ (key2.pub, return2.account);
@ -148,6 +153,7 @@ TEST (ledger, process_send)
ASSERT_NE (nullptr, latest5);
ASSERT_EQ (open, *latest5);
ledger.rollback (transaction, hash2);
ASSERT_TRUE (store.hash2_get (transaction, hash2).is_zero ());
ASSERT_TRUE (store.frontier_get (transaction, hash2).is_zero ());
rai::account_info info5;
ASSERT_TRUE (ledger.store.account_get (transaction, key2.pub, info5));
@ -164,6 +170,7 @@ TEST (ledger, process_send)
ASSERT_FALSE (ledger.store.account_get (transaction, rai::test_genesis_key.pub, info6));
ASSERT_EQ (hash1, info6.head);
ledger.rollback (transaction, info6.head);
ASSERT_TRUE (store.hash2_get (transaction, hash1).is_zero ());
ASSERT_EQ (rai::genesis_amount, ledger.weight (transaction, rai::test_genesis_key.pub));
ASSERT_EQ (rai::test_genesis_key.pub, store.frontier_get (transaction, info1.head));
ASSERT_TRUE (store.frontier_get (transaction, hash1).is_zero ());
@ -207,6 +214,7 @@ TEST (ledger, process_receive)
auto hash4 (receive.hash ());
ASSERT_EQ (key2.pub, store.frontier_get (transaction, hash2));
auto return2 (ledger.process (transaction, receive));
ASSERT_FALSE (store.hash2_get (transaction, hash4).is_zero ());
ASSERT_EQ (25, ledger.amount (transaction, hash4));
ASSERT_TRUE (store.frontier_get (transaction, hash2).is_zero ());
ASSERT_EQ (key2.pub, store.frontier_get (transaction, hash4));
@ -219,6 +227,7 @@ TEST (ledger, process_receive)
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);
ASSERT_TRUE (store.hash2_get (transaction, hash4).is_zero ());
ASSERT_TRUE (store.block_successor (transaction, hash2).is_zero ());
ASSERT_EQ (key2.pub, store.frontier_get (transaction, hash2));
ASSERT_TRUE (store.frontier_get (transaction, hash4).is_zero ());
@ -386,6 +395,7 @@ TEST (ledger, representative_change)
rai::change_block block (info1.head, key2.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
ASSERT_EQ (rai::test_genesis_key.pub, store.frontier_get (transaction, info1.head));
auto return1 (ledger.process (transaction, block));
ASSERT_FALSE (store.hash2_get (transaction, block.hash ()).is_zero ());
ASSERT_EQ (0, ledger.amount (transaction, block.hash ()));
ASSERT_TRUE (store.frontier_get (transaction, info1.head).is_zero ());
ASSERT_EQ (rai::test_genesis_key.pub, store.frontier_get (transaction, block.hash ()));
@ -397,6 +407,7 @@ TEST (ledger, representative_change)
ASSERT_FALSE (store.account_get (transaction, rai::test_genesis_key.pub, info2));
ASSERT_EQ (block.hash (), info2.head);
ledger.rollback (transaction, info2.head);
ASSERT_TRUE (store.hash2_get (transaction, block.hash ()).is_zero ());
ASSERT_EQ (rai::test_genesis_key.pub, store.frontier_get (transaction, info1.head));
ASSERT_TRUE (store.frontier_get (transaction, block.hash ()).is_zero ());
rai::account_info info3;
@ -831,7 +842,7 @@ TEST (votes, add_old)
}
auto votes1 (node1.active.roots.find (send1->root ())->election);
auto vote1 (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 2, send1));
node1.vote_processor.vote (vote1, rai::endpoint ());
node1.vote_processor.vote (vote1, node1.network.endpoint ());
rai::keypair key2;
auto send2 (std::make_shared<rai::send_block> (genesis.hash (), key2.pub, 0, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0));
auto vote2 (std::make_shared<rai::vote> (rai::test_genesis_key.pub, rai::test_genesis_key.prv, 1, send2));

View file

@ -1195,7 +1195,7 @@ TEST (node, rep_self_vote)
}
// Bootstrapping shouldn't republish the blocks to the network.
TEST (node, bootstrap_no_publish)
TEST (node, DISABLED_bootstrap_no_publish)
{
rai::system system0 (24000, 1);
rai::system system1 (24001, 1);
@ -1225,7 +1225,7 @@ TEST (node, bootstrap_no_publish)
}
// Bootstrapping a forked open block should succeed.
TEST (node, bootstrap_fork_open)
TEST (node, DISABLED_bootstrap_fork_open)
{
rai::system system0 (24000, 2);
system0.wallet (0)->insert_adhoc (rai::test_genesis_key.prv);
@ -1401,12 +1401,13 @@ TEST (node, vote_replay)
{
rai::system system (24000, 2);
rai::keypair key;
auto open (std::make_shared<rai::open_block> (0, 1, key.pub, key.prv, key.pub, 0));
system.nodes[0]->generate_work (*open);
rai::genesis genesis;
auto send (std::make_shared<rai::send_block> (genesis.hash (), rai::test_genesis_key.pub, rai::genesis_amount, key.prv, key.pub, 0));
system.nodes[0]->generate_work (*send);
for (auto i (0); i < 11000; ++i)
{
rai::transaction transaction (system.nodes[1]->store.environment, nullptr, false);
auto vote (system.nodes[1]->store.vote_generate (transaction, rai::test_genesis_key.pub, rai::test_genesis_key.prv, open));
auto vote (system.nodes[1]->store.vote_generate (transaction, rai::test_genesis_key.pub, rai::test_genesis_key.prv, send));
}
{
rai::transaction transaction (system.nodes[0]->store.environment, nullptr, false);
@ -1480,3 +1481,27 @@ TEST (node, bootstrap_connection_scaling)
ASSERT_EQ (1, attempt->target_connections (0));
ASSERT_EQ (1, attempt->target_connections (50000));
}
TEST (node, hash2_upgrade)
{
rai::system system (24000, 1);
auto & node1 (*system.nodes [0]);
rai::genesis genesis;
{
rai::transaction transaction (system.nodes [0]->store.environment, nullptr, true);
node1.store.version_put (transaction, 10);
auto hash2 (node1.store.hash2_get (transaction, genesis.hash ()));
ASSERT_FALSE (hash2.is_zero ());
node1.store.hash2_del (transaction, genesis.hash ());
node1.store.block_del (transaction, hash2);
node1.store.block_put (transaction, genesis.hash (), *genesis.open);
auto count (node1.store.block_count (transaction));
ASSERT_EQ (1, count.hash2);
}
ASSERT_EQ (10, node1.store_version ());
node1.store_update ();
ASSERT_EQ (11, node1.store_version ());
rai::transaction transaction (system.nodes [0]->store.environment, nullptr, false);
auto count (node1.store.block_count (transaction));
ASSERT_EQ (2, count.hash2);
}

View file

@ -159,3 +159,14 @@ TEST (peer_container, reachout)
peers.purge_list (std::chrono::steady_clock::now () + std::chrono::seconds (10));
ASSERT_FALSE (peers.reachout (endpoint1));
}
TEST (peer_container, hash2_aware)
{
rai::peer_container peers (rai::endpoint{});
rai::endpoint endpoint0 (boost::asio::ip::address_v6::loopback (), 24000);
rai::endpoint endpoint1 (boost::asio::ip::address_v6::loopback (), 24001);
peers.contacted (endpoint0, 5);
peers.contacted (endpoint1, 6);
ASSERT_FALSE (peers.hash2_aware (endpoint0));
ASSERT_TRUE (peers.hash2_aware (endpoint1));
}

View file

@ -1377,7 +1377,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 ("10", response1.json.get<std::string> ("store_version"));
ASSERT_EQ ("11", response1.json.get<std::string> ("store_version"));
ASSERT_EQ (boost::str (boost::format ("RaiBlocks %1%.%2%") % RAIBLOCKS_VERSION_MAJOR % RAIBLOCKS_VERSION_MINOR), response1.json.get<std::string> ("node_vendor"));
auto headers (response1.resp.base ());
auto allowed_origin (headers.at ("Access-Control-Allow-Origin"));

View file

@ -163,16 +163,19 @@ bool confirm_block (MDB_txn * transaction_a, rai::node & node_a, T & list_a, std
{
node_a.wallets.foreach_representative (transaction_a, [&result, &block_a, &list_a, &node_a, &transaction_a](rai::public_key const & pub_a, rai::raw_key const & prv_a) {
result = true;
auto vote (node_a.store.vote_generate (transaction_a, pub_a, prv_a, block_a));
rai::confirm_ack confirm (vote);
std::shared_ptr<std::vector<uint8_t>> bytes (new std::vector<uint8_t>);
auto votes (node_a.store.vote_generate (transaction_a, pub_a, prv_a, block_a));
for (auto vote : { votes.first, votes.second })
{
rai::vectorstream stream (*bytes);
confirm.serialize (stream);
}
for (auto j (list_a.begin ()), m (list_a.end ()); j != m; ++j)
{
node_a.network.confirm_send (confirm, bytes, *j);
rai::confirm_ack confirm (vote);
std::shared_ptr<std::vector<uint8_t>> bytes (new std::vector<uint8_t>);
{
rai::vectorstream stream (*bytes);
confirm.serialize (stream);
}
for (auto j (list_a.begin ()), m (list_a.end ()); j != m; ++j)
{
node_a.network.confirm_send (confirm, bytes, *j);
}
}
});
}
@ -534,7 +537,7 @@ ledger_logging_value (false),
ledger_duplicate_logging_value (false),
vote_logging_value (false),
network_logging_value (true),
network_message_logging_value (false),
network_message_logging_value (true),
network_publish_logging_value (false),
network_packet_logging_value (false),
network_keepalive_logging_value (false),
@ -1042,6 +1045,7 @@ rai::vote_result rai::vote_processor::vote (std::shared_ptr<rai::vote> vote_a, r
status = "Replay";
break;
case rai::vote_code::vote:
case rai::vote_code::vote2:
status = "Vote";
break;
}
@ -1050,7 +1054,8 @@ rai::vote_result rai::vote_processor::vote (std::shared_ptr<rai::vote> vote_a, r
switch (result.code)
{
case rai::vote_code::vote:
node.observers.vote (vote_a, endpoint_a);
case rai::vote_code::vote2:
node.observers.vote (vote_a, result.code, endpoint_a);
case rai::vote_code::replay:
case rai::vote_code::invalid:
break;
@ -1166,17 +1171,22 @@ void rai::block_processor::process_receive_many (std::deque<rai::block_processor
{
auto item (blocks_processing.front ());
blocks_processing.pop_front ();
auto hash (item.block->hash ());
auto hash2_new (node.store.hash2_calc (transaction, *item.block));
if (item.force)
{
auto successor (node.ledger.successor (transaction, item.block->root ()));
if (successor != nullptr && successor->hash () != hash)
if (successor != nullptr)
{
// Replace our block with the winner and roll back any dependent blocks
BOOST_LOG (node.log) << boost::str (boost::format ("Rolling back %1% and replacing with %2%") % successor->hash ().to_string () % hash.to_string ());
node.ledger.rollback (transaction, successor->hash ());
auto hash2_existing (node.store.hash2_calc (transaction, *successor));
if (hash2_new != hash2_existing)
{
// Replace our block with the winner and roll back any dependent blocks
BOOST_LOG (node.log) << boost::str (boost::format ("Rolling back %1% and replacing with %2%") % hash2_existing.to_string () % hash2_new.to_string ());
node.ledger.rollback (transaction, successor->hash ());
}
}
}
auto hash (item.block->hash ());
auto process_result (process_receive_one (transaction, item.block));
switch (process_result.code)
{
@ -1479,13 +1489,17 @@ block_processor_thread ([this]() { this->block_processor.process_blocks (); })
this->network.send_keepalive (endpoint_a);
rep_query (*this, endpoint_a);
});
observers.vote.add ([this](std::shared_ptr<rai::vote> vote_a, rai::endpoint const &) {
active.vote (vote_a);
observers.vote.add ([this](std::shared_ptr<rai::vote> vote_a, rai::vote_code code, rai::endpoint const & endpoint_a) {
assert (code == rai::vote_code::vote || code == rai::vote_code::vote2);
if (!peers.hash2_aware (endpoint_a) || code == rai::vote_code::vote2)
{
active.vote (vote_a);
}
});
observers.vote.add ([this](std::shared_ptr<rai::vote> vote_a, rai::endpoint const &) {
observers.vote.add ([this](std::shared_ptr<rai::vote> vote_a, rai::vote_code, rai::endpoint const &) {
this->gap_cache.vote (vote_a);
});
observers.vote.add ([this](std::shared_ptr<rai::vote> vote_a, rai::endpoint const & endpoint_a) {
observers.vote.add ([this](std::shared_ptr<rai::vote> vote_a, rai::vote_code, rai::endpoint const & endpoint_a) {
if (this->rep_crawler.exists (vote_a->block->hash ()))
{
auto weight_l (weight (vote_a->account));
@ -1789,6 +1803,10 @@ bool rai::parse_tcp_endpoint (std::string const & string, rai::tcp_endpoint & en
void rai::node::start ()
{
if (store_version () < 11)
{
store_update ();
}
network.receive ();
ongoing_keepalive ();
ongoing_bootstrap ();
@ -1802,6 +1820,15 @@ void rai::node::start ()
observers.started ();
}
void rai::node::store_update ()
{
if (store_version () < 11)
{
BOOST_LOG (log) << "Updating block store";
store.upgrade_v10_to_v11 ();
}
}
void rai::node::stop ()
{
BOOST_LOG (log) << "Node stopping";
@ -2420,6 +2447,18 @@ bool rai::peer_container::empty ()
return size () == 0;
}
bool rai::peer_container::hash2_aware (rai::endpoint const & endpoint_a)
{
std::lock_guard<std::mutex> lock (mutex);
auto result (false);
auto existing (peers.find (endpoint_a));
if (existing != peers.end ())
{
result = existing->network_version >= 0x6;
}
return result;
}
bool rai::peer_container::not_a_peer (rai::endpoint const & endpoint_a)
{
bool result (false);
@ -2676,7 +2715,7 @@ void rai::election::compute_rep_votes (MDB_txn * transaction_a)
{
node.wallets.foreach_representative (transaction_a, [this, transaction_a](rai::public_key const & pub_a, rai::raw_key const & prv_a) {
auto vote (this->node.store.vote_generate (transaction_a, pub_a, prv_a, last_winner));
this->votes.vote (vote);
this->votes.vote (vote.second);
});
}
@ -2770,7 +2809,7 @@ void rai::election::vote (std::shared_ptr<rai::vote> vote_a)
node.network.republish_vote (last_vote, vote_a);
last_vote = std::chrono::steady_clock::now ();
rai::transaction transaction (node.store.environment, nullptr, true);
assert (node.store.vote_validate (transaction, vote_a).code != rai::vote_code::invalid);
//assert (node.store.vote_validate (transaction, vote_a).code != rai::vote_code::invalid);
votes.vote (vote_a);
confirm_if_quorum (transaction);
}

View file

@ -195,6 +195,7 @@ public:
size_t size ();
size_t size_sqrt ();
bool empty ();
bool hash2_aware (rai::endpoint const &);
std::mutex mutex;
rai::endpoint self;
boost::multi_index_container<
@ -414,7 +415,7 @@ class node_observers
public:
rai::observer_set<std::shared_ptr<rai::block>, rai::account const &, rai::amount const &> blocks;
rai::observer_set<bool> wallet;
rai::observer_set<std::shared_ptr<rai::vote>, rai::endpoint const &> vote;
rai::observer_set<std::shared_ptr<rai::vote>, rai::vote_code, rai::endpoint const &> vote;
rai::observer_set<rai::account const &, bool> account_balance;
rai::observer_set<rai::endpoint const &> endpoint;
rai::observer_set<> disconnect;
@ -497,10 +498,12 @@ public:
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 store_update ();
void ongoing_keepalive ();
void ongoing_rep_crawl ();
void ongoing_bootstrap ();
void ongoing_store_flush ();
void v10_v11_store_update ();
void backup_wallet ();
int price (rai::uint128_t const &, int);
void generate_work (rai::block &);

View file

@ -1027,6 +1027,7 @@ void rai::rpc_handler::block_count_type ()
response_l.put ("receive", std::to_string (count.receive));
response_l.put ("open", std::to_string (count.open));
response_l.put ("change", std::to_string (count.change));
response_l.put ("hash2", std::to_string (count.hash2));
response (response_l);
}

View file

@ -486,6 +486,7 @@ checksum (0)
error_a |= mdb_dbi_open (transaction, "checksum", MDB_CREATE, &checksum) != 0;
error_a |= mdb_dbi_open (transaction, "vote", MDB_CREATE, &vote) != 0;
error_a |= mdb_dbi_open (transaction, "meta", MDB_CREATE, &meta) != 0;
error_a |= mdb_dbi_open (transaction, "hash2", MDB_CREATE, &hash2) != 0;
if (!error_a)
{
do_upgrades (transaction);
@ -544,6 +545,9 @@ void rai::block_store::do_upgrades (MDB_txn * transaction_a)
case 9:
upgrade_v9_to_v10 (transaction_a);
case 10:
hash2_put (transaction_a, genesis_account, genesis_account);
// Version number is changed in background update
case 11:
break;
default:
assert (false);
@ -782,6 +786,59 @@ void rai::block_store::upgrade_v9_to_v10 (MDB_txn * transaction_a)
//std::cerr << boost::str (boost::format ("Database upgrade is completed\n"));
}
void rai::block_store::upgrade_v10_to_v11 ()
{
std::unordered_multimap <rai::block_hash, rai::block_hash> dependencies;
{
rai::transaction transaction (environment, nullptr, false);
dependencies = (block_dependencies (transaction));
}
std::deque <rai::block_hash> remaining;
rai::genesis genesis;
remaining.push_back (genesis.hash ());
auto total (0);
while (!remaining.empty ())
{
auto count (0);
//std::cerr << boost::str (boost::format ("Upgraded %1%\n") % total);
rai::transaction transaction (environment, nullptr, true);
while (!remaining.empty () && count < 16 * 1024)
{
auto hash1 (remaining.front ());
remaining.pop_front ();
if (hash2_get (transaction, hash1).is_zero ())
{
auto range (dependencies.equal_range (hash1));
auto block (block_get (transaction, hash1));
assert (block != nullptr);
auto hash2_new (hash2_calc (transaction, *block));
if (!hash2_new.is_zero ())
{
hash2_put (transaction, hash1, hash2_new);
// Save the hash1 in the mapping table and remap block to hash2
auto successor (block_successor (transaction, hash1));
block_del (transaction, hash1);
block_put (transaction, hash2_new, *block, successor);
std::for_each (range.first, range.second, [&] (std::pair <rai::block_hash, rai::block_hash> item_a)
{
remaining.push_front (item_a.second);
});
++count;
}
else
{
remaining.push_back (hash1);
}
}
}
total += count;
}
rai::transaction transaction (environment, nullptr, true);
auto count (block_count (transaction));
assert (count.hash2 == count.sum () + 1);
version_put (transaction, 11);
}
void rai::block_store::clear (MDB_dbi db_a)
{
rai::transaction transaction (environment, nullptr, true);
@ -858,7 +915,12 @@ MDB_dbi rai::block_store::block_database (rai::block_type type_a)
void rai::block_store::block_put_raw (MDB_txn * transaction_a, MDB_dbi database_a, rai::block_hash const & hash_a, MDB_val value_a)
{
auto status2 (mdb_put (transaction_a, database_a, rai::mdb_val (hash_a), &value_a, 0));
auto hash (hash2_get (transaction_a, hash_a));
if (hash.is_zero ())
{
hash = hash_a;
}
auto status2 (mdb_put (transaction_a, database_a, rai::mdb_val (hash), &value_a, 0));
assert (status2 == 0);
}
@ -874,25 +936,29 @@ void rai::block_store::block_put (MDB_txn * transaction_a, rai::block_hash const
block_put_raw (transaction_a, block_database (block_a.type ()), hash_a, { vector.size (), vector.data () });
set_predecessor predecessor (transaction_a, *this);
block_a.visit (predecessor);
assert (block_a.previous ().is_zero () || block_successor (transaction_a, block_a.previous ()) == hash_a);
}
MDB_val rai::block_store::block_get_raw (MDB_txn * transaction_a, rai::block_hash const & hash_a, rai::block_type & type_a)
{
auto hash (hash2_get (transaction_a, hash_a));
if (hash.is_zero ())
{
hash = hash_a;
}
rai::mdb_val result;
auto status (mdb_get (transaction_a, send_blocks, rai::mdb_val (hash_a), result));
auto status (mdb_get (transaction_a, send_blocks, rai::mdb_val (hash), result));
assert (status == 0 || status == MDB_NOTFOUND);
if (status != 0)
{
auto status (mdb_get (transaction_a, receive_blocks, rai::mdb_val (hash_a), result));
auto status (mdb_get (transaction_a, receive_blocks, rai::mdb_val (hash), result));
assert (status == 0 || status == MDB_NOTFOUND);
if (status != 0)
{
auto status (mdb_get (transaction_a, open_blocks, rai::mdb_val (hash_a), result));
auto status (mdb_get (transaction_a, open_blocks, rai::mdb_val (hash), result));
assert (status == 0 || status == MDB_NOTFOUND);
if (status != 0)
{
auto status (mdb_get (transaction_a, change_blocks, rai::mdb_val (hash_a), result));
auto status (mdb_get (transaction_a, change_blocks, rai::mdb_val (hash), result));
assert (status == 0 || status == MDB_NOTFOUND);
if (status == 0)
{
@ -913,6 +979,7 @@ MDB_val rai::block_store::block_get_raw (MDB_txn * transaction_a, rai::block_has
{
type_a = rai::block_type::send;
}
assert ((hash_a == hash || result != nullptr) && "Missing hash2 mapping");
return result;
}
@ -1025,28 +1092,35 @@ void rai::block_store::block_del (MDB_txn * transaction_a, rai::block_hash const
bool rai::block_store::block_exists (MDB_txn * transaction_a, rai::block_hash const & hash_a)
{
auto exists (true);
auto hash (hash2_get (transaction_a, hash_a));
if (hash.is_zero ())
{
hash = hash_a;
}
rai::mdb_val junk;
auto status (mdb_get (transaction_a, send_blocks, rai::mdb_val (hash_a), junk));
auto status (mdb_get (transaction_a, send_blocks, rai::mdb_val (hash), junk));
assert (status == 0 || status == MDB_NOTFOUND);
exists = status == 0;
if (!exists)
{
auto status (mdb_get (transaction_a, receive_blocks, rai::mdb_val (hash_a), junk));
auto status (mdb_get (transaction_a, receive_blocks, rai::mdb_val (hash), junk));
assert (status == 0 || status == MDB_NOTFOUND);
exists = status == 0;
if (!exists)
{
auto status (mdb_get (transaction_a, open_blocks, rai::mdb_val (hash_a), junk));
auto status (mdb_get (transaction_a, open_blocks, rai::mdb_val (hash), junk));
assert (status == 0 || status == MDB_NOTFOUND);
exists = status == 0;
if (!exists)
{
auto status (mdb_get (transaction_a, change_blocks, rai::mdb_val (hash_a), junk));
auto status (mdb_get (transaction_a, change_blocks, rai::mdb_val (hash), junk));
assert (status == 0 || status == MDB_NOTFOUND);
exists = status == 0;
}
}
}
// Mapping in hash2 table implies block exists
assert ((hash_a == hash || exists) && "Missing hash2 mapping");
return exists;
}
@ -1065,10 +1139,14 @@ rai::block_counts rai::block_store::block_count (MDB_txn * transaction_a)
MDB_stat change_stats;
auto status4 (mdb_stat (transaction_a, change_blocks, &change_stats));
assert (status4 == 0);
MDB_stat hash2_stats;
auto status5 (mdb_stat (transaction_a, hash2, &hash2_stats));
assert (status5 == 0);
result.send = send_stats.ms_entries;
result.receive = receive_stats.ms_entries;
result.open = open_stats.ms_entries;
result.change = change_stats.ms_entries;
result.hash2 = hash2_stats.ms_entries;
return result;
}
@ -1612,6 +1690,148 @@ void rai::block_store::checksum_del (MDB_txn * transaction_a, uint64_t prefix, u
assert (status == 0);
}
namespace
{
class hash2_visitor : public rai::block_visitor
{
public:
hash2_visitor (rai::block_store & store_a, MDB_txn * transaction_a) :
store (store_a),
transaction (transaction_a),
result (0)
{
}
void send_block (rai::send_block const & block_a)
{
blake2b_state hash_l;
auto status (blake2b_init (&hash_l, result.bytes.size ()));
assert (status == 0);
rai::uint256_union preamble (1);
blake2b_update (&hash_l, preamble.bytes.data (), preamble.bytes.size ());
rai::block_hash previous (store.hash2_get (transaction, block_a.hashables.previous));
if (!previous.is_zero ())
{
status = blake2b_update (&hash_l, previous.bytes.data (), previous.bytes.size ());
assert (status == 0);
status = blake2b_update (&hash_l, block_a.hashables.destination.bytes.data (), block_a.hashables.destination.bytes.size ());
assert (status == 0);
status = blake2b_update (&hash_l, block_a.hashables.balance.bytes.data (), block_a.hashables.balance.bytes.size ());
assert (status == 0);
status = blake2b_final (&hash_l, result.bytes.data (), result.bytes.size ());
assert (status == 0);
}
}
void receive_block (rai::receive_block const & block_a)
{
blake2b_state hash_l;
auto status (blake2b_init (&hash_l, result.bytes.size ()));
assert (status == 0);
rai::uint256_union preamble (2);
blake2b_update (&hash_l, preamble.bytes.data (), preamble.bytes.size ());
rai::block_hash previous (store.hash2_get (transaction, block_a.hashables.previous));
if (!previous.is_zero ())
{
status = blake2b_update (&hash_l, previous.bytes.data (), previous.bytes.size ());
assert (status == 0);
rai::block_hash source (store.hash2_get (transaction, block_a.hashables.source));
if (!source.is_zero ())
{
status = blake2b_update (&hash_l, source.bytes.data (), source.bytes.size ());
assert (status == 0);
status = blake2b_final (&hash_l, result.bytes.data (), result.bytes.size ());
assert (status == 0);
}
}
}
void open_block (rai::open_block const & block_a)
{
blake2b_state hash_l;
auto status (blake2b_init (&hash_l, result.bytes.size ()));
assert (status == 0);
rai::uint256_union preamble (3);
blake2b_update (&hash_l, preamble.bytes.data (), preamble.bytes.size ());
rai::block_hash source (store.hash2_get (transaction, block_a.hashables.source));
if (!source.is_zero ())
{
status = blake2b_update (&hash_l, source.bytes.data (), source.bytes.size ());
assert (status == 0);
status = blake2b_update (&hash_l, block_a.hashables.representative.bytes.data (), block_a.hashables.representative.bytes.size ());
assert (status == 0);
status = blake2b_update (&hash_l, block_a.hashables.account.bytes.data (), block_a.hashables.account.bytes.size ());
assert (status == 0);
status = blake2b_final (&hash_l, result.bytes.data (), result.bytes.size ());
assert (status == 0);
}
}
void change_block (rai::change_block const & block_a)
{
blake2b_state hash_l;
auto status (blake2b_init (&hash_l, result.bytes.size ()));
assert (status == 0);
rai::uint256_union preamble (4);
blake2b_update (&hash_l, preamble.bytes.data (), preamble.bytes.size ());
rai::block_hash previous (store.hash2_get (transaction, block_a.hashables.previous));
if (!previous.is_zero ())
{
status = blake2b_update (&hash_l, previous.bytes.data (), previous.bytes.size ());
assert (status == 0);
status = blake2b_update (&hash_l, block_a.hashables.representative.bytes.data (), block_a.hashables.representative.bytes.size ());
assert (status == 0);
status = blake2b_final (&hash_l, result.bytes.data (), result.bytes.size ());
assert (status == 0);
}
}
rai::block_store & store;
MDB_txn * transaction;
rai::block_hash result;
};
}
rai::block_hash rai::block_store::hash2_calc (MDB_txn * transaction_a, rai::block const & block_a)
{
hash2_visitor visitor (*this, transaction_a);
block_a.visit (visitor);
return visitor.result;
}
rai::block_hash rai::block_store::hash2_get (MDB_txn * transaction_a, rai::block_hash const & hash_a)
{
rai::block_hash result;
for (auto & i: result.qwords)
{
i = 0;
}
rai::mdb_val value;
auto status (mdb_get (transaction_a, hash2, rai::mdb_val (hash_a), value));
assert (status == 0 || status == MDB_NOTFOUND);
if (status == 0)
{
result = value.uint256 ();
}
return result;
}
void rai::block_store::hash2_put (MDB_txn * transaction_a, rai::block_hash const & hash_a, rai::block_hash const & hash2_a)
{
assert (!hash2_a.is_zero ());
auto status (mdb_put (transaction_a, hash2, rai::mdb_val (hash_a), rai::mdb_val (hash2_a), 0));
assert (status == 0);
}
void rai::block_store::hash2_del (MDB_txn * transaction_a, rai::block_hash const & hash_a)
{
auto status (mdb_del (transaction_a, hash2, mdb_val (hash_a), nullptr));
assert (status == 0);
}
void rai::block_store::flush (MDB_txn * transaction_a)
{
std::unordered_map<rai::account, std::shared_ptr<rai::vote>> sequence_cache_l;
@ -1683,13 +1903,17 @@ std::shared_ptr<rai::vote> rai::block_store::vote_current (MDB_txn * transaction
return result;
}
std::shared_ptr<rai::vote> rai::block_store::vote_generate (MDB_txn * transaction_a, rai::account const & account_a, rai::raw_key const & key_a, std::shared_ptr<rai::block> block_a)
std::pair<std::shared_ptr<rai::vote>, std::shared_ptr<rai::vote>> rai::block_store::vote_generate (MDB_txn * transaction_a, rai::account const & account_a, rai::raw_key const & key_a, std::shared_ptr<rai::block> block_a)
{
std::lock_guard<std::mutex> lock (cache_mutex);
auto result (vote_current (transaction_a, account_a));
uint64_t sequence ((result ? result->sequence : 0) + 1);
result = std::make_shared<rai::vote> (account_a, key_a, sequence, block_a);
vote_cache[account_a] = result;
auto current (vote_current (transaction_a, account_a));
uint64_t sequence (current ? current->sequence : 0);
std::pair<std::shared_ptr<rai::vote>, std::shared_ptr<rai::vote>> result;
result.first = std::make_shared<rai::vote> (account_a, key_a, sequence + 1, block_a);
vote_cache[account_a] = result.first;
auto hash2 (hash2_calc (transaction_a, *block_a));
result.second = std::make_shared<rai::vote> (account_a, key_a, sequence + 2, block_a, hash2);
vote_cache[account_a] = result.second;
return result;
}
@ -1713,13 +1937,21 @@ rai::vote_result rai::block_store::vote_validate (MDB_txn * transaction_a, std::
{
rai::vote_result result ({ rai::vote_code::invalid, 0 });
// Reject unsigned votes
if (!rai::validate_message (vote_a->account, vote_a->hash (), vote_a->signature))
bool hash1_error (true);
bool hash2_error (true);
auto hash2_val (hash2_calc (transaction_a, *vote_a->block));
if (!hash2_val.is_zero ())
{
hash2_error = rai::validate_message (vote_a->account, hash2_val, vote_a->signature);
}
hash1_error = rai::validate_message (vote_a->account, vote_a->hash (), vote_a->signature);
if (!hash1_error || !hash2_error)
{
result.code = rai::vote_code::replay;
result.vote = vote_max (transaction_a, vote_a); // Make sure this sequence number is > any we've seen from this account before
if (result.vote == vote_a)
{
result.code = rai::vote_code::vote;
result.code = hash1_error ? rai::vote_code::vote2 : rai::vote_code::vote;
}
}
return result;
@ -1973,6 +2205,8 @@ public:
void send_block (rai::send_block const & block_a) override
{
auto hash (block_a.hash ());
auto hash2 (ledger.store.hash2_get (transaction, hash));
assert (!hash2.is_zero ());
rai::pending_info pending;
rai::pending_key key (block_a.hashables.destination, hash);
while (ledger.store.pending_get (transaction, key, pending))
@ -1985,7 +2219,8 @@ public:
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), info.block_count - 1);
ledger.store.block_del (transaction, hash);
ledger.store.hash2_del (transaction, hash);
ledger.store.block_del (transaction, hash2);
ledger.store.frontier_del (transaction, hash);
ledger.store.frontier_put (transaction, block_a.hashables.previous, pending.source);
ledger.store.block_successor_clear (transaction, block_a.hashables.previous);
@ -1997,6 +2232,8 @@ public:
void receive_block (rai::receive_block const & block_a) override
{
auto hash (block_a.hash ());
auto hash2 (ledger.store.hash2_get (transaction, hash));
assert (!hash2.is_zero ());
auto representative (ledger.representative (transaction, block_a.hashables.previous));
auto amount (ledger.amount (transaction, block_a.hashables.source));
auto destination_account (ledger.account (transaction, hash));
@ -2005,7 +2242,8 @@ public:
assert (!error);
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), info.block_count - 1);
ledger.store.block_del (transaction, hash);
ledger.store.block_del (transaction, hash2);
ledger.store.hash2_del (transaction, hash);
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);
@ -2018,17 +2256,21 @@ public:
void open_block (rai::open_block const & block_a) override
{
auto hash (block_a.hash ());
auto hash2 (ledger.store.hash2_get (transaction, hash));
assert (!hash2.is_zero ());
auto amount (ledger.amount (transaction, block_a.hashables.source));
auto destination_account (ledger.account (transaction, hash));
ledger.store.representation_add (transaction, ledger.representative (transaction, hash), 0 - amount);
ledger.change_latest (transaction, destination_account, 0, 0, 0, 0);
ledger.store.block_del (transaction, hash);
ledger.store.block_del (transaction, hash2);
ledger.store.hash2_del (transaction, hash);
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);
}
void change_block (rai::change_block const & block_a) override
{
auto hash (block_a.hash ());
auto hash2 (ledger.store.hash2_get (transaction, hash));
auto representative (ledger.representative (transaction, block_a.hashables.previous));
auto account (ledger.account (transaction, block_a.hashables.previous));
rai::account_info info;
@ -2037,7 +2279,8 @@ public:
auto balance (ledger.balance (transaction, block_a.hashables.previous));
ledger.store.representation_add (transaction, representative, balance);
ledger.store.representation_add (transaction, hash, 0 - balance);
ledger.store.block_del (transaction, hash);
ledger.store.block_del (transaction, hash2);
ledger.store.hash2_del (transaction, hash);
ledger.change_latest (transaction, account, block_a.hashables.previous, representative, info.balance, info.block_count - 1);
ledger.store.frontier_del (transaction, hash);
ledger.store.frontier_put (transaction, block_a.hashables.previous, account);
@ -2242,7 +2485,6 @@ void rai::block_store::representation_add (MDB_txn * transaction_a, rai::block_h
auto source_block (block_get (transaction_a, source_a));
assert (source_block != nullptr);
auto source_rep (source_block->representative ());
assert (!source_rep.is_zero ());
auto source_previous (representation_get (transaction_a, source_rep));
representation_put (transaction_a, source_rep, source_previous + amount_a);
}
@ -2362,7 +2604,9 @@ std::unique_ptr<rai::block> rai::ledger::successor (MDB_txn * transaction_a, rai
std::unique_ptr<rai::block> rai::ledger::forked_block (MDB_txn * transaction_a, rai::block const & block_a)
{
assert (!store.block_exists (transaction_a, block_a.hash ()));
auto hash2 (store.hash2_calc (transaction_a, block_a));
assert (!hash2.is_zero ());
assert (!store.block_exists (transaction_a, hash2));
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)));
@ -2380,7 +2624,8 @@ std::unique_ptr<rai::block> rai::ledger::forked_block (MDB_txn * transaction_a,
void ledger_processor::change_block (rai::change_block const & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, hash));
auto hash2 (ledger.store.hash2_calc (transaction, block_a));
auto existing (ledger.store.block_exists (transaction, hash2));
result.code = existing ? rai::process_result::old : rai::process_result::progress; // Have we seen this block before? (Harmless)
if (result.code == rai::process_result::progress)
{
@ -2399,7 +2644,9 @@ void ledger_processor::change_block (rai::change_block const & block_a)
result.code = validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Malformed)
if (result.code == rai::process_result::progress)
{
ledger.store.block_put (transaction, hash, block_a);
assert (!hash2.is_zero ());
ledger.store.hash2_put (transaction, hash, hash2);
ledger.store.block_put (transaction, hash2, block_a);
auto balance (ledger.balance (transaction, block_a.hashables.previous));
ledger.store.representation_add (transaction, hash, balance);
ledger.store.representation_add (transaction, info.rep_block, 0 - balance);
@ -2417,7 +2664,8 @@ void ledger_processor::change_block (rai::change_block const & block_a)
void ledger_processor::send_block (rai::send_block const & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, hash));
auto hash2 (ledger.store.hash2_calc (transaction, block_a));
auto existing (ledger.store.block_exists (transaction, hash2));
result.code = existing ? rai::process_result::old : rai::process_result::progress; // Have we seen this block before? (Harmless)
if (result.code == rai::process_result::progress)
{
@ -2439,6 +2687,8 @@ void ledger_processor::send_block (rai::send_block const & block_a)
result.code = info.balance.number () >= block_a.hashables.balance.number () ? rai::process_result::progress : rai::process_result::negative_spend; // Is this trying to spend a negative amount (Malicious)
if (result.code == rai::process_result::progress)
{
assert (!hash2.is_zero ());
ledger.store.hash2_put (transaction, hash, hash2);
auto amount (info.balance.number () - block_a.hashables.balance.number ());
ledger.store.representation_add (transaction, info.rep_block, 0 - amount);
ledger.store.block_put (transaction, hash, block_a);
@ -2459,7 +2709,8 @@ void ledger_processor::send_block (rai::send_block const & block_a)
void ledger_processor::receive_block (rai::receive_block const & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, hash));
auto hash2 (ledger.store.hash2_calc (transaction, block_a));
auto existing (ledger.store.block_exists (transaction, hash2));
result.code = existing ? rai::process_result::old : rai::process_result::progress; // Have we seen this block already? (Harmless)
if (result.code == rai::process_result::progress)
{
@ -2487,6 +2738,8 @@ void ledger_processor::receive_block (rai::receive_block const & block_a)
rai::account_info source_info;
auto error (ledger.store.account_get (transaction, pending.source, source_info));
assert (!error);
assert (!hash2.is_zero ());
ledger.store.hash2_put (transaction, hash, hash2);
ledger.store.pending_del (transaction, key);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, account, hash, info.rep_block, new_balance, info.block_count + 1);
@ -2510,7 +2763,8 @@ void ledger_processor::receive_block (rai::receive_block const & block_a)
void ledger_processor::open_block (rai::open_block const & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, hash));
auto hash2 (ledger.store.hash2_calc (transaction, block_a));
auto existing (ledger.store.block_exists (transaction, hash2));
result.code = existing ? rai::process_result::old : rai::process_result::progress; // Have we seen this block already? (Harmless)
if (result.code == rai::process_result::progress)
{
@ -2536,7 +2790,9 @@ void ledger_processor::open_block (rai::open_block const & block_a)
rai::account_info source_info;
auto error (ledger.store.account_get (transaction, pending.source, source_info));
assert (!error);
assert (!hash2.is_zero ());
ledger.store.pending_del (transaction, key);
ledger.store.hash2_put (transaction, hash, hash2);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, block_a.hashables.account, hash, hash, pending.amount.number (), info.block_count + 1);
ledger.store.representation_add (transaction, hash, pending.amount.number ());
@ -2615,6 +2871,14 @@ signature (rai::sign_message (prv_a, account_a, hash ()))
{
}
rai::vote::vote (rai::account const & account_a, rai::raw_key const & prv_a, uint64_t sequence_a, std::shared_ptr<rai::block> block_a, rai::block_hash const & hash_a) :
sequence (sequence_a),
block (block_a),
account (account_a),
signature (rai::sign_message (prv_a, account_a, hash_a))
{
}
rai::vote::vote (MDB_val const & value_a)
{
rai::bufferstream stream (reinterpret_cast<uint8_t const *> (value_a.mv_data), value_a.mv_size);
@ -2674,8 +2938,11 @@ rai::genesis::genesis ()
void rai::genesis::initialize (MDB_txn * transaction_a, rai::block_store & store_a) const
{
auto hash_l (hash ());
auto hash2 (store_a.hash2_calc (transaction_a, *open));
assert (!hash2.is_zero ());
assert (store_a.latest_begin (transaction_a) == store_a.latest_end ());
store_a.block_put (transaction_a, hash_l, *open);
store_a.hash2_put (transaction_a, hash_l, hash2);
store_a.block_put (transaction_a, hash2, *open);
store_a.account_put (transaction_a, genesis_account, { hash_l, open->hash (), open->hash (), std::numeric_limits<rai::uint128_t>::max (), rai::seconds_since_epoch (), 1 });
store_a.representation_put (transaction_a, genesis_account, std::numeric_limits<rai::uint128_t>::max ());
store_a.checksum_put (transaction_a, 0, 0, hash_l);

View file

@ -136,6 +136,7 @@ public:
size_t receive;
size_t open;
size_t change;
size_t hash2;
};
class vote
{
@ -145,6 +146,7 @@ public:
vote (bool &, rai::stream &);
vote (bool &, rai::stream &, rai::block_type);
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::shared_ptr<rai::block>, rai::block_hash const &);
vote (MDB_val const &);
rai::uint256_union hash () const;
bool operator== (rai::vote const &) const;
@ -164,7 +166,8 @@ enum class vote_code
{
invalid, // Vote is not signed correctly
replay, // Vote does not have the highest sequence number, it's a replay
vote // Vote has the highest sequence number
vote, // Vote has the highest sequence number
vote2
};
class vote_result
{
@ -249,11 +252,16 @@ public:
bool checksum_get (MDB_txn *, uint64_t, uint8_t, rai::checksum &);
void checksum_del (MDB_txn *, uint64_t, uint8_t);
rai::block_hash hash2_calc (MDB_txn *, rai::block const &);
rai::block_hash hash2_get (MDB_txn *, rai::block_hash const &);
void hash2_put (MDB_txn *, rai::block_hash const &, rai::block_hash const &);
void hash2_del (MDB_txn *, rai::block_hash const &);
rai::vote_result vote_validate (MDB_txn *, std::shared_ptr<rai::vote>);
// Return latest vote for an account from store
std::shared_ptr<rai::vote> vote_get (MDB_txn *, rai::account const &);
// Populate vote with the next sequence number
std::shared_ptr<rai::vote> vote_generate (MDB_txn *, rai::account const &, rai::raw_key const &, std::shared_ptr<rai::block>);
std::pair<std::shared_ptr<rai::vote>, std::shared_ptr<rai::vote>> vote_generate (MDB_txn *, rai::account const &, rai::raw_key const &, std::shared_ptr<rai::block>);
// Return either vote or the stored vote with a higher sequence number
std::shared_ptr<rai::vote> vote_max (MDB_txn *, std::shared_ptr<rai::vote>);
// Return latest vote for an account considering the vote cache
@ -276,6 +284,7 @@ public:
void upgrade_v7_to_v8 (MDB_txn *);
void upgrade_v8_to_v9 (MDB_txn *);
void upgrade_v9_to_v10 (MDB_txn *);
void upgrade_v10_to_v11 ();
void clear (MDB_dbi);
@ -304,10 +313,12 @@ public:
MDB_dbi unsynced;
// (uint56_t, uint8_t) -> block_hash // Mapping of region to checksum
MDB_dbi checksum;
// account -> uint64_t // Highest vote observed for account
// account -> uint64_t // Highest vote observed for account
MDB_dbi vote;
// uint256_union -> ? // Meta information about block store
// uint256_union -> ? // Meta information about block store
MDB_dbi meta;
// uint256_union -> uint256_union // Mapping of v1 hash to v2 hash
MDB_dbi hash2;
};
enum class process_result
{