Fix reported by TSAN issues (#1739)

*  prevent reported possible deadlocks & segfaults
* improve mutexes in core_test & slow_test
This commit is contained in:
Sergey Kroshnin 2019-02-18 14:27:28 +03:00 committed by GitHub
commit ba597fff81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 301 additions and 202 deletions

View file

@ -197,7 +197,7 @@ ge25519_is_neutral_vartime(const ge25519 *p) {
curve25519_contract(point_buffer[0], p->x);
curve25519_contract(point_buffer[1], p->y);
curve25519_contract(point_buffer[2], p->z);
memcpy(batch_point_buffer[1], point_buffer[1], 32);
// memcpy(batch_point_buffer[1], point_buffer[1], 32); // remove used in testing batch_point_buffer to fix tsan warnings
return (memcmp(point_buffer[0], zero, 32) == 0) && (memcmp(point_buffer[1], point_buffer[2], 32) == 0);
}

View file

@ -10,15 +10,18 @@ TEST (conflicts, start_stop)
auto send1 (std::make_shared<nano::send_block> (genesis.hash (), key1.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node1.work_generate_blocking (*send1);
ASSERT_EQ (nano::process_result::progress, node1.process (*send1).code);
ASSERT_EQ (0, node1.active.roots.size ());
ASSERT_EQ (0, node1.active.size ());
node1.active.start (send1);
ASSERT_EQ (1, node1.active.roots.size ());
ASSERT_EQ (1, node1.active.size ());
auto root1 (send1->root ());
auto existing1 (node1.active.roots.find (nano::uint512_union (send1->previous (), root1)));
ASSERT_NE (node1.active.roots.end (), existing1);
auto votes1 (existing1->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (1, votes1->last_votes.size ());
{
std::lock_guard<std::mutex> guard (node1.active.mutex);
auto existing1 (node1.active.roots.find (nano::uint512_union (send1->previous (), root1)));
ASSERT_NE (node1.active.roots.end (), existing1);
auto votes1 (existing1->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (1, votes1->last_votes.size ());
}
}
TEST (conflicts, add_existing)
@ -34,14 +37,17 @@ TEST (conflicts, add_existing)
nano::keypair key2;
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node1.active.start (send2);
ASSERT_EQ (1, node1.active.roots.size ());
ASSERT_EQ (1, node1.active.size ());
auto vote1 (std::make_shared<nano::vote> (key2.pub, key2.prv, 0, send2));
node1.active.vote (vote1);
ASSERT_EQ (1, node1.active.roots.size ());
auto votes1 (node1.active.roots.find (nano::uint512_union (send2->previous (), send2->root ()))->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (2, votes1->last_votes.size ());
ASSERT_NE (votes1->last_votes.end (), votes1->last_votes.find (key2.pub));
ASSERT_EQ (1, node1.active.size ());
{
std::lock_guard<std::mutex> guard (node1.active.mutex);
auto votes1 (node1.active.roots.find (nano::uint512_union (send2->previous (), send2->root ()))->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (2, votes1->last_votes.size ());
ASSERT_NE (votes1->last_votes.end (), votes1->last_votes.find (key2.pub));
}
}
TEST (conflicts, add_two)
@ -59,7 +65,7 @@ TEST (conflicts, add_two)
node1.work_generate_blocking (*send2);
ASSERT_EQ (nano::process_result::progress, node1.process (*send2).code);
node1.active.start (send2);
ASSERT_EQ (2, node1.active.roots.size ());
ASSERT_EQ (2, node1.active.size ());
}
TEST (vote_uniquer, null)
@ -159,17 +165,24 @@ TEST (conflicts, reprioritize)
node1.work_generate_blocking (*send1);
uint64_t difficulty1;
nano::work_validate (*send1, &difficulty1);
nano::send_block send1_copy (*send1);
node1.process_active (send1);
node1.block_processor.flush ();
auto existing1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ())));
ASSERT_NE (node1.active.roots.end (), existing1);
ASSERT_EQ (difficulty1, existing1->difficulty);
node1.work_generate_blocking (*send1, difficulty1);
{
std::lock_guard<std::mutex> guard (node1.active.mutex);
auto existing1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ())));
ASSERT_NE (node1.active.roots.end (), existing1);
ASSERT_EQ (difficulty1, existing1->difficulty);
}
node1.work_generate_blocking (send1_copy, difficulty1);
uint64_t difficulty2;
nano::work_validate (*send1, &difficulty2);
node1.process_active (send1);
nano::work_validate (send1_copy, &difficulty2);
node1.process_active (std::make_shared<nano::send_block> (send1_copy));
node1.block_processor.flush ();
auto existing2 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ())));
ASSERT_NE (node1.active.roots.end (), existing2);
ASSERT_EQ (difficulty2, existing2->difficulty);
{
std::lock_guard<std::mutex> guard (node1.active.mutex);
auto existing2 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ())));
ASSERT_NE (node1.active.roots.end (), existing2);
ASSERT_EQ (difficulty2, existing2->difficulty);
}
}

View file

@ -20,13 +20,19 @@ TEST (gap_cache, add_existing)
auto block1 (std::make_shared<nano::send_block> (0, 1, 2, nano::keypair ().prv, 4, 5));
auto transaction (system.nodes[0]->store.tx_begin (true));
cache.add (transaction, block1->hash ());
std::unique_lock<std::mutex> lock (cache.mutex);
auto existing1 (cache.blocks.get<1> ().find (block1->hash ()));
ASSERT_NE (cache.blocks.get<1> ().end (), existing1);
auto arrival (existing1->arrival);
lock.unlock ();
system.deadline_set (20s);
while (arrival == std::chrono::steady_clock::now ())
;
{
ASSERT_NO_ERROR (system.poll ());
}
cache.add (transaction, block1->hash ());
ASSERT_EQ (1, cache.blocks.size ());
ASSERT_EQ (1, cache.size ());
lock.lock ();
auto existing2 (cache.blocks.get<1> ().find (block1->hash ()));
ASSERT_NE (cache.blocks.get<1> ().end (), existing2);
ASSERT_GT (existing2->arrival, arrival);
@ -39,14 +45,20 @@ TEST (gap_cache, comparison)
auto block1 (std::make_shared<nano::send_block> (1, 0, 2, nano::keypair ().prv, 4, 5));
auto transaction (system.nodes[0]->store.tx_begin (true));
cache.add (transaction, block1->hash ());
std::unique_lock<std::mutex> lock (cache.mutex);
auto existing1 (cache.blocks.get<1> ().find (block1->hash ()));
ASSERT_NE (cache.blocks.get<1> ().end (), existing1);
auto arrival (existing1->arrival);
lock.unlock ();
system.deadline_set (20s);
while (std::chrono::steady_clock::now () == arrival)
;
{
ASSERT_NO_ERROR (system.poll ());
}
auto block3 (std::make_shared<nano::send_block> (0, 42, 1, nano::keypair ().prv, 3, 4));
cache.add (transaction, block3->hash ());
ASSERT_EQ (2, cache.blocks.size ());
ASSERT_EQ (2, cache.size ());
lock.lock ();
auto existing2 (cache.blocks.get<1> ().find (block3->hash ()));
ASSERT_NE (cache.blocks.get<1> ().end (), existing2);
ASSERT_GT (existing2->arrival, arrival);
@ -92,16 +104,16 @@ TEST (gap_cache, two_dependencies)
auto send1 (std::make_shared<nano::send_block> (genesis.hash (), key.pub, 1, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (genesis.hash ())));
auto send2 (std::make_shared<nano::send_block> (send1->hash (), key.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.work.generate (send1->hash ())));
auto open (std::make_shared<nano::open_block> (send1->hash (), key.pub, key.pub, key.prv, key.pub, system.work.generate (key.pub)));
ASSERT_EQ (0, system.nodes[0]->gap_cache.blocks.size ());
ASSERT_EQ (0, system.nodes[0]->gap_cache.size ());
system.nodes[0]->block_processor.add (send2, nano::seconds_since_epoch ());
system.nodes[0]->block_processor.flush ();
ASSERT_EQ (1, system.nodes[0]->gap_cache.blocks.size ());
ASSERT_EQ (1, system.nodes[0]->gap_cache.size ());
system.nodes[0]->block_processor.add (open, nano::seconds_since_epoch ());
system.nodes[0]->block_processor.flush ();
ASSERT_EQ (2, system.nodes[0]->gap_cache.blocks.size ());
ASSERT_EQ (2, system.nodes[0]->gap_cache.size ());
system.nodes[0]->block_processor.add (send1, nano::seconds_since_epoch ());
system.nodes[0]->block_processor.flush ();
ASSERT_EQ (0, system.nodes[0]->gap_cache.blocks.size ());
ASSERT_EQ (0, system.nodes[0]->gap_cache.size ());
auto transaction (system.nodes[0]->store.tx_begin ());
ASSERT_TRUE (system.nodes[0]->store.block_exists (transaction, send1->hash ()));
ASSERT_TRUE (system.nodes[0]->store.block_exists (transaction, send2->hash ()));

View file

@ -717,9 +717,9 @@ TEST (votes, check_signature)
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
auto node_l (system.nodes[0]);
node1.active.start (send1);
std::lock_guard<std::mutex> lock (node1.active.mutex);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
ASSERT_EQ (1, votes1->last_votes.size ());
std::unique_lock<std::mutex> lock (node1.active.mutex);
auto vote1 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send1));
vote1->signature.bytes[0] ^= 1;
ASSERT_EQ (nano::vote_code::invalid, node1.vote_processor.vote_blocking (transaction, vote1, nano::endpoint (boost::asio::ip::address_v6 (), 0)));
@ -739,12 +739,15 @@ TEST (votes, add_one)
auto transaction (node1.store.tx_begin (true));
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
node1.active.start (send1);
std::unique_lock<std::mutex> lock (node1.active.mutex);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
ASSERT_EQ (1, votes1->last_votes.size ());
lock.unlock ();
auto vote1 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send1));
ASSERT_FALSE (node1.active.vote (vote1));
auto vote2 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 2, send1));
ASSERT_FALSE (node1.active.vote (vote2));
lock.lock ();
ASSERT_EQ (2, votes1->last_votes.size ());
auto existing1 (votes1->last_votes.find (nano::test_genesis_key.pub));
ASSERT_NE (votes1->last_votes.end (), existing1);
@ -765,20 +768,23 @@ TEST (votes, add_two)
auto transaction (node1.store.tx_begin (true));
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
node1.active.start (send1);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
auto vote1 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send1));
ASSERT_FALSE (node1.active.vote (vote1));
nano::keypair key2;
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
auto vote2 (std::make_shared<nano::vote> (key2.pub, key2.prv, 1, send2));
ASSERT_FALSE (node1.active.vote (vote2));
ASSERT_EQ (3, votes1->last_votes.size ());
ASSERT_NE (votes1->last_votes.end (), votes1->last_votes.find (nano::test_genesis_key.pub));
ASSERT_EQ (send1->hash (), votes1->last_votes[nano::test_genesis_key.pub].hash);
ASSERT_NE (votes1->last_votes.end (), votes1->last_votes.find (key2.pub));
ASSERT_EQ (send2->hash (), votes1->last_votes[key2.pub].hash);
auto winner (*votes1->tally (transaction).begin ());
ASSERT_EQ (*send1, *winner.second);
{
std::lock_guard<std::mutex> lock (node1.active.mutex);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
ASSERT_EQ (3, votes1->last_votes.size ());
ASSERT_NE (votes1->last_votes.end (), votes1->last_votes.find (nano::test_genesis_key.pub));
ASSERT_EQ (send1->hash (), votes1->last_votes[nano::test_genesis_key.pub].hash);
ASSERT_NE (votes1->last_votes.end (), votes1->last_votes.find (key2.pub));
ASSERT_EQ (send2->hash (), votes1->last_votes[key2.pub].hash);
auto winner (*votes1->tally (transaction).begin ());
ASSERT_EQ (*send1, *winner.second);
}
}
// Higher sequence numbers change the vote
@ -793,22 +799,27 @@ TEST (votes, add_existing)
auto transaction (node1.store.tx_begin (true));
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
node1.active.start (send1);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
auto vote1 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send1));
ASSERT_FALSE (node1.active.vote (vote1));
ASSERT_FALSE (node1.active.publish (send1));
std::unique_lock<std::mutex> lock (node1.active.mutex);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
ASSERT_EQ (1, votes1->last_votes[nano::test_genesis_key.pub].sequence);
nano::keypair key2;
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, nano::genesis_amount - nano::Gxrb_ratio, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
auto vote2 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 2, send2));
// Pretend we've waited the timeout
votes1->last_votes[nano::test_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
lock.unlock ();
ASSERT_FALSE (node1.active.vote (vote2));
ASSERT_FALSE (node1.active.publish (send2));
lock.lock ();
ASSERT_EQ (2, votes1->last_votes[nano::test_genesis_key.pub].sequence);
// Also resend the old vote, and see if we respect the sequence number
votes1->last_votes[nano::test_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
lock.unlock ();
ASSERT_TRUE (node1.active.vote (vote1));
lock.lock ();
ASSERT_EQ (2, votes1->last_votes[nano::test_genesis_key.pub].sequence);
ASSERT_EQ (2, votes1->last_votes.size ());
ASSERT_NE (votes1->last_votes.end (), votes1->last_votes.find (nano::test_genesis_key.pub));
@ -829,18 +840,15 @@ TEST (votes, add_old)
auto transaction (node1.store.tx_begin (true));
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
node1.active.start (send1);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
auto vote1 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 2, send1));
std::unique_lock<std::mutex> lock (node1.active.mutex);
std::lock_guard<std::mutex> lock (node1.active.mutex);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
node1.vote_processor.vote_blocking (transaction, vote1, node1.network.endpoint ());
lock.unlock ();
nano::keypair key2;
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
auto vote2 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send2));
votes1->last_votes[nano::test_genesis_key.pub].time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
lock.lock ();
node1.vote_processor.vote_blocking (transaction, vote2, node1.network.endpoint ());
lock.unlock ();
ASSERT_EQ (2, votes1->last_votes.size ());
ASSERT_NE (votes1->last_votes.end (), votes1->last_votes.find (nano::test_genesis_key.pub));
ASSERT_EQ (send1->hash (), votes1->last_votes[nano::test_genesis_key.pub].hash);
@ -864,21 +872,18 @@ TEST (votes, add_old_different_account)
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send2).code);
node1.active.start (send1);
node1.active.start (send2);
std::unique_lock<std::mutex> lock (node1.active.mutex);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
auto votes2 (node1.active.roots.find (nano::uint512_union (send2->previous (), send2->root ()))->election);
ASSERT_EQ (1, votes1->last_votes.size ());
ASSERT_EQ (1, votes2->last_votes.size ());
auto vote1 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 2, send1));
std::unique_lock<std::mutex> lock (node1.active.mutex);
auto vote_result1 (node1.vote_processor.vote_blocking (transaction, vote1, node1.network.endpoint ()));
lock.unlock ();
ASSERT_EQ (nano::vote_code::vote, vote_result1);
ASSERT_EQ (2, votes1->last_votes.size ());
ASSERT_EQ (1, votes2->last_votes.size ());
lock.lock ();
auto vote2 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send2));
auto vote_result2 (node1.vote_processor.vote_blocking (transaction, vote2, node1.network.endpoint ()));
lock.unlock ();
ASSERT_EQ (nano::vote_code::vote, vote_result2);
ASSERT_EQ (2, votes1->last_votes.size ());
ASSERT_EQ (2, votes2->last_votes.size ());
@ -904,18 +909,15 @@ TEST (votes, add_cooldown)
auto transaction (node1.store.tx_begin (true));
ASSERT_EQ (nano::process_result::progress, node1.ledger.process (transaction, *send1).code);
node1.active.start (send1);
std::unique_lock<std::mutex> lock (node1.active.mutex);
auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election);
auto vote1 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send1));
std::unique_lock<std::mutex> lock (node1.active.mutex);
node1.vote_processor.vote_blocking (transaction, vote1, node1.network.endpoint ());
lock.unlock ();
nano::keypair key2;
auto send2 (std::make_shared<nano::send_block> (genesis.hash (), key2.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node1.work_generate_blocking (*send2);
auto vote2 (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 2, send2));
lock.lock ();
node1.vote_processor.vote_blocking (transaction, vote2, node1.network.endpoint ());
lock.unlock ();
ASSERT_EQ (2, votes1->last_votes.size ());
ASSERT_NE (votes1->last_votes.end (), votes1->last_votes.find (nano::test_genesis_key.pub));
ASSERT_EQ (send1->hash (), votes1->last_votes[nano::test_genesis_key.pub].hash);
@ -2495,7 +2497,7 @@ TEST (ledger, unchecked_epoch_invalid)
auto transaction (node1.store.tx_begin ());
ASSERT_FALSE (node1.store.block_exists (transaction, epoch1->hash ()));
ASSERT_TRUE (node1.store.block_exists (transaction, epoch2->hash ()));
ASSERT_TRUE (node1.active.roots.empty ());
ASSERT_TRUE (node1.active.empty ());
auto unchecked_count (node1.store.unchecked_count (transaction));
ASSERT_EQ (unchecked_count, 0);
nano::account_info info;

View file

@ -58,7 +58,7 @@ TEST (network, self_discard)
nano::udp_data data;
data.endpoint = system.nodes[0]->network.endpoint ();
ASSERT_EQ (0, system.nodes[0]->stats.count (nano::stat::type::error, nano::stat::detail::bad_sender));
system.nodes[0]->network.receive_action (&data);
system.nodes[0]->network.receive_action (&data, system.nodes[0]->network.endpoint ());
ASSERT_EQ (1, system.nodes[0]->stats.count (nano::stat::type::error, nano::stat::detail::bad_sender));
}
@ -612,7 +612,7 @@ TEST (bootstrap_processor, process_one)
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (0, node1->active.roots.size ());
ASSERT_EQ (0, node1->active.size ());
node1->stop ();
}
@ -665,7 +665,7 @@ TEST (bootstrap_processor, process_state)
{
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (0, node1->active.roots.size ());
ASSERT_EQ (0, node1->active.size ());
node1->stop ();
}
@ -1062,7 +1062,7 @@ TEST (bulk, offline_send)
ASSERT_NE (std::numeric_limits<nano::uint256_t>::max (), system.nodes[0]->balance (nano::test_genesis_key.pub));
// Wait to finish election background tasks
system.deadline_set (10s);
while (!system.nodes[0]->active.roots.empty ())
while (!system.nodes[0]->active.empty ())
{
ASSERT_NO_ERROR (system.poll ());
}

View file

@ -32,7 +32,7 @@ TEST (node, block_store_path_failure)
nano::logging logging;
logging.init (path);
nano::work_pool work (std::numeric_limits<unsigned>::max (), nullptr);
auto node (std::make_shared<nano::node> (init, *service, 0, path, alarm, logging, work));
auto node (std::make_shared<nano::node> (init, *service, 24000, path, alarm, logging, work));
ASSERT_TRUE (node->wallets.items.empty ());
node->stop ();
}
@ -199,9 +199,12 @@ TEST (node, node_receive_quorum)
auto done (false);
while (!done)
{
auto info (system.nodes[0]->active.roots.find (nano::uint512_union (previous, previous)));
ASSERT_NE (system.nodes[0]->active.roots.end (), info);
done = info->election->announcements > nano::active_transactions::announcement_min;
{
std::lock_guard<std::mutex> guard (system.nodes[0]->active.mutex);
auto info (system.nodes[0]->active.roots.find (nano::uint512_union (previous, previous)));
ASSERT_NE (system.nodes[0]->active.roots.end (), info);
done = info->election->announcements > nano::active_transactions::announcement_min;
}
ASSERT_NO_ERROR (system.poll ());
}
nano::system system2 (24001, 1);
@ -275,13 +278,13 @@ TEST (node, receive_gap)
{
nano::system system (24000, 1);
auto & node1 (*system.nodes[0]);
ASSERT_EQ (0, node1.gap_cache.blocks.size ());
ASSERT_EQ (0, node1.gap_cache.size ());
auto block (std::make_shared<nano::send_block> (5, 1, 2, nano::keypair ().prv, 4, 0));
node1.work_generate_blocking (*block);
nano::publish message (block);
node1.process_message (message, node1.network.endpoint ());
node1.block_processor.flush ();
ASSERT_EQ (1, node1.gap_cache.blocks.size ());
ASSERT_EQ (1, node1.gap_cache.size ());
}
TEST (node, merge_peers)
@ -368,7 +371,7 @@ TEST (node, unlock_search)
{
ASSERT_NO_ERROR (system.poll ());
}
while (!system.nodes[0]->active.roots.empty ())
while (!system.nodes[0]->active.empty ())
{
ASSERT_NO_ERROR (system.poll ());
}
@ -822,21 +825,23 @@ TEST (node, fork_publish)
node1.work_generate_blocking (*send2);
node1.process_active (send1);
node1.block_processor.flush ();
ASSERT_EQ (1, node1.active.roots.size ());
ASSERT_EQ (1, node1.active.size ());
std::unique_lock<std::mutex> lock (node1.active.mutex);
auto existing (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ())));
ASSERT_NE (node1.active.roots.end (), existing);
auto election (existing->election);
lock.unlock ();
system.deadline_set (1s);
// Wait until the genesis rep activated & makes vote
while (election->last_votes.size () != 2)
while (election->last_votes_size () != 2)
{
auto transaction (node1.store.tx_begin ());
election->compute_rep_votes (transaction);
node1.block_processor.generator.add (send1->hash ());
node1.vote_processor.flush ();
ASSERT_NO_ERROR (system.poll ());
}
node1.process_active (send2);
node1.block_processor.flush ();
lock.lock ();
auto existing1 (election->last_votes.find (nano::test_genesis_key.pub));
ASSERT_NE (election->last_votes.end (), existing1);
ASSERT_EQ (send1->hash (), existing1->second.hash);
@ -864,18 +869,20 @@ TEST (node, fork_keep)
node1.block_processor.flush ();
node2.process_active (send1);
node2.block_processor.flush ();
ASSERT_EQ (1, node1.active.roots.size ());
ASSERT_EQ (1, node2.active.roots.size ());
ASSERT_EQ (1, node1.active.size ());
ASSERT_EQ (1, node2.active.size ());
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
node1.process_active (send2);
node1.block_processor.flush ();
node2.process_active (send2);
node2.block_processor.flush ();
std::unique_lock<std::mutex> lock (node2.active.mutex);
auto conflict (node2.active.roots.find (nano::uint512_union (genesis.hash (), genesis.hash ())));
ASSERT_NE (node2.active.roots.end (), conflict);
auto votes1 (conflict->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (1, votes1->last_votes.size ());
lock.unlock ();
{
auto transaction0 (system.nodes[0]->store.tx_begin ());
auto transaction1 (system.nodes[1]->store.tx_begin ());
@ -884,13 +891,14 @@ TEST (node, fork_keep)
}
system.deadline_set (1.5min);
// Wait until the genesis rep makes a vote
while (votes1->last_votes.size () == 1)
while (votes1->last_votes_size () == 1)
{
ASSERT_NO_ERROR (system.poll ());
}
auto transaction0 (system.nodes[0]->store.tx_begin ());
auto transaction1 (system.nodes[1]->store.tx_begin ());
// The vote should be in agreement with what we already have.
lock.lock ();
auto winner (*votes1->tally (transaction1).begin ());
ASSERT_EQ (*send1, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
@ -915,18 +923,20 @@ TEST (node, fork_flip)
node1.block_processor.flush ();
node2.process_message (publish2, node1.network.endpoint ());
node2.block_processor.flush ();
ASSERT_EQ (1, node1.active.roots.size ());
ASSERT_EQ (1, node2.active.roots.size ());
ASSERT_EQ (1, node1.active.size ());
ASSERT_EQ (1, node2.active.size ());
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
node1.process_message (publish2, node1.network.endpoint ());
node1.block_processor.flush ();
node2.process_message (publish1, node2.network.endpoint ());
node2.block_processor.flush ();
std::unique_lock<std::mutex> lock (node2.active.mutex);
auto conflict (node2.active.roots.find (nano::uint512_union (genesis.hash (), genesis.hash ())));
ASSERT_NE (node2.active.roots.end (), conflict);
auto votes1 (conflict->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (1, votes1->last_votes.size ());
lock.unlock ();
{
auto transaction (system.nodes[0]->store.tx_begin ());
ASSERT_TRUE (node1.store.block_exists (transaction, publish1.block->hash ()));
@ -944,6 +954,7 @@ TEST (node, fork_flip)
}
auto transaction1 (system.nodes[0]->store.tx_begin ());
auto transaction2 (system.nodes[1]->store.tx_begin ());
lock.lock ();
auto winner (*votes1->tally (transaction2).begin ());
ASSERT_EQ (*publish1.block, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
@ -972,19 +983,21 @@ TEST (node, fork_multi_flip)
node2.process_message (publish2, node2.network.endpoint ());
node2.process_message (publish3, node2.network.endpoint ());
node2.block_processor.flush ();
ASSERT_EQ (1, node1.active.roots.size ());
ASSERT_EQ (2, node2.active.roots.size ());
ASSERT_EQ (1, node1.active.size ());
ASSERT_EQ (2, node2.active.size ());
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
node1.process_message (publish2, node1.network.endpoint ());
node1.process_message (publish3, node1.network.endpoint ());
node1.block_processor.flush ();
node2.process_message (publish1, node2.network.endpoint ());
node2.block_processor.flush ();
std::unique_lock<std::mutex> lock (node2.active.mutex);
auto conflict (node2.active.roots.find (nano::uint512_union (genesis.hash (), genesis.hash ())));
ASSERT_NE (node2.active.roots.end (), conflict);
auto votes1 (conflict->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (1, votes1->last_votes.size ());
lock.unlock ();
{
auto transaction (system.nodes[0]->store.tx_begin ());
ASSERT_TRUE (node1.store.block_exists (transaction, publish1.block->hash ()));
@ -1003,6 +1016,7 @@ TEST (node, fork_multi_flip)
}
auto transaction1 (system.nodes[0]->store.tx_begin ());
auto transaction2 (system.nodes[1]->store.tx_begin ());
lock.lock ();
auto winner (*votes1->tally (transaction2).begin ());
ASSERT_EQ (*publish1.block, *winner.second);
ASSERT_EQ (nano::genesis_amount - 100, winner.first);
@ -1070,7 +1084,7 @@ TEST (node, fork_open)
node1.block_processor.flush ();
auto open2 (std::make_shared<nano::open_block> (publish1.block->hash (), 2, key1.pub, key1.prv, key1.pub, system.work.generate (key1.pub)));
nano::publish publish3 (open2);
ASSERT_EQ (2, node1.active.roots.size ());
ASSERT_EQ (2, node1.active.size ());
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
node1.process_message (publish3, node1.network.endpoint ());
node1.block_processor.flush ();
@ -1100,19 +1114,21 @@ TEST (node, fork_open_flip)
// node2 gets copy that will be evicted
node2.process_active (open2);
node2.block_processor.flush ();
ASSERT_EQ (2, node1.active.roots.size ());
ASSERT_EQ (2, node2.active.roots.size ());
ASSERT_EQ (2, node1.active.size ());
ASSERT_EQ (2, node2.active.size ());
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
// Notify both nodes that a fork exists
node1.process_active (open2);
node1.block_processor.flush ();
node2.process_active (open1);
node2.block_processor.flush ();
std::unique_lock<std::mutex> lock (node2.active.mutex);
auto conflict (node2.active.roots.find (nano::uint512_union (open1->previous (), open1->root ())));
ASSERT_NE (node2.active.roots.end (), conflict);
auto votes1 (conflict->election);
ASSERT_NE (nullptr, votes1);
ASSERT_EQ (1, votes1->last_votes.size ());
lock.unlock ();
ASSERT_TRUE (node1.block (open1->hash ()) != nullptr);
ASSERT_TRUE (node2.block (open2->hash ()) != nullptr);
system.deadline_set (10s);
@ -1124,6 +1140,7 @@ TEST (node, fork_open_flip)
node2.block_processor.flush ();
auto transaction1 (system.nodes[0]->store.tx_begin ());
auto transaction2 (system.nodes[1]->store.tx_begin ());
lock.lock ();
auto winner (*votes1->tally (transaction2).begin ());
ASSERT_EQ (*open1, *winner.second);
ASSERT_EQ (nano::genesis_amount - 1, winner.first);
@ -1381,23 +1398,30 @@ TEST (node, rep_self_vote)
}
system.wallet (0)->insert_adhoc (rep_big.prv);
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
ASSERT_EQ (system.wallet (0)->wallets.reps_count, 2);
auto block0 (std::make_shared<nano::send_block> (node0->latest (nano::test_genesis_key.pub), rep_big.pub, nano::uint128_t ("0x60000000000000000000000000000000"), nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0));
node0->work_generate_blocking (*block0);
ASSERT_EQ (nano::process_result::progress, node0->process (*block0).code);
auto & active (node0->active);
active.start (block0);
std::unique_lock<std::mutex> lock (active.mutex);
auto existing (active.roots.find (nano::uint512_union (block0->previous (), block0->root ())));
ASSERT_NE (active.roots.end (), existing);
auto election (existing->election);
lock.unlock ();
system.deadline_set (1s);
// Wait until representatives are activated & make vote
while (existing->election->last_votes.size () != 3)
while (election->last_votes_size () != 3)
{
lock.lock ();
auto transaction (node0->store.tx_begin ());
existing->election->compute_rep_votes (transaction);
election->compute_rep_votes (transaction);
lock.unlock ();
node0->vote_processor.flush ();
ASSERT_NO_ERROR (system.poll ());
}
auto & rep_votes (existing->election->last_votes);
lock.lock ();
auto & rep_votes (election->last_votes);
ASSERT_NE (rep_votes.end (), rep_votes.find (nano::test_genesis_key.pub));
ASSERT_NE (rep_votes.end (), rep_votes.find (rep_big.pub));
}
@ -1418,7 +1442,7 @@ TEST (node, DISABLED_bootstrap_no_publish)
}
ASSERT_FALSE (node1->bootstrap_initiator.in_progress ());
node1->bootstrap_initiator.bootstrap (node0->network.endpoint ());
ASSERT_TRUE (node1->active.roots.empty ());
ASSERT_TRUE (node1->active.empty ());
system1.deadline_set (10s);
while (node1->block (send0.hash ()) == nullptr)
{
@ -1426,7 +1450,7 @@ TEST (node, DISABLED_bootstrap_no_publish)
system0.poll ();
auto ec = system1.poll ();
// There should never be an active transaction because the only activity is bootstrapping 1 block which shouldn't be publishing.
ASSERT_TRUE (node1->active.roots.empty ());
ASSERT_TRUE (node1->active.empty ());
ASSERT_NO_ERROR (ec);
}
}
@ -1448,7 +1472,7 @@ TEST (node, bootstrap_bulk_push)
}
ASSERT_FALSE (node0->bootstrap_initiator.in_progress ());
ASSERT_FALSE (node1->bootstrap_initiator.in_progress ());
ASSERT_TRUE (node1->active.roots.empty ());
ASSERT_TRUE (node1->active.empty ());
node0->bootstrap_initiator.bootstrap (node1->network.endpoint (), false);
system1.deadline_set (10s);
while (node1->block (send0.hash ()) == nullptr)
@ -1457,7 +1481,7 @@ TEST (node, bootstrap_bulk_push)
ASSERT_NO_ERROR (system1.poll ());
}
// since this uses bulk_push, the new block should be republished
ASSERT_FALSE (node1->active.roots.empty ());
ASSERT_FALSE (node1->active.empty ());
}
// Bootstrapping a forked open block should succeed.
@ -1486,7 +1510,7 @@ TEST (node, bootstrap_fork_open)
}
ASSERT_FALSE (node1->bootstrap_initiator.in_progress ());
node1->bootstrap_initiator.bootstrap (node0->network.endpoint ());
ASSERT_TRUE (node1->active.roots.empty ());
ASSERT_TRUE (node1->active.empty ());
system0.deadline_set (10s);
while (node1->ledger.block_exists (open1.hash ()))
{
@ -1575,7 +1599,7 @@ TEST (node, no_voting)
// Broadcast a confirm so others should know this is a rep node
wallet0->send_action (nano::test_genesis_key.pub, key1.pub, nano::Mxrb_ratio);
system.deadline_set (10s);
while (!node1.active.roots.empty ())
while (!node1.active.empty ())
{
ASSERT_NO_ERROR (system.poll ());
}
@ -1743,9 +1767,9 @@ TEST (node, block_confirm)
ASSERT_EQ (nano::process_result::progress, system.nodes[1]->ledger.process (transaction, *send2).code);
}
system.nodes[0]->block_confirm (send2);
ASSERT_TRUE (system.nodes[0]->active.confirmed.empty ());
ASSERT_TRUE (system.nodes[0]->active.list_confirmed ().empty ());
system.deadline_set (10s);
while (system.nodes[0]->active.confirmed.empty ())
while (system.nodes[0]->active.list_confirmed ().empty ())
{
ASSERT_NO_ERROR (system.poll ());
}
@ -1812,17 +1836,20 @@ TEST (node, confirm_quorum)
}
system.wallet (0)->send_action (nano::test_genesis_key.pub, nano::test_genesis_key.pub, new_balance.number ());
system.deadline_set (10s);
while (system.nodes[0]->active.roots.empty ())
while (system.nodes[0]->active.empty ())
{
ASSERT_NO_ERROR (system.poll ());
}
auto done (false);
while (!done)
{
ASSERT_FALSE (system.nodes[0]->active.roots.empty ());
auto info (system.nodes[0]->active.roots.find (nano::uint512_union (send1->hash (), send1->hash ())));
ASSERT_NE (system.nodes[0]->active.roots.end (), info);
done = info->election->announcements > nano::active_transactions::announcement_min;
ASSERT_FALSE (system.nodes[0]->active.empty ());
{
std::lock_guard<std::mutex> guard (system.nodes[0]->active.mutex);
auto info (system.nodes[0]->active.roots.find (nano::uint512_union (send1->hash (), send1->hash ())));
ASSERT_NE (system.nodes[0]->active.roots.end (), info);
done = info->election->announcements > nano::active_transactions::announcement_min;
}
ASSERT_NO_ERROR (system.poll ());
}
ASSERT_EQ (0, system.nodes[0]->balance (nano::test_genesis_key.pub));
@ -2157,12 +2184,12 @@ TEST (node, block_processor_reject_rolled_back)
node.block_processor.flush ();
ASSERT_FALSE (node.ledger.block_exists (send1->hash ()));
ASSERT_TRUE (node.ledger.block_exists (send2->hash ()));
ASSERT_TRUE (node.active.roots.empty ());
ASSERT_TRUE (node.active.empty ());
// Block send1 cannot be processed & start fork resolution election
node.block_processor.add (send1);
node.block_processor.flush ();
ASSERT_FALSE (node.ledger.block_exists (send1->hash ()));
ASSERT_TRUE (node.active.roots.empty ());
ASSERT_TRUE (node.active.empty ());
}
TEST (node, confirm_back)
@ -2179,7 +2206,7 @@ TEST (node, confirm_back)
node.process_active (open);
node.process_active (send2);
node.block_processor.flush ();
ASSERT_EQ (3, node.active.roots.size ());
ASSERT_EQ (3, node.active.size ());
std::vector<nano::block_hash> vote_blocks;
vote_blocks.push_back (send2->hash ());
auto vote (std::make_shared<nano::vote> (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 0, vote_blocks));
@ -2189,7 +2216,7 @@ TEST (node, confirm_back)
node.vote_processor.vote_blocking (transaction, vote, node.network.endpoint ());
}
system.deadline_set (10s);
while (!node.active.roots.empty ())
while (!node.active.empty ())
{
ASSERT_NO_ERROR (system.poll ());
}

View file

@ -284,15 +284,14 @@ TEST (rpc, send)
request.put ("source", nano::test_genesis_key.pub.to_account ());
request.put ("destination", nano::test_genesis_key.pub.to_account ());
request.put ("amount", "100");
system.deadline_set (10s);
boost::thread thread2 ([&system]() {
system.deadline_set (10s);
while (system.nodes[0]->balance (nano::test_genesis_key.pub) == nano::genesis_amount)
{
ASSERT_NO_ERROR (system.poll ());
}
});
test_response response (request, rpc, system.io_ctx);
system.deadline_set (5s);
while (response.status == 0)
{
ASSERT_NO_ERROR (system.poll ());
@ -320,15 +319,14 @@ TEST (rpc, send_fail)
request.put ("destination", nano::test_genesis_key.pub.to_account ());
request.put ("amount", "100");
std::atomic<bool> done (false);
system.deadline_set (10s);
boost::thread thread2 ([&system, &done]() {
system.deadline_set (10s);
while (!done)
{
ASSERT_NO_ERROR (system.poll ());
}
});
test_response response (request, rpc, system.io_ctx);
system.deadline_set (5s);
while (response.status == 0)
{
ASSERT_NO_ERROR (system.poll ());
@ -1853,9 +1851,12 @@ TEST (rpc, search_pending)
nano::system system (24000, 1);
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
auto wallet (system.nodes[0]->wallets.items.begin ()->first.to_string ());
nano::send_block block (system.nodes[0]->latest (nano::test_genesis_key.pub), nano::test_genesis_key.pub, nano::genesis_amount - system.nodes[0]->config.receive_minimum.number (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
auto transaction (system.nodes[0]->store.tx_begin (true));
ASSERT_EQ (nano::process_result::progress, system.nodes[0]->ledger.process (transaction, block).code);
auto latest (system.nodes[0]->latest (nano::test_genesis_key.pub));
nano::send_block block (latest, nano::test_genesis_key.pub, nano::genesis_amount - system.nodes[0]->config.receive_minimum.number (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.nodes[0]->work_generate_blocking (latest));
{
auto transaction (system.nodes[0]->store.tx_begin (true));
ASSERT_EQ (nano::process_result::progress, system.nodes[0]->ledger.process (transaction, block).code);
}
nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true));
rpc.start ();
boost::property_tree::ptree request;
@ -3204,9 +3205,12 @@ TEST (rpc, search_pending_all)
{
nano::system system (24000, 1);
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
nano::send_block block (system.nodes[0]->latest (nano::test_genesis_key.pub), nano::test_genesis_key.pub, nano::genesis_amount - system.nodes[0]->config.receive_minimum.number (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0);
auto transaction (system.nodes[0]->store.tx_begin (true));
ASSERT_EQ (nano::process_result::progress, system.nodes[0]->ledger.process (transaction, block).code);
auto latest (system.nodes[0]->latest (nano::test_genesis_key.pub));
nano::send_block block (latest, nano::test_genesis_key.pub, nano::genesis_amount - system.nodes[0]->config.receive_minimum.number (), nano::test_genesis_key.prv, nano::test_genesis_key.pub, system.nodes[0]->work_generate_blocking (latest));
{
auto transaction (system.nodes[0]->store.tx_begin (true));
ASSERT_EQ (nano::process_result::progress, system.nodes[0]->ledger.process (transaction, block).code);
}
nano::rpc rpc (system.io_ctx, *system.nodes[0], nano::rpc_config (true));
rpc.start ();
boost::property_tree::ptree request;
@ -4172,10 +4176,10 @@ TEST (rpc, confirmation_history)
nano::system system (24000, 1);
nano::keypair key;
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
ASSERT_TRUE (system.nodes[0]->active.confirmed.empty ());
ASSERT_TRUE (system.nodes[0]->active.list_confirmed ().empty ());
auto block (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, nano::Gxrb_ratio));
system.deadline_set (10s);
while (system.nodes[0]->active.confirmed.empty ())
while (system.nodes[0]->active.list_confirmed ().empty ())
{
ASSERT_NO_ERROR (system.poll ());
}
@ -4209,12 +4213,12 @@ TEST (rpc, confirmation_history_hash)
nano::system system (24000, 1);
nano::keypair key;
system.wallet (0)->insert_adhoc (nano::test_genesis_key.prv);
ASSERT_TRUE (system.nodes[0]->active.confirmed.empty ());
ASSERT_TRUE (system.nodes[0]->active.list_confirmed ().empty ());
auto send1 (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, nano::Gxrb_ratio));
auto send2 (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, nano::Gxrb_ratio));
auto send3 (system.wallet (0)->send_action (nano::test_genesis_key.pub, key.pub, nano::Gxrb_ratio));
system.deadline_set (10s);
while (system.nodes[0]->active.confirmed.size () != 3)
while (system.nodes[0]->active.list_confirmed ().size () != 3)
{
ASSERT_NO_ERROR (system.poll ());
}

View file

@ -178,7 +178,7 @@ TEST (wallet, send_async)
ASSERT_NO_ERROR (system.poll ());
}
});
bool success (false);
std::atomic<bool> success (false);
system.wallet (0)->send_async (nano::test_genesis_key.pub, key2.pub, std::numeric_limits<nano::uint128_t>::max (), [&success](std::shared_ptr<nano::block> block_a) { ASSERT_NE (nullptr, block_a); success = true; });
thread.join ();
ASSERT_TRUE (success);

View file

@ -85,11 +85,11 @@ TEST (wallets, upgrade)
auto node1 (std::make_shared<nano::node> (init1, system.io_ctx, 24001, path, system.alarm, system.logging, system.work));
ASSERT_FALSE (init1.error ());
node1->wallets.create (id.pub);
auto transaction_source (node1->wallets.env.tx_begin (true));
MDB_txn * tx_source (*boost::polymorphic_downcast<nano::mdb_txn *> (transaction_source.impl.get ()));
auto & mdb_store (dynamic_cast<nano::mdb_store &> (node1->store));
auto transaction_destination (mdb_store.tx_begin_write ());
MDB_txn * tx_destination (*boost::polymorphic_downcast<nano::mdb_txn *> (transaction_destination.impl.get ()));
auto transaction_source (node1->wallets.env.tx_begin (true));
MDB_txn * tx_source (*boost::polymorphic_downcast<nano::mdb_txn *> (transaction_source.impl.get ()));
node1->wallets.move_table (id.pub.to_string (), tx_source, tx_destination);
node1->store.version_put (transaction_destination, 11);
}
@ -97,10 +97,10 @@ TEST (wallets, upgrade)
auto node1 (std::make_shared<nano::node> (init1, system.io_ctx, 24001, path, system.alarm, system.logging, system.work));
ASSERT_EQ (1, node1->wallets.items.size ());
ASSERT_EQ (id.pub, node1->wallets.items.begin ()->first);
auto transaction_old (node1->store.tx_begin_write ());
MDB_txn * tx_old (*boost::polymorphic_downcast<nano::mdb_txn *> (transaction_old.impl.get ()));
auto transaction_new (node1->wallets.env.tx_begin (true));
MDB_txn * tx_new (*boost::polymorphic_downcast<nano::mdb_txn *> (transaction_new.impl.get ()));
auto transaction_old (node1->store.tx_begin_write ());
MDB_txn * tx_old (*boost::polymorphic_downcast<nano::mdb_txn *> (transaction_old.impl.get ()));
MDB_dbi old_handle;
ASSERT_EQ (MDB_NOTFOUND, mdb_dbi_open (tx_old, id.pub.to_string ().c_str (), 0, &old_handle));
MDB_dbi new_handle;

View file

@ -610,7 +610,7 @@ int main (int argc, char * const * argv)
node->vote_processor.vote (vote, node->network.endpoint ());
votes.pop_front ();
}
while (!node->active.roots.empty ())
while (!node->active.empty ())
{
std::this_thread::sleep_for (std::chrono::milliseconds (100));
}

View file

@ -72,8 +72,8 @@ void nano::block_processor::add (nano::unchecked_info const & info_a)
}
blocks_hashes.insert (hash);
}
condition.notify_all ();
}
condition.notify_all ();
}
else
{
@ -106,10 +106,7 @@ void nano::block_processor::process_blocks ()
}
else
{
lock.unlock ();
condition.notify_all ();
lock.lock ();
condition.wait (lock);
}
}

View file

@ -1400,14 +1400,15 @@ void nano::bootstrap_attempt::lazy_add (nano::block_hash const & hash_a)
void nano::bootstrap_attempt::lazy_pull_flush ()
{
std::unique_lock<std::mutex> lock (lazy_mutex);
assert (!mutex.try_lock ());
std::unique_lock<std::mutex> lazy_lock (lazy_mutex);
auto transaction (node->store.tx_begin_read ());
for (auto & pull_start : lazy_pulls)
{
// Recheck if block was already processed
if (lazy_blocks.find (pull_start) == lazy_blocks.end () && !node->store.block_exists (transaction, pull_start))
{
add_pull (nano::pull_info (pull_start, pull_start, nano::block_hash (0), lazy_max_pull_blocks));
pulls.push_back (nano::pull_info (pull_start, pull_start, nano::block_hash (0), lazy_max_pull_blocks));
}
}
lazy_pulls.clear ();
@ -1480,17 +1481,15 @@ void nano::bootstrap_attempt::lazy_run ()
// Flushing lazy pulls
if (iterations % 100 == 0)
{
lock.unlock ();
lazy_pull_flush ();
lock.lock ();
}
}
// Flushing may resolve forks which can add more pulls
// Flushing lazy pulls
lock.unlock ();
node->block_processor.flush ();
lazy_pull_flush ();
lock.lock ();
lazy_pull_flush ();
}
if (!stopped)
{

View file

@ -118,7 +118,7 @@ public:
std::atomic<uint64_t> total_blocks;
std::atomic<unsigned> runs_count;
std::vector<std::pair<nano::block_hash, nano::block_hash>> bulk_push_targets;
bool stopped;
std::atomic<bool> stopped;
nano::bootstrap_mode mode;
std::mutex mutex;
std::condition_variable condition;

View file

@ -612,7 +612,7 @@ nano::confirm_ack::confirm_ack (bool & error_a, nano::stream & stream_a, nano::m
message (header_a),
vote (std::make_shared<nano::vote> (error_a, stream_a, header.block_type ()))
{
if (uniquer_a)
if (!error_a && uniquer_a)
{
vote = uniquer_a->unique (vote);
}
@ -622,6 +622,7 @@ nano::confirm_ack::confirm_ack (std::shared_ptr<nano::vote> vote_a) :
message (nano::message_type::confirm_ack),
vote (vote_a)
{
assert (!vote_a->blocks.empty ());
auto & first_vote_block (vote_a->blocks[0]);
if (first_vote_block.which ())
{
@ -640,17 +641,6 @@ void nano::confirm_ack::serialize (nano::stream & stream_a) const
vote->serialize (stream_a, header.block_type ());
}
bool nano::confirm_ack::deserialize (nano::stream & stream_a, nano::vote_uniquer * uniquer_a)
{
assert (header.type == nano::message_type::confirm_ack);
auto result (vote->deserialize (stream_a));
if (uniquer_a)
{
vote = uniquer_a->unique (vote);
}
return result;
}
bool nano::confirm_ack::operator== (nano::confirm_ack const & other_a) const
{
auto result (*vote == *other_a.vote);

View file

@ -313,7 +313,6 @@ public:
confirm_ack (bool &, nano::stream &, nano::message_header const &, nano::vote_uniquer * = nullptr);
confirm_ack (std::shared_ptr<nano::vote>);
void serialize (nano::stream &) const override;
bool deserialize (nano::stream &, nano::vote_uniquer * = nullptr);
void visit (nano::message_visitor &) const override;
bool operator== (nano::confirm_ack const &) const;
std::shared_ptr<nano::vote> vote;

View file

@ -847,6 +847,7 @@ void nano::mdb_store::version_put (nano::transaction const & transaction_a, int
{
auto status (mdb_drop (env.tx (transaction_a), blocks_info, 1));
release_assert (status == MDB_SUCCESS);
blocks_info = 0;
}
}

View file

@ -136,6 +136,7 @@ void nano::network::receive ()
void nano::network::process_packets ()
{
auto local_endpoint (endpoint ());
while (on.load ())
{
auto data (buffer_container.dequeue ());
@ -144,7 +145,7 @@ void nano::network::process_packets ()
break;
}
//std::cerr << data->endpoint.address ().to_string ();
receive_action (data);
receive_action (data, local_endpoint);
buffer_container.release (data);
}
}
@ -152,7 +153,11 @@ void nano::network::process_packets ()
void nano::network::stop ()
{
on = false;
socket.close ();
std::unique_lock<std::mutex> lock (socket_mutex);
if (socket.is_open ())
{
socket.close ();
}
resolver.cancel ();
buffer_container.stop ();
}
@ -806,10 +811,14 @@ public:
};
}
void nano::network::receive_action (nano::udp_data * data_a)
void nano::network::receive_action (nano::udp_data * data_a, nano::endpoint const & local_endpoint_a)
{
auto allowed_sender (true);
if (data_a->endpoint == endpoint ())
if (!on)
{
allowed_sender = false;
}
else if (data_a->endpoint == local_endpoint_a)
{
allowed_sender = false;
}
@ -968,7 +977,11 @@ namespace nano
std::unique_ptr<seq_con_info_component> collect_seq_con_info (alarm & alarm, const std::string & name)
{
auto composite = std::make_unique<seq_con_info_composite> (name);
auto count = alarm.operations.size ();
size_t count = 0;
{
std::lock_guard<std::mutex> guard (alarm.mutex);
count = alarm.operations.size ();
}
auto sizeof_element = sizeof (decltype (alarm.operations)::value_type);
composite->add_component (std::make_unique<seq_con_info_leaf> (seq_con_info{ "operations", count, sizeof_element }));
return composite;
@ -1833,16 +1846,17 @@ nano::uint128_t nano::gap_cache::bootstrap_threshold (nano::transaction const &
return result;
}
size_t nano::gap_cache::size ()
{
std::lock_guard<std::mutex> lock (mutex);
return blocks.size ();
}
namespace nano
{
std::unique_ptr<seq_con_info_component> collect_seq_con_info (gap_cache & gap_cache, const std::string & name)
{
size_t count = 0;
{
std::lock_guard<std::mutex> (gap_cache.mutex);
count = gap_cache.blocks.size ();
}
auto count = gap_cache.size ();
auto sizeof_element = sizeof (decltype (gap_cache.blocks)::value_type);
auto composite = std::make_unique<seq_con_info_composite> (name);
composite->add_component (std::make_unique<seq_con_info_leaf> (seq_con_info{ "blocks", count, sizeof_element }));
@ -2703,6 +2717,7 @@ void nano::node::process_message (nano::message & message_a, nano::endpoint cons
nano::endpoint nano::network::endpoint ()
{
boost::system::error_code ec;
std::unique_lock<std::mutex> lock (socket_mutex);
auto port (socket.local_endpoint (ec).port ());
if (ec)
{
@ -2963,18 +2978,21 @@ void nano::network::send_buffer (uint8_t const * data_a, size_t size_a, nano::en
{
BOOST_LOG (node.log) << "Sending packet";
}
socket.async_send_to (boost::asio::buffer (data_a, size_a), endpoint_a, [this, callback_a](boost::system::error_code const & ec, size_t size_a) {
callback_a (ec, size_a);
this->node.stats.add (nano::stat::type::traffic, nano::stat::dir::out, size_a);
if (ec == boost::system::errc::host_unreachable)
{
this->node.stats.inc (nano::stat::type::error, nano::stat::detail::unreachable_host, nano::stat::dir::out);
}
if (this->node.config.logging.network_packet_logging ())
{
BOOST_LOG (this->node.log) << "Packet send complete";
}
});
if (on.load ())
{
socket.async_send_to (boost::asio::buffer (data_a, size_a), endpoint_a, [this, callback_a](boost::system::error_code const & ec, size_t size_a) {
callback_a (ec, size_a);
this->node.stats.add (nano::stat::type::traffic, nano::stat::dir::out, size_a);
if (ec == boost::system::errc::host_unreachable)
{
this->node.stats.inc (nano::stat::type::error, nano::stat::detail::unreachable_host, nano::stat::dir::out);
}
if (this->node.config.logging.network_packet_logging ())
{
BOOST_LOG (this->node.log) << "Packet send complete";
}
});
}
}
std::shared_ptr<nano::node> nano::node::shared ()
@ -3268,6 +3286,12 @@ bool nano::election::publish (std::shared_ptr<nano::block> block_a)
return result;
}
size_t nano::election::last_votes_size ()
{
std::lock_guard<std::mutex> lock (node.active.mutex);
return last_votes.size ();
}
void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> & lock_a)
{
std::unordered_set<nano::uint512_union> inactive;
@ -3282,13 +3306,12 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
for (auto i (roots.get<1> ().begin ()), n (roots.get<1> ().end ()); i != n; ++i)
{
auto root (i->root);
lock_a.unlock ();
auto election_l (i->election);
if ((election_l->confirmed || election_l->stopped) && i->election->announcements >= announcement_min - 1)
if ((election_l->confirmed || election_l->stopped) && election_l->announcements >= announcement_min - 1)
{
if (election_l->confirmed)
{
confirmed.push_back (i->election->status);
confirmed.push_back (election_l->status);
if (confirmed.size () > election_history_size)
{
confirmed.pop_front ();
@ -3298,12 +3321,12 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
}
else
{
if (i->election->announcements > announcement_long)
if (election_l->announcements > announcement_long)
{
++unconfirmed_count;
unconfirmed_announcements += i->election->announcements;
unconfirmed_announcements += election_l->announcements;
// Log votes for very long unconfirmed elections
if (i->election->announcements % 50 == 1)
if (election_l->announcements % 50 == 1)
{
auto tally_l (election_l->tally (transaction));
election_l->log_votes (tally_l);
@ -3311,7 +3334,7 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
/* Escalation for long unconfirmed elections
Start new elections for previous block & source
if there are less than 100 active elections */
if (i->election->announcements % announcement_long == 1 && roots_size < 100 && !nano::is_test_network)
if (election_l->announcements % announcement_long == 1 && roots_size < 100 && !nano::is_test_network)
{
std::shared_ptr<nano::block> previous;
auto previous_hash (election_l->status.winner->previous ());
@ -3339,7 +3362,7 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
}
}
}
if (i->election->announcements < announcement_long || i->election->announcements % announcement_long == 1)
if (election_l->announcements < announcement_long || election_l->announcements % announcement_long == 1)
{
if (node.ledger.could_fit (transaction, *election_l->status.winner))
{
@ -3351,20 +3374,20 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
}
else
{
if (i->election->announcements != 0)
if (election_l->announcements != 0)
{
election_l->stop ();
}
}
}
if (i->election->announcements % 4 == 1)
if (election_l->announcements % 4 == 1)
{
auto reps (std::make_shared<std::vector<nano::peer_information>> (node.peers.representatives (std::numeric_limits<size_t>::max ())));
std::unordered_set<nano::account> probable_reps;
nano::uint128_t total_weight (0);
for (auto j (reps->begin ()), m (reps->end ()); j != m;)
{
auto & rep_votes (i->election->last_votes);
auto & rep_votes (election_l->last_votes);
auto rep_acct (j->probable_rep_account);
// Calculate if representative isn't recorded for several IP addresses
if (probable_reps.find (rep_acct) == probable_reps.end ())
@ -3400,7 +3423,7 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
{
if (confirm_req_bundle.size () < max_broadcast_queue)
{
confirm_req_bundle.push_back (std::make_pair (i->election->status.winner, reps));
confirm_req_bundle.push_back (std::make_pair (election_l->status.winner, reps));
}
}
else
@ -3408,7 +3431,7 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
for (auto & rep : *reps)
{
auto rep_request (requests_bundle.find (rep.endpoint));
auto block (i->election->status.winner);
auto block (election_l->status.winner);
auto root_hash (std::make_pair (block->hash (), block->root ()));
if (rep_request == requests_bundle.end ())
{
@ -3429,14 +3452,14 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
{
if (!nano::is_test_network)
{
confirm_req_bundle.push_back (std::make_pair (i->election->status.winner, std::make_shared<std::vector<nano::peer_information>> (node.peers.list_vector (100))));
confirm_req_bundle.push_back (std::make_pair (election_l->status.winner, std::make_shared<std::vector<nano::peer_information>> (node.peers.list_vector (100))));
}
else
{
for (auto & rep : *reps)
{
auto rep_request (requests_bundle.find (rep.endpoint));
auto block (i->election->status.winner);
auto block (election_l->status.winner);
auto root_hash (std::make_pair (block->hash (), block->root ()));
if (rep_request == requests_bundle.end ())
{
@ -3453,8 +3476,8 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
}
}
++election_l->announcements;
lock_a.lock ();
}
lock_a.unlock ();
// Rebroadcast unconfirmed blocks
if (!rebroadcast_bundle.empty ())
{
@ -3470,6 +3493,7 @@ void nano::active_transactions::request_confirm (std::unique_lock<std::mutex> &
{
node.network.broadcast_confirm_req_batch (confirm_req_bundle);
}
lock_a.lock ();
for (auto i (inactive.begin ()), n (inactive.end ()); i != n; ++i)
{
auto root_it (roots.find (*i));
@ -3631,6 +3655,12 @@ std::deque<std::shared_ptr<nano::block>> nano::active_transactions::list_blocks
return result;
}
std::deque<nano::election_status> nano::active_transactions::list_confirmed ()
{
std::lock_guard<std::mutex> lock (mutex);
return confirmed;
}
void nano::active_transactions::erase (nano::block const & block_a)
{
std::lock_guard<std::mutex> lock (mutex);
@ -3641,6 +3671,18 @@ void nano::active_transactions::erase (nano::block const & block_a)
}
}
bool nano::active_transactions::empty ()
{
std::lock_guard<std::mutex> lock (mutex);
return roots.empty ();
}
size_t nano::active_transactions::size ()
{
std::lock_guard<std::mutex> lock (mutex);
return roots.size ();
}
nano::active_transactions::active_transactions (nano::node & node_a) :
node (node_a),
started (false),

View file

@ -79,6 +79,7 @@ public:
void confirm_if_quorum (nano::transaction const &);
void log_votes (nano::tally_t const &);
bool publish (std::shared_ptr<nano::block> block_a);
size_t last_votes_size ();
void stop ();
nano::node & node;
std::unordered_map<nano::account, nano::vote_info> last_votes;
@ -117,6 +118,8 @@ public:
void update_difficulty (nano::block const &);
std::deque<std::shared_ptr<nano::block>> list_blocks (bool = false);
void erase (nano::block const &);
bool empty ();
size_t size ();
void stop ();
bool publish (std::shared_ptr<nano::block> block_a);
boost::multi_index_container<
@ -129,6 +132,7 @@ public:
std::greater<uint64_t>>>>
roots;
std::unordered_map<nano::block_hash, std::shared_ptr<nano::election>> blocks;
std::deque<nano::election_status> list_confirmed ();
std::deque<nano::election_status> confirmed;
nano::node & node;
std::mutex mutex;
@ -194,6 +198,7 @@ public:
void add (nano::transaction const &, nano::block_hash const &, std::chrono::steady_clock::time_point = std::chrono::steady_clock::now ());
void vote (std::shared_ptr<nano::vote>);
nano::uint128_t bootstrap_threshold (nano::transaction const &);
size_t size ();
boost::multi_index_container<
nano::gap_information,
boost::multi_index::indexed_by<
@ -324,7 +329,7 @@ public:
void process_packets ();
void start ();
void stop ();
void receive_action (nano::udp_data *);
void receive_action (nano::udp_data *, nano::endpoint const &);
void rpc_action (boost::system::error_code const &, size_t);
void republish_vote (std::shared_ptr<nano::vote>);
void republish_block (std::shared_ptr<nano::block>);

View file

@ -1519,8 +1519,8 @@ void nano::rpc_handler::confirmation_history ()
}
if (!ec)
{
std::lock_guard<std::mutex> lock (node.active.mutex);
for (auto i (node.active.confirmed.begin ()), n (node.active.confirmed.end ()); i != n; ++i)
auto confirmed (node.active.list_confirmed ());
for (auto i (confirmed.begin ()), n (confirmed.end ()); i != n; ++i)
{
if (hash.is_zero () || i->winner->hash () == hash)
{

View file

@ -758,9 +758,11 @@ wallets (wallets_a)
void nano::wallet::enter_initial_password ()
{
std::lock_guard<std::recursive_mutex> lock (store.mutex);
nano::raw_key password_l;
store.password.value (password_l);
{
std::lock_guard<std::recursive_mutex> lock (store.mutex);
store.password.value (password_l);
}
if (password_l.data.is_zero ())
{
auto transaction (wallets.tx_begin_write ());
@ -1320,7 +1322,7 @@ void nano::wallet::work_cache_blocking (nano::account const & account_a, nano::b
BOOST_LOG (wallets.node.log) << "Work generation for " << root_a.to_string () << ", with a difficulty of " << difficulty << " complete: " << (std::chrono::duration_cast<std::chrono::microseconds> (std::chrono::steady_clock::now () - begin).count ()) << " us";
}
auto transaction (wallets.tx_begin_write ());
if (store.exists (transaction, account_a))
if (live () && store.exists (transaction, account_a))
{
work_update (transaction, account_a, root_a, work);
}
@ -1439,6 +1441,8 @@ void nano::wallets::destroy (nano::uint256_union const & id_a)
{
std::lock_guard<std::mutex> lock (mutex);
auto transaction (tx_begin_write ());
// action_mutex should be after transactions to prevent deadlocks in deterministic_insert () & insert_adhoc ()
std::lock_guard<std::mutex> action_lock (action_mutex);
auto existing (items.find (id_a));
assert (existing != items.end ());
auto wallet (existing->second);
@ -1491,7 +1495,7 @@ void nano::wallets::reload ()
void nano::wallets::do_wallet_actions ()
{
std::unique_lock<std::mutex> lock (mutex);
std::unique_lock<std::mutex> action_lock (action_mutex);
while (!stopped)
{
if (!actions.empty ())
@ -1502,16 +1506,16 @@ void nano::wallets::do_wallet_actions ()
actions.erase (first);
if (wallet->live ())
{
lock.unlock ();
action_lock.unlock ();
observer (true);
current (*wallet);
observer (false);
lock.lock ();
action_lock.lock ();
}
}
else
{
condition.wait (lock);
condition.wait (action_lock);
}
}
}
@ -1519,7 +1523,7 @@ void nano::wallets::do_wallet_actions ()
void nano::wallets::queue_wallet_action (nano::uint128_t const & amount_a, std::shared_ptr<nano::wallet> wallet_a, std::function<void(nano::wallet &)> const & action_a)
{
{
std::lock_guard<std::mutex> lock (mutex);
std::lock_guard<std::mutex> action_lock (action_mutex);
actions.insert (std::make_pair (amount_a, std::make_pair (wallet_a, std::move (action_a))));
}
condition.notify_all ();
@ -1580,7 +1584,7 @@ bool nano::wallets::exists (nano::transaction const & transaction_a, nano::publi
void nano::wallets::stop ()
{
{
std::lock_guard<std::mutex> lock (mutex);
std::lock_guard<std::mutex> action_lock (action_mutex);
stopped = true;
actions.clear ();
}

View file

@ -190,13 +190,14 @@ public:
std::unordered_map<nano::uint256_union, std::shared_ptr<nano::wallet>> items;
std::multimap<nano::uint128_t, std::pair<std::shared_ptr<nano::wallet>, std::function<void(nano::wallet &)>>, std::greater<nano::uint128_t>> actions;
std::mutex mutex;
std::mutex action_mutex;
std::condition_variable condition;
nano::kdf kdf;
MDB_dbi handle;
MDB_dbi send_action_ids;
nano::node & node;
nano::mdb_env & env;
bool stopped;
std::atomic<bool> stopped;
boost::thread thread;
static nano::uint128_t const generate_priority;
static nano::uint128_t const high_priority;

View file

@ -734,7 +734,7 @@ uniquer (uniquer_a)
std::shared_ptr<nano::vote> nano::vote_uniquer::unique (std::shared_ptr<nano::vote> vote_a)
{
auto result (vote_a);
if (result != nullptr)
if (result != nullptr && !result->blocks.empty ())
{
if (!result->blocks[0].which ())
{

View file

@ -201,13 +201,13 @@ TEST (node, fork_storm)
empty = 0;
single = 0;
std::for_each (system.nodes.begin (), system.nodes.end (), [&](std::shared_ptr<nano::node> const & node_a) {
if (node_a->active.roots.empty ())
if (node_a->active.empty ())
{
++empty;
}
else
{
if (node_a->active.roots.begin ()->election->last_votes.size () == 1)
if (node_a->active.roots.begin ()->election->last_votes_size () == 1)
{
++single;
}
@ -409,11 +409,14 @@ TEST (wallets, rep_scan)
nano::system system (24000, 1);
auto & node (*system.nodes[0]);
auto wallet (system.wallet (0));
auto transaction (node.wallets.tx_begin_write ());
for (auto i (0); i < 10000; ++i)
{
wallet->deterministic_insert (transaction);
auto transaction (node.wallets.tx_begin_write ());
for (auto i (0); i < 10000; ++i)
{
wallet->deterministic_insert (transaction);
}
}
auto transaction (node.store.tx_begin_read ());
auto begin (std::chrono::steady_clock::now ());
node.wallets.foreach_representative (transaction, [](nano::public_key const & pub_a, nano::raw_key const & prv_a) {
});