diff --git a/crypto/ed25519-donna/ed25519-donna-batchverify.h b/crypto/ed25519-donna/ed25519-donna-batchverify.h index 43c4923b..cba751be 100644 --- a/crypto/ed25519-donna/ed25519-donna-batchverify.h +++ b/crypto/ed25519-donna/ed25519-donna-batchverify.h @@ -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); } diff --git a/nano/core_test/conflicts.cpp b/nano/core_test/conflicts.cpp index 382f9910..29f750ad 100644 --- a/nano/core_test/conflicts.cpp +++ b/nano/core_test/conflicts.cpp @@ -10,15 +10,18 @@ TEST (conflicts, start_stop) auto send1 (std::make_shared (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 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 (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 (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 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 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 (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 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); + } } diff --git a/nano/core_test/gap_cache.cpp b/nano/core_test/gap_cache.cpp index f74881f9..11717deb 100644 --- a/nano/core_test/gap_cache.cpp +++ b/nano/core_test/gap_cache.cpp @@ -20,13 +20,19 @@ TEST (gap_cache, add_existing) auto block1 (std::make_shared (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 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 (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 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 (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 (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 (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 (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 ())); diff --git a/nano/core_test/ledger.cpp b/nano/core_test/ledger.cpp index 74d3af54..9280142d 100644 --- a/nano/core_test/ledger.cpp +++ b/nano/core_test/ledger.cpp @@ -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 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 lock (node1.active.mutex); auto vote1 (std::make_shared (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 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::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send1)); ASSERT_FALSE (node1.active.vote (vote1)); auto vote2 (std::make_shared (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::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 (genesis.hash (), key2.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0)); auto vote2 (std::make_shared (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 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::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 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 (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::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::test_genesis_key.pub, nano::test_genesis_key.prv, 2, send1)); - std::unique_lock lock (node1.active.mutex); + std::lock_guard 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 (genesis.hash (), key2.pub, 0, nano::test_genesis_key.prv, nano::test_genesis_key.pub, 0)); auto vote2 (std::make_shared (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 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::test_genesis_key.pub, nano::test_genesis_key.prv, 2, send1)); - std::unique_lock 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::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 lock (node1.active.mutex); auto votes1 (node1.active.roots.find (nano::uint512_union (send1->previous (), send1->root ()))->election); auto vote1 (std::make_shared (nano::test_genesis_key.pub, nano::test_genesis_key.prv, 1, send1)); - std::unique_lock lock (node1.active.mutex); node1.vote_processor.vote_blocking (transaction, vote1, node1.network.endpoint ()); - lock.unlock (); nano::keypair key2; auto send2 (std::make_shared (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::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; diff --git a/nano/core_test/network.cpp b/nano/core_test/network.cpp index 30b3512f..3e15436f 100644 --- a/nano/core_test/network.cpp +++ b/nano/core_test/network.cpp @@ -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::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 ()); } diff --git a/nano/core_test/node.cpp b/nano/core_test/node.cpp index 515dd0dc..d4ad7f9c 100644 --- a/nano/core_test/node.cpp +++ b/nano/core_test/node.cpp @@ -32,7 +32,7 @@ TEST (node, block_store_path_failure) nano::logging logging; logging.init (path); nano::work_pool work (std::numeric_limits::max (), nullptr); - auto node (std::make_shared (init, *service, 0, path, alarm, logging, work)); + auto node (std::make_shared (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 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 (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 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 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 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 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 (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 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 (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 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 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 vote_blocks; vote_blocks.push_back (send2->hash ()); auto vote (std::make_shared (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 ()); } diff --git a/nano/core_test/rpc.cpp b/nano/core_test/rpc.cpp index 7c913cc6..e3100d8c 100644 --- a/nano/core_test/rpc.cpp +++ b/nano/core_test/rpc.cpp @@ -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 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 ()); } diff --git a/nano/core_test/wallet.cpp b/nano/core_test/wallet.cpp index b6d25b23..ef1a99d4 100644 --- a/nano/core_test/wallet.cpp +++ b/nano/core_test/wallet.cpp @@ -178,7 +178,7 @@ TEST (wallet, send_async) ASSERT_NO_ERROR (system.poll ()); } }); - bool success (false); + std::atomic success (false); system.wallet (0)->send_async (nano::test_genesis_key.pub, key2.pub, std::numeric_limits::max (), [&success](std::shared_ptr block_a) { ASSERT_NE (nullptr, block_a); success = true; }); thread.join (); ASSERT_TRUE (success); diff --git a/nano/core_test/wallets.cpp b/nano/core_test/wallets.cpp index a0a516ef..02f6823b 100644 --- a/nano/core_test/wallets.cpp +++ b/nano/core_test/wallets.cpp @@ -85,11 +85,11 @@ TEST (wallets, upgrade) auto node1 (std::make_shared (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 (transaction_source.impl.get ())); auto & mdb_store (dynamic_cast (node1->store)); auto transaction_destination (mdb_store.tx_begin_write ()); MDB_txn * tx_destination (*boost::polymorphic_downcast (transaction_destination.impl.get ())); - auto transaction_source (node1->wallets.env.tx_begin (true)); - MDB_txn * tx_source (*boost::polymorphic_downcast (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 (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 (transaction_old.impl.get ())); auto transaction_new (node1->wallets.env.tx_begin (true)); MDB_txn * tx_new (*boost::polymorphic_downcast (transaction_new.impl.get ())); + auto transaction_old (node1->store.tx_begin_write ()); + MDB_txn * tx_old (*boost::polymorphic_downcast (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; diff --git a/nano/nano_node/entry.cpp b/nano/nano_node/entry.cpp index c64bdb2f..1adc2447 100644 --- a/nano/nano_node/entry.cpp +++ b/nano/nano_node/entry.cpp @@ -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)); } diff --git a/nano/node/blockprocessor.cpp b/nano/node/blockprocessor.cpp index d93ade8d..67bcef50 100644 --- a/nano/node/blockprocessor.cpp +++ b/nano/node/blockprocessor.cpp @@ -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); } } diff --git a/nano/node/bootstrap.cpp b/nano/node/bootstrap.cpp index 9052fbc4..c195d81e 100644 --- a/nano/node/bootstrap.cpp +++ b/nano/node/bootstrap.cpp @@ -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 lock (lazy_mutex); + assert (!mutex.try_lock ()); + std::unique_lock 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) { diff --git a/nano/node/bootstrap.hpp b/nano/node/bootstrap.hpp index 8b3789a3..c43a9d69 100644 --- a/nano/node/bootstrap.hpp +++ b/nano/node/bootstrap.hpp @@ -118,7 +118,7 @@ public: std::atomic total_blocks; std::atomic runs_count; std::vector> bulk_push_targets; - bool stopped; + std::atomic stopped; nano::bootstrap_mode mode; std::mutex mutex; std::condition_variable condition; diff --git a/nano/node/common.cpp b/nano/node/common.cpp index f38ccd1f..adeb4015 100644 --- a/nano/node/common.cpp +++ b/nano/node/common.cpp @@ -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 (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 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); diff --git a/nano/node/common.hpp b/nano/node/common.hpp index 707ce057..31067d4d 100644 --- a/nano/node/common.hpp +++ b/nano/node/common.hpp @@ -313,7 +313,6 @@ public: confirm_ack (bool &, nano::stream &, nano::message_header const &, nano::vote_uniquer * = nullptr); confirm_ack (std::shared_ptr); 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 vote; diff --git a/nano/node/lmdb.cpp b/nano/node/lmdb.cpp index 59ee6731..f062359f 100644 --- a/nano/node/lmdb.cpp +++ b/nano/node/lmdb.cpp @@ -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; } } diff --git a/nano/node/node.cpp b/nano/node/node.cpp index a859bf52..b7547052 100644 --- a/nano/node/node.cpp +++ b/nano/node/node.cpp @@ -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 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 collect_seq_con_info (alarm & alarm, const std::string & name) { auto composite = std::make_unique (name); - auto count = alarm.operations.size (); + size_t count = 0; + { + std::lock_guard 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{ "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 lock (mutex); + return blocks.size (); +} + namespace nano { std::unique_ptr collect_seq_con_info (gap_cache & gap_cache, const std::string & name) { - size_t count = 0; - { - std::lock_guard (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 (name); composite->add_component (std::make_unique (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 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::shared () @@ -3268,6 +3286,12 @@ bool nano::election::publish (std::shared_ptr block_a) return result; } +size_t nano::election::last_votes_size () +{ + std::lock_guard lock (node.active.mutex); + return last_votes.size (); +} + void nano::active_transactions::request_confirm (std::unique_lock & lock_a) { std::unordered_set inactive; @@ -3282,13 +3306,12 @@ void nano::active_transactions::request_confirm (std::unique_lock & 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 & } 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 & /* 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 previous; auto previous_hash (election_l->status.winner->previous ()); @@ -3339,7 +3362,7 @@ void nano::active_transactions::request_confirm (std::unique_lock & } } } - 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 & } 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> (node.peers.representatives (std::numeric_limits::max ()))); std::unordered_set 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 & { 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 & 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 & { if (!nano::is_test_network) { - confirm_req_bundle.push_back (std::make_pair (i->election->status.winner, std::make_shared> (node.peers.list_vector (100)))); + confirm_req_bundle.push_back (std::make_pair (election_l->status.winner, std::make_shared> (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 & } } ++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 & { 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> nano::active_transactions::list_blocks return result; } +std::deque nano::active_transactions::list_confirmed () +{ + std::lock_guard lock (mutex); + return confirmed; +} + void nano::active_transactions::erase (nano::block const & block_a) { std::lock_guard lock (mutex); @@ -3641,6 +3671,18 @@ void nano::active_transactions::erase (nano::block const & block_a) } } +bool nano::active_transactions::empty () +{ + std::lock_guard lock (mutex); + return roots.empty (); +} + +size_t nano::active_transactions::size () +{ + std::lock_guard lock (mutex); + return roots.size (); +} + nano::active_transactions::active_transactions (nano::node & node_a) : node (node_a), started (false), diff --git a/nano/node/node.hpp b/nano/node/node.hpp index bda997e0..c25c170f 100644 --- a/nano/node/node.hpp +++ b/nano/node/node.hpp @@ -79,6 +79,7 @@ public: void confirm_if_quorum (nano::transaction const &); void log_votes (nano::tally_t const &); bool publish (std::shared_ptr block_a); + size_t last_votes_size (); void stop (); nano::node & node; std::unordered_map last_votes; @@ -117,6 +118,8 @@ public: void update_difficulty (nano::block const &); std::deque> list_blocks (bool = false); void erase (nano::block const &); + bool empty (); + size_t size (); void stop (); bool publish (std::shared_ptr block_a); boost::multi_index_container< @@ -129,6 +132,7 @@ public: std::greater>>> roots; std::unordered_map> blocks; + std::deque list_confirmed (); std::deque 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::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); void republish_block (std::shared_ptr); diff --git a/nano/node/rpc.cpp b/nano/node/rpc.cpp index 4b715a52..33b50e24 100644 --- a/nano/node/rpc.cpp +++ b/nano/node/rpc.cpp @@ -1519,8 +1519,8 @@ void nano::rpc_handler::confirmation_history () } if (!ec) { - std::lock_guard 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) { diff --git a/nano/node/wallet.cpp b/nano/node/wallet.cpp index 9cdf8440..784d7c2d 100644 --- a/nano/node/wallet.cpp +++ b/nano/node/wallet.cpp @@ -758,9 +758,11 @@ wallets (wallets_a) void nano::wallet::enter_initial_password () { - std::lock_guard lock (store.mutex); nano::raw_key password_l; - store.password.value (password_l); + { + std::lock_guard 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::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 lock (mutex); auto transaction (tx_begin_write ()); + // action_mutex should be after transactions to prevent deadlocks in deterministic_insert () & insert_adhoc () + std::lock_guard 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 lock (mutex); + std::unique_lock 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 wallet_a, std::function const & action_a) { { - std::lock_guard lock (mutex); + std::lock_guard 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 lock (mutex); + std::lock_guard action_lock (action_mutex); stopped = true; actions.clear (); } diff --git a/nano/node/wallet.hpp b/nano/node/wallet.hpp index f840ad75..067c4764 100644 --- a/nano/node/wallet.hpp +++ b/nano/node/wallet.hpp @@ -190,13 +190,14 @@ public: std::unordered_map> items; std::multimap, std::function>, std::greater> 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 stopped; boost::thread thread; static nano::uint128_t const generate_priority; static nano::uint128_t const high_priority; diff --git a/nano/secure/common.cpp b/nano/secure/common.cpp index 6b545103..5e894b67 100644 --- a/nano/secure/common.cpp +++ b/nano/secure/common.cpp @@ -734,7 +734,7 @@ uniquer (uniquer_a) std::shared_ptr nano::vote_uniquer::unique (std::shared_ptr vote_a) { auto result (vote_a); - if (result != nullptr) + if (result != nullptr && !result->blocks.empty ()) { if (!result->blocks[0].which ()) { diff --git a/nano/slow_test/node.cpp b/nano/slow_test/node.cpp index 1898ede6..8683a62d 100644 --- a/nano/slow_test/node.cpp +++ b/nano/slow_test/node.cpp @@ -201,13 +201,13 @@ TEST (node, fork_storm) empty = 0; single = 0; std::for_each (system.nodes.begin (), system.nodes.end (), [&](std::shared_ptr 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) { });