commit
7855c82da7
31 changed files with 642 additions and 128 deletions
|
|
@ -12,6 +12,7 @@ add_executable(
|
|||
blockprocessor.cpp
|
||||
bootstrap.cpp
|
||||
bootstrap_server.cpp
|
||||
bucketing.cpp
|
||||
cli.cpp
|
||||
confirmation_solicitor.cpp
|
||||
confirming_set.cpp
|
||||
|
|
@ -26,6 +27,7 @@ add_executable(
|
|||
ipc.cpp
|
||||
ledger.cpp
|
||||
ledger_confirm.cpp
|
||||
ledger_priority.cpp
|
||||
locks.cpp
|
||||
logging.cpp
|
||||
message.cpp
|
||||
|
|
|
|||
|
|
@ -514,6 +514,7 @@ TEST (inactive_votes_cache, election_start)
|
|||
node.vote_processor.vote (vote2, std::make_shared<nano::transport::inproc::channel> (node, node));
|
||||
// Only election for send1 should start, other blocks are missing dependencies and don't have enough final weight
|
||||
ASSERT_TIMELY_EQ (5s, 1, node.active.size ());
|
||||
ASSERT_TRUE (node.vote_router.contains (send1->hash ()));
|
||||
ASSERT_TRUE (node.vote_router.active (send1->hash ()));
|
||||
|
||||
// Confirm elections with weight quorum
|
||||
|
|
|
|||
55
nano/core_test/bucketing.cpp
Normal file
55
nano/core_test/bucketing.cpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#include <nano/node/bucketing.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
TEST (bucketing, construction)
|
||||
{
|
||||
nano::bucketing bucketing;
|
||||
ASSERT_EQ (63, bucketing.size ());
|
||||
}
|
||||
|
||||
TEST (bucketing, zero_index)
|
||||
{
|
||||
nano::bucketing bucketing;
|
||||
ASSERT_EQ (0, bucketing.bucket_index (0));
|
||||
}
|
||||
|
||||
TEST (bucketing, raw_index)
|
||||
{
|
||||
nano::bucketing bucketing;
|
||||
ASSERT_EQ (0, bucketing.bucket_index (nano::raw_ratio));
|
||||
}
|
||||
|
||||
TEST (bucketing, nano_index)
|
||||
{
|
||||
nano::bucketing bucketing;
|
||||
ASSERT_EQ (14, bucketing.bucket_index (nano::nano_ratio));
|
||||
}
|
||||
|
||||
TEST (bucketing, Knano_index)
|
||||
{
|
||||
nano::bucketing bucketing;
|
||||
ASSERT_EQ (49, bucketing.bucket_index (nano::Knano_ratio));
|
||||
}
|
||||
|
||||
TEST (bucketing, max_index)
|
||||
{
|
||||
nano::bucketing bucketing;
|
||||
ASSERT_EQ (62, bucketing.bucket_index (std::numeric_limits<nano::amount::underlying_type>::max ()));
|
||||
}
|
||||
|
||||
TEST (bucketing, indices)
|
||||
{
|
||||
nano::bucketing bucketing;
|
||||
auto indices = bucketing.bucket_indices ();
|
||||
ASSERT_EQ (63, indices.size ());
|
||||
ASSERT_EQ (indices.size (), bucketing.size ());
|
||||
|
||||
// Check that the indices are in ascending order
|
||||
ASSERT_TRUE (std::adjacent_find (indices.begin (), indices.end (), [] (auto const & lhs, auto const & rhs) {
|
||||
return lhs >= rhs;
|
||||
})
|
||||
== indices.end ());
|
||||
}
|
||||
|
|
@ -256,8 +256,7 @@ TEST (election_scheduler_bucket, construction)
|
|||
auto & node = *system.add_node ();
|
||||
|
||||
nano::scheduler::priority_bucket_config bucket_config;
|
||||
nano::scheduler::bucket bucket{ nano::Knano_ratio, bucket_config, node.active, node.stats };
|
||||
ASSERT_EQ (nano::Knano_ratio, bucket.minimum_balance);
|
||||
nano::scheduler::bucket bucket{ 0, bucket_config, node.active, node.stats };
|
||||
ASSERT_TRUE (bucket.empty ());
|
||||
ASSERT_EQ (0, bucket.size ());
|
||||
}
|
||||
|
|
@ -269,7 +268,9 @@ TEST (election_scheduler_bucket, insert_one)
|
|||
|
||||
nano::scheduler::priority_bucket_config bucket_config;
|
||||
nano::scheduler::bucket bucket{ 0, bucket_config, node.active, node.stats };
|
||||
ASSERT_FALSE (bucket.contains (block0 ()->hash ()));
|
||||
ASSERT_TRUE (bucket.push (1000, block0 ()));
|
||||
ASSERT_TRUE (bucket.contains (block0 ()->hash ()));
|
||||
ASSERT_FALSE (bucket.empty ());
|
||||
ASSERT_EQ (1, bucket.size ());
|
||||
auto blocks = bucket.blocks ();
|
||||
|
|
@ -320,10 +321,15 @@ TEST (election_scheduler_bucket, max_blocks)
|
|||
};
|
||||
nano::scheduler::bucket bucket{ 0, bucket_config, node.active, node.stats };
|
||||
ASSERT_TRUE (bucket.push (2000, block0 ()));
|
||||
ASSERT_TRUE (bucket.contains (block0 ()->hash ()));
|
||||
ASSERT_TRUE (bucket.push (900, block1 ()));
|
||||
ASSERT_TRUE (bucket.contains (block1 ()->hash ()));
|
||||
ASSERT_FALSE (bucket.push (3000, block2 ()));
|
||||
ASSERT_FALSE (bucket.contains (block2 ()->hash ()));
|
||||
ASSERT_TRUE (bucket.push (1001, block3 ())); // Evicts 2000
|
||||
ASSERT_FALSE (bucket.contains (block0 ()->hash ()));
|
||||
ASSERT_TRUE (bucket.push (1000, block0 ())); // Evicts 1001
|
||||
ASSERT_FALSE (bucket.contains (block3 ()->hash ()));
|
||||
ASSERT_EQ (2, bucket.size ());
|
||||
auto blocks = bucket.blocks ();
|
||||
ASSERT_EQ (2, blocks.size ());
|
||||
|
|
|
|||
324
nano/core_test/ledger_priority.cpp
Normal file
324
nano/core_test/ledger_priority.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/secure/common.hpp>
|
||||
#include <nano/secure/ledger.hpp>
|
||||
#include <nano/secure/ledger_set_any.hpp>
|
||||
#include <nano/secure/ledger_set_confirmed.hpp>
|
||||
#include <nano/test_common/ledger_context.hpp>
|
||||
#include <nano/test_common/make_store.hpp>
|
||||
#include <nano/test_common/testutil.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
// Test priority of genesis block
|
||||
TEST (ledger_priority, genesis_priority)
|
||||
{
|
||||
auto ctx = nano::test::ledger_empty ();
|
||||
auto & ledger = ctx.ledger ();
|
||||
auto & store = ctx.store ();
|
||||
auto transaction = ledger.tx_begin_write ();
|
||||
|
||||
auto const [priority_balance, priority_timestamp] = ledger.block_priority (transaction, *nano::dev::genesis);
|
||||
ASSERT_EQ (nano::dev::constants.genesis_amount, priority_balance);
|
||||
ASSERT_EQ (0, priority_timestamp);
|
||||
}
|
||||
|
||||
// Test priority of legacy blocks
|
||||
TEST (ledger_priority, legacy_blocks_priority)
|
||||
{
|
||||
auto ctx = nano::test::ledger_empty ();
|
||||
auto & ledger = ctx.ledger ();
|
||||
auto & pool = ctx.pool ();
|
||||
auto transaction = ledger.tx_begin_write ();
|
||||
|
||||
// Create legacy send block
|
||||
nano::keypair key1;
|
||||
nano::block_builder builder;
|
||||
auto send = builder
|
||||
.send ()
|
||||
.previous (nano::dev::genesis->hash ())
|
||||
.destination (key1.pub)
|
||||
.balance (100)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*pool.generate (nano::dev::genesis->hash ()))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
||||
|
||||
// Check send priority - should use max of current and previous balance
|
||||
auto const [send_balance, send_timestamp] = ledger.block_priority (transaction, *send);
|
||||
ASSERT_EQ (nano::dev::constants.genesis_amount, send_balance);
|
||||
ASSERT_EQ (nano::dev::genesis->sideband ().timestamp, send_timestamp);
|
||||
|
||||
// Create legacy open/receive block
|
||||
auto open = builder
|
||||
.open ()
|
||||
.source (send->hash ())
|
||||
.representative (key1.pub)
|
||||
.account (key1.pub)
|
||||
.sign (key1.prv, key1.pub)
|
||||
.work (*pool.generate (key1.pub))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open));
|
||||
|
||||
// Check open priority - should use current balance
|
||||
auto const [open_balance, open_timestamp] = ledger.block_priority (transaction, *open);
|
||||
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, open_balance);
|
||||
ASSERT_EQ (open->sideband ().timestamp, open_timestamp);
|
||||
}
|
||||
|
||||
// Test priority of a send state block
|
||||
TEST (ledger_priority, send_priority)
|
||||
{
|
||||
auto ctx = nano::test::ledger_empty ();
|
||||
auto & ledger = ctx.ledger ();
|
||||
auto & pool = ctx.pool ();
|
||||
auto transaction = ledger.tx_begin_write ();
|
||||
|
||||
nano::keypair key1;
|
||||
nano::block_builder builder;
|
||||
|
||||
// Create state send block
|
||||
auto send = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (nano::dev::genesis->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (100)
|
||||
.link (key1.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*pool.generate (nano::dev::genesis->hash ()))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
||||
|
||||
// Check priority
|
||||
auto const [priority_balance, priority_timestamp] = ledger.block_priority (transaction, *send);
|
||||
ASSERT_EQ (nano::dev::constants.genesis_amount, priority_balance);
|
||||
ASSERT_EQ (nano::dev::genesis->sideband ().timestamp, priority_timestamp);
|
||||
}
|
||||
|
||||
// Test priority of a full balance state send
|
||||
TEST (ledger_priority, full_balance_send)
|
||||
{
|
||||
auto ctx = nano::test::ledger_empty ();
|
||||
auto & ledger = ctx.ledger ();
|
||||
auto & pool = ctx.pool ();
|
||||
auto transaction = ledger.tx_begin_write ();
|
||||
|
||||
nano::keypair key1;
|
||||
nano::block_builder builder;
|
||||
|
||||
// Create state send block that sends full balance
|
||||
auto send = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (nano::dev::genesis->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (0)
|
||||
.link (key1.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*pool.generate (nano::dev::genesis->hash ()))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
||||
|
||||
// Check priority - should use previous balance since current is 0
|
||||
auto const [priority_balance, priority_timestamp] = ledger.block_priority (transaction, *send);
|
||||
ASSERT_EQ (nano::dev::constants.genesis_amount, priority_balance);
|
||||
ASSERT_EQ (nano::dev::genesis->sideband ().timestamp, priority_timestamp);
|
||||
}
|
||||
|
||||
// Test priority of state blocks with multiple operations
|
||||
TEST (ledger_priority, sequential_blocks)
|
||||
{
|
||||
auto ctx = nano::test::ledger_empty ();
|
||||
auto & ledger = ctx.ledger ();
|
||||
auto & pool = ctx.pool ();
|
||||
auto transaction = ledger.tx_begin_write ();
|
||||
|
||||
nano::keypair key1;
|
||||
nano::block_builder builder;
|
||||
|
||||
// First state send
|
||||
auto send1 = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (nano::dev::genesis->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 100)
|
||||
.link (key1.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*pool.generate (nano::dev::genesis->hash ()))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
|
||||
|
||||
// State open
|
||||
auto open = builder
|
||||
.state ()
|
||||
.account (key1.pub)
|
||||
.previous (0)
|
||||
.representative (key1.pub)
|
||||
.balance (100)
|
||||
.link (send1->hash ())
|
||||
.sign (key1.prv, key1.pub)
|
||||
.work (*pool.generate (key1.pub))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open));
|
||||
|
||||
// Second state send
|
||||
auto send2 = builder
|
||||
.state ()
|
||||
.account (key1.pub)
|
||||
.previous (open->hash ())
|
||||
.representative (key1.pub)
|
||||
.balance (50)
|
||||
.link (nano::dev::genesis_key.pub)
|
||||
.sign (key1.prv, key1.pub)
|
||||
.work (*pool.generate (open->hash ()))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
||||
|
||||
// Check priorities follow the chain
|
||||
auto const [priority_balance1, timestamp1] = ledger.block_priority (transaction, *send1);
|
||||
auto const [priority_balance2, timestamp2] = ledger.block_priority (transaction, *open);
|
||||
auto const [priority_balance3, timestamp3] = ledger.block_priority (transaction, *send2);
|
||||
|
||||
ASSERT_EQ (nano::dev::constants.genesis_amount, priority_balance1);
|
||||
ASSERT_EQ (100, priority_balance2);
|
||||
ASSERT_EQ (100, priority_balance3); // Max of current (50) and previous (100)
|
||||
|
||||
ASSERT_EQ (nano::dev::genesis->sideband ().timestamp, timestamp1);
|
||||
ASSERT_EQ (send1->sideband ().timestamp, timestamp2);
|
||||
ASSERT_EQ (open->sideband ().timestamp, timestamp3);
|
||||
}
|
||||
|
||||
// Test priority after rolling back state blocks
|
||||
TEST (ledger_priority, block_rollback)
|
||||
{
|
||||
auto ctx = nano::test::ledger_empty ();
|
||||
auto & ledger = ctx.ledger ();
|
||||
auto & pool = ctx.pool ();
|
||||
auto transaction = ledger.tx_begin_write ();
|
||||
|
||||
nano::keypair key1;
|
||||
nano::block_builder builder;
|
||||
|
||||
// First state send
|
||||
auto send1 = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (nano::dev::genesis->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 100)
|
||||
.link (key1.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*pool.generate (nano::dev::genesis->hash ()))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
|
||||
|
||||
// Get priority before rollback
|
||||
auto const [priority_before, timestamp_before] = ledger.block_priority (transaction, *send1);
|
||||
|
||||
// Rollback the send
|
||||
ASSERT_FALSE (ledger.rollback (transaction, send1->hash ()));
|
||||
|
||||
// Create new state send with different amount
|
||||
auto send2 = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (nano::dev::genesis->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 200)
|
||||
.link (key1.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*pool.generate (nano::dev::genesis->hash ()))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
||||
|
||||
// Check priority after rollback and new block
|
||||
auto const [priority_after, timestamp_after] = ledger.block_priority (transaction, *send2);
|
||||
|
||||
// Priorities should be the same since both use genesis as previous
|
||||
ASSERT_EQ (priority_before, priority_after);
|
||||
ASSERT_EQ (timestamp_before, timestamp_after);
|
||||
}
|
||||
|
||||
// Test priority with state block fork
|
||||
TEST (ledger_priority, block_fork)
|
||||
{
|
||||
auto ctx = nano::test::ledger_empty ();
|
||||
auto & ledger = ctx.ledger ();
|
||||
auto & pool = ctx.pool ();
|
||||
auto transaction = ledger.tx_begin_write ();
|
||||
|
||||
nano::keypair key1, key2;
|
||||
nano::block_builder builder;
|
||||
|
||||
// First state send
|
||||
auto send1 = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (nano::dev::genesis->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 100)
|
||||
.link (key1.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*pool.generate (nano::dev::genesis->hash ()))
|
||||
.build ();
|
||||
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
|
||||
|
||||
// Create two competing state sends
|
||||
auto send2a = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (send1->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 200)
|
||||
.link (key1.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*pool.generate (send1->hash ()))
|
||||
.build ();
|
||||
|
||||
auto send2b = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (send1->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 150)
|
||||
.link (key2.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*pool.generate (send1->hash ()))
|
||||
.build ();
|
||||
|
||||
// Process first fork
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2a));
|
||||
|
||||
// Try to process second fork
|
||||
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, send2b));
|
||||
|
||||
// Get priority of first fork
|
||||
auto const [priority_a, timestamp_a] = ledger.block_priority (transaction, *send2a);
|
||||
|
||||
// Rollback first fork
|
||||
ASSERT_FALSE (ledger.rollback (transaction, send2a->hash ()));
|
||||
|
||||
// Process second fork
|
||||
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2b));
|
||||
|
||||
// Check priority of second fork
|
||||
auto const [priority_b, timestamp_b] = ledger.block_priority (transaction, *send2b);
|
||||
|
||||
// Both should use send1's balance as previous
|
||||
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, priority_a);
|
||||
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, priority_b);
|
||||
// Both should use send1's timestamp
|
||||
ASSERT_EQ (send1->sideband ().timestamp, timestamp_a);
|
||||
ASSERT_EQ (send1->sideband ().timestamp, timestamp_b);
|
||||
}
|
||||
|
|
@ -57,7 +57,9 @@ TEST (vote_cache, insert_one_hash)
|
|||
auto rep1 = create_rep (7);
|
||||
auto hash1 = nano::test::random_hash ();
|
||||
auto vote1 = nano::test::make_vote (rep1, { hash1 }, 1024 * 1024);
|
||||
ASSERT_FALSE (vote_cache.contains (hash1));
|
||||
vote_cache.insert (vote1);
|
||||
ASSERT_TRUE (vote_cache.contains (hash1));
|
||||
ASSERT_EQ (1, vote_cache.size ());
|
||||
|
||||
auto peek1 = vote_cache.find (hash1);
|
||||
|
|
@ -265,9 +267,14 @@ TEST (vote_cache, erase)
|
|||
auto vote1 = nano::test::make_vote (rep1, { hash1 }, 1024 * 1024);
|
||||
auto vote2 = nano::test::make_vote (rep2, { hash2 }, 1024 * 1024);
|
||||
auto vote3 = nano::test::make_vote (rep3, { hash3 }, 1024 * 1024);
|
||||
ASSERT_TRUE (vote_cache.empty ());
|
||||
ASSERT_FALSE (vote_cache.contains (hash1));
|
||||
vote_cache.insert (vote1);
|
||||
vote_cache.insert (vote2);
|
||||
vote_cache.insert (vote3);
|
||||
ASSERT_TRUE (vote_cache.contains (hash1));
|
||||
ASSERT_TRUE (vote_cache.contains (hash2));
|
||||
ASSERT_TRUE (vote_cache.contains (hash3));
|
||||
ASSERT_EQ (3, vote_cache.size ());
|
||||
ASSERT_FALSE (vote_cache.empty ());
|
||||
ASSERT_FALSE (vote_cache.find (hash1).empty ());
|
||||
|
|
@ -275,11 +282,16 @@ TEST (vote_cache, erase)
|
|||
ASSERT_FALSE (vote_cache.find (hash3).empty ());
|
||||
vote_cache.erase (hash2);
|
||||
ASSERT_EQ (2, vote_cache.size ());
|
||||
ASSERT_FALSE (vote_cache.contains (hash2));
|
||||
ASSERT_FALSE (vote_cache.find (hash1).empty ());
|
||||
ASSERT_TRUE (vote_cache.find (hash2).empty ());
|
||||
ASSERT_FALSE (vote_cache.find (hash3).empty ());
|
||||
vote_cache.erase (hash1);
|
||||
vote_cache.erase (hash3);
|
||||
ASSERT_EQ (0, vote_cache.size ());
|
||||
ASSERT_FALSE (vote_cache.contains (hash1));
|
||||
ASSERT_FALSE (vote_cache.contains (hash2));
|
||||
ASSERT_FALSE (vote_cache.contains (hash3));
|
||||
ASSERT_TRUE (vote_cache.find (hash1).empty ());
|
||||
ASSERT_TRUE (vote_cache.find (hash2).empty ());
|
||||
ASSERT_TRUE (vote_cache.find (hash3).empty ());
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ nano::uint128_t const Knano_ratio = nano::uint128_t ("10000000000000000000000000
|
|||
nano::uint128_t const nano_ratio = nano::uint128_t ("1000000000000000000000000000000"); // 10^30 = 1 nano
|
||||
nano::uint128_t const raw_ratio = nano::uint128_t ("1"); // 10^0
|
||||
|
||||
using bucket_index = uint64_t;
|
||||
using priority_timestamp = uint64_t; // Priority within the bucket
|
||||
|
||||
class uint128_union
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ add_library(
|
|||
bandwidth_limiter.cpp
|
||||
blockprocessor.hpp
|
||||
blockprocessor.cpp
|
||||
bucketing.hpp
|
||||
bucketing.cpp
|
||||
bootstrap_weights_beta.hpp
|
||||
bootstrap_weights_live.hpp
|
||||
bootstrap/account_sets.hpp
|
||||
|
|
|
|||
51
nano/node/bucketing.cpp
Normal file
51
nano/node/bucketing.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/lib/utility.hpp>
|
||||
#include <nano/node/bucketing.hpp>
|
||||
#include <nano/secure/ledger.hpp>
|
||||
#include <nano/secure/ledger_set_any.hpp>
|
||||
|
||||
nano::bucketing::bucketing ()
|
||||
{
|
||||
auto build_region = [this] (uint128_t const & begin, uint128_t const & end, size_t count) {
|
||||
auto width = (end - begin) / count;
|
||||
for (auto i = 0; i < count; ++i)
|
||||
{
|
||||
minimums.push_back (begin + i * width);
|
||||
}
|
||||
};
|
||||
|
||||
minimums.push_back (uint128_t{ 0 });
|
||||
build_region (uint128_t{ 1 } << 79, uint128_t{ 1 } << 88, 1);
|
||||
build_region (uint128_t{ 1 } << 88, uint128_t{ 1 } << 92, 2);
|
||||
build_region (uint128_t{ 1 } << 92, uint128_t{ 1 } << 96, 4);
|
||||
build_region (uint128_t{ 1 } << 96, uint128_t{ 1 } << 100, 8);
|
||||
build_region (uint128_t{ 1 } << 100, uint128_t{ 1 } << 104, 16);
|
||||
build_region (uint128_t{ 1 } << 104, uint128_t{ 1 } << 108, 16);
|
||||
build_region (uint128_t{ 1 } << 108, uint128_t{ 1 } << 112, 8);
|
||||
build_region (uint128_t{ 1 } << 112, uint128_t{ 1 } << 116, 4);
|
||||
build_region (uint128_t{ 1 } << 116, uint128_t{ 1 } << 120, 2);
|
||||
minimums.push_back (uint128_t{ 1 } << 120);
|
||||
|
||||
for (auto i = 0; i < minimums.size (); ++i)
|
||||
{
|
||||
indices.push_back (i);
|
||||
}
|
||||
}
|
||||
|
||||
nano::bucket_index nano::bucketing::bucket_index (nano::amount balance) const
|
||||
{
|
||||
release_assert (!minimums.empty ());
|
||||
auto it = std::upper_bound (minimums.begin (), minimums.end (), balance);
|
||||
release_assert (it != minimums.begin ()); // There should always be a bucket with a minimum_balance of 0
|
||||
return std::distance (minimums.begin (), std::prev (it));
|
||||
}
|
||||
|
||||
std::vector<nano::bucket_index> const & nano::bucketing::bucket_indices () const
|
||||
{
|
||||
return indices;
|
||||
}
|
||||
|
||||
size_t nano::bucketing::size () const
|
||||
{
|
||||
return minimums.size ();
|
||||
}
|
||||
21
nano/node/bucketing.hpp
Normal file
21
nano/node/bucketing.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/node/fwd.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class bucketing
|
||||
{
|
||||
public:
|
||||
bucketing ();
|
||||
|
||||
nano::bucket_index bucket_index (nano::amount balance) const;
|
||||
std::vector<nano::bucket_index> const & bucket_indices () const;
|
||||
size_t size () const;
|
||||
|
||||
private:
|
||||
std::vector<nano::uint128_t> minimums;
|
||||
std::vector<nano::bucket_index> indices;
|
||||
};
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ namespace nano
|
|||
class account_sets_config;
|
||||
class active_elections;
|
||||
class block_processor;
|
||||
class bucketing;
|
||||
class bootstrap_config;
|
||||
class bootstrap_server;
|
||||
class bootstrap_service;
|
||||
|
|
|
|||
|
|
@ -4548,7 +4548,7 @@ void nano::json_handler::wallet_frontiers ()
|
|||
|
||||
void nano::json_handler::wallet_history ()
|
||||
{
|
||||
uint64_t modified_since (1);
|
||||
uint64_t modified_since (0);
|
||||
boost::optional<std::string> modified_since_text (request.get_optional<std::string> ("modified_since"));
|
||||
if (modified_since_text.is_initialized ())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <nano/node/bootstrap/bootstrap_service.hpp>
|
||||
#include <nano/node/bootstrap_weights_beta.hpp>
|
||||
#include <nano/node/bootstrap_weights_live.hpp>
|
||||
#include <nano/node/bucketing.hpp>
|
||||
#include <nano/node/confirming_set.hpp>
|
||||
#include <nano/node/daemonconfig.hpp>
|
||||
#include <nano/node/election_status.hpp>
|
||||
|
|
@ -129,6 +130,8 @@ nano::node::node (std::shared_ptr<boost::asio::io_context> io_ctx_a, std::filesy
|
|||
block_processor{ *block_processor_impl },
|
||||
confirming_set_impl{ std::make_unique<nano::confirming_set> (config.confirming_set, ledger, block_processor, stats, logger) },
|
||||
confirming_set{ *confirming_set_impl },
|
||||
bucketing_impl{ std::make_unique<nano::bucketing> () },
|
||||
bucketing{ *bucketing_impl },
|
||||
active_impl{ std::make_unique<nano::active_elections> (*this, confirming_set, block_processor) },
|
||||
active{ *active_impl },
|
||||
rep_crawler (config.rep_crawler, *this),
|
||||
|
|
@ -149,7 +152,7 @@ nano::node::node (std::shared_ptr<boost::asio::io_context> io_ctx_a, std::filesy
|
|||
generator{ *generator_impl },
|
||||
final_generator_impl{ std::make_unique<nano::vote_generator> (config, *this, ledger, wallets, vote_processor, history, network, stats, logger, /* final */ true) },
|
||||
final_generator{ *final_generator_impl },
|
||||
scheduler_impl{ std::make_unique<nano::scheduler::component> (config, *this, ledger, block_processor, active, online_reps, vote_cache, confirming_set, stats, logger) },
|
||||
scheduler_impl{ std::make_unique<nano::scheduler::component> (config, *this, ledger, bucketing, block_processor, active, online_reps, vote_cache, confirming_set, stats, logger) },
|
||||
scheduler{ *scheduler_impl },
|
||||
aggregator_impl{ std::make_unique<nano::request_aggregator> (config.request_aggregator, *this, stats, generator, final_generator, history, ledger, wallets, vote_router) },
|
||||
aggregator{ *aggregator_impl },
|
||||
|
|
@ -330,6 +333,7 @@ nano::node::node (std::shared_ptr<boost::asio::io_context> io_ctx_a, std::filesy
|
|||
logger.info (nano::log::type::node, "Work pool threads: {} ({})", work.threads.size (), (work.opencl ? "OpenCL" : "CPU"));
|
||||
logger.info (nano::log::type::node, "Work peers: {}", config.work_peers.size ());
|
||||
logger.info (nano::log::type::node, "Node ID: {}", node_id.pub.to_node_id ());
|
||||
logger.info (nano::log::type::node, "Number of buckets: {}", bucketing.size ());
|
||||
|
||||
if (!work_generation_enabled ())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -179,6 +179,8 @@ public:
|
|||
nano::block_processor & block_processor;
|
||||
std::unique_ptr<nano::confirming_set> confirming_set_impl;
|
||||
nano::confirming_set & confirming_set;
|
||||
std::unique_ptr<nano::bucketing> bucketing_impl;
|
||||
nano::bucketing & bucketing;
|
||||
std::unique_ptr<nano::active_elections> active_impl;
|
||||
nano::active_elections & active;
|
||||
nano::online_reps online_reps;
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@
|
|||
* bucket
|
||||
*/
|
||||
|
||||
nano::scheduler::bucket::bucket (nano::uint128_t minimum_balance_a, priority_bucket_config const & config_a, nano::active_elections & active_a, nano::stats & stats_a) :
|
||||
nano::scheduler::bucket::bucket (nano::bucket_index index_a, priority_bucket_config const & config_a, nano::active_elections & active_a, nano::stats & stats_a) :
|
||||
index{ index_a },
|
||||
config{ config_a },
|
||||
minimum_balance{ minimum_balance_a },
|
||||
active{ active_a },
|
||||
stats{ stats_a }
|
||||
{
|
||||
|
|
@ -34,7 +34,7 @@ bool nano::scheduler::bucket::available () const
|
|||
}
|
||||
}
|
||||
|
||||
bool nano::scheduler::bucket::election_vacancy (priority_t candidate) const
|
||||
bool nano::scheduler::bucket::election_vacancy (nano::priority_timestamp candidate) const
|
||||
{
|
||||
debug_assert (!mutex.try_lock ());
|
||||
|
||||
|
|
@ -133,6 +133,12 @@ bool nano::scheduler::bucket::push (uint64_t time, std::shared_ptr<nano::block>
|
|||
return inserted;
|
||||
}
|
||||
|
||||
bool nano::scheduler::bucket::contains (nano::block_hash const & hash) const
|
||||
{
|
||||
nano::lock_guard<nano::mutex> lock{ mutex };
|
||||
return queue.get<tag_hash> ().contains (hash);
|
||||
}
|
||||
|
||||
size_t nano::scheduler::bucket::size () const
|
||||
{
|
||||
nano::lock_guard<nano::mutex> lock{ mutex };
|
||||
|
|
@ -183,20 +189,6 @@ void nano::scheduler::bucket::dump () const
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* block_entry
|
||||
*/
|
||||
|
||||
bool nano::scheduler::bucket::block_entry::operator< (block_entry const & other_a) const
|
||||
{
|
||||
return time < other_a.time || (time == other_a.time && block->hash () < other_a.block->hash ());
|
||||
}
|
||||
|
||||
bool nano::scheduler::bucket::block_entry::operator== (block_entry const & other_a) const
|
||||
{
|
||||
return time == other_a.time && block->hash () == other_a.block->hash ();
|
||||
}
|
||||
|
||||
/*
|
||||
* priority_bucket_config
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <nano/secure/common.hpp>
|
||||
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
|
|
@ -20,13 +21,6 @@
|
|||
|
||||
namespace mi = boost::multi_index;
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class election;
|
||||
class active_elections;
|
||||
class block;
|
||||
}
|
||||
|
||||
namespace nano::scheduler
|
||||
{
|
||||
class priority_bucket_config final
|
||||
|
|
@ -53,20 +47,19 @@ public:
|
|||
class bucket final
|
||||
{
|
||||
public:
|
||||
using priority_t = uint64_t;
|
||||
nano::bucket_index const index;
|
||||
|
||||
public:
|
||||
bucket (nano::uint128_t minimum_balance, priority_bucket_config const &, nano::active_elections &, nano::stats &);
|
||||
bucket (nano::bucket_index, priority_bucket_config const &, nano::active_elections &, nano::stats &);
|
||||
~bucket ();
|
||||
|
||||
nano::uint128_t const minimum_balance;
|
||||
|
||||
bool available () const;
|
||||
bool activate ();
|
||||
void update ();
|
||||
|
||||
bool push (uint64_t time, std::shared_ptr<nano::block> block);
|
||||
|
||||
bool contains (nano::block_hash const &) const;
|
||||
size_t size () const;
|
||||
size_t election_count () const;
|
||||
bool empty () const;
|
||||
|
|
@ -75,7 +68,7 @@ public:
|
|||
void dump () const;
|
||||
|
||||
private:
|
||||
bool election_vacancy (priority_t candidate) const;
|
||||
bool election_vacancy (nano::priority_timestamp candidate) const;
|
||||
bool election_overfill () const;
|
||||
void cancel_lowest_election ();
|
||||
|
||||
|
|
@ -90,32 +83,57 @@ private: // Blocks
|
|||
uint64_t time;
|
||||
std::shared_ptr<nano::block> block;
|
||||
|
||||
bool operator< (block_entry const & other_a) const;
|
||||
bool operator== (block_entry const & other_a) const;
|
||||
};
|
||||
nano::block_hash hash () const
|
||||
{
|
||||
return block->hash ();
|
||||
}
|
||||
|
||||
std::set<block_entry> queue;
|
||||
|
||||
private: // Elections
|
||||
struct election_entry
|
||||
{
|
||||
std::shared_ptr<nano::election> election;
|
||||
nano::qualified_root root;
|
||||
priority_t priority;
|
||||
// Keep operators inlined
|
||||
bool operator< (block_entry const & other) const
|
||||
{
|
||||
return time < other.time || (time == other.time && hash () < other.hash ());
|
||||
}
|
||||
bool operator== (block_entry const & other) const
|
||||
{
|
||||
return time == other.time && hash () == other.hash ();
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
class tag_sequenced {};
|
||||
class tag_root {};
|
||||
class tag_priority {};
|
||||
class tag_hash {};
|
||||
// clang-format on
|
||||
|
||||
// clang-format off
|
||||
using ordered_blocks = boost::multi_index_container<block_entry,
|
||||
mi::indexed_by<
|
||||
mi::ordered_non_unique<mi::tag<tag_priority>,
|
||||
mi::identity<block_entry>>,
|
||||
mi::hashed_unique<mi::tag<tag_hash>,
|
||||
mi::const_mem_fun<block_entry, nano::block_hash, &block_entry::hash>>
|
||||
>>;
|
||||
// clang-format on
|
||||
|
||||
ordered_blocks queue;
|
||||
|
||||
private: // Elections
|
||||
struct election_entry
|
||||
{
|
||||
std::shared_ptr<nano::election> election;
|
||||
nano::qualified_root root;
|
||||
nano::priority_timestamp priority;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
using ordered_elections = boost::multi_index_container<election_entry,
|
||||
mi::indexed_by<
|
||||
mi::sequenced<mi::tag<tag_sequenced>>,
|
||||
mi::hashed_unique<mi::tag<tag_root>,
|
||||
mi::member<election_entry, nano::qualified_root, &election_entry::root>>,
|
||||
mi::ordered_non_unique<mi::tag<tag_priority>,
|
||||
mi::member<election_entry, priority_t, &election_entry::priority>>
|
||||
mi::member<election_entry, nano::priority_timestamp, &election_entry::priority>>
|
||||
>>;
|
||||
// clang-format on
|
||||
|
||||
|
|
@ -124,4 +142,4 @@ private: // Elections
|
|||
private:
|
||||
mutable nano::mutex mutex;
|
||||
};
|
||||
} // namespace nano::scheduler
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
#include <nano/node/scheduler/optimistic.hpp>
|
||||
#include <nano/node/scheduler/priority.hpp>
|
||||
|
||||
nano::scheduler::component::component (nano::node_config & node_config, nano::node & node, nano::ledger & ledger, nano::block_processor & block_processor, nano::active_elections & active, nano::online_reps & online_reps, nano::vote_cache & vote_cache, nano::confirming_set & confirming_set, nano::stats & stats, nano::logger & logger) :
|
||||
nano::scheduler::component::component (nano::node_config & node_config, nano::node & node, nano::ledger & ledger, nano::bucketing & bucketing, nano::block_processor & block_processor, nano::active_elections & active, nano::online_reps & online_reps, nano::vote_cache & vote_cache, nano::confirming_set & confirming_set, nano::stats & stats, nano::logger & logger) :
|
||||
hinted_impl{ std::make_unique<nano::scheduler::hinted> (node_config.hinted_scheduler, node, vote_cache, active, online_reps, stats) },
|
||||
manual_impl{ std::make_unique<nano::scheduler::manual> (node) },
|
||||
optimistic_impl{ std::make_unique<nano::scheduler::optimistic> (node_config.optimistic_scheduler, node, ledger, active, node_config.network_params.network, stats) },
|
||||
priority_impl{ std::make_unique<nano::scheduler::priority> (node_config, node, ledger, block_processor, active, confirming_set, stats, logger) },
|
||||
priority_impl{ std::make_unique<nano::scheduler::priority> (node_config, node, ledger, bucketing, block_processor, active, confirming_set, stats, logger) },
|
||||
hinted{ *hinted_impl },
|
||||
manual{ *manual_impl },
|
||||
optimistic{ *optimistic_impl },
|
||||
|
|
@ -43,6 +43,11 @@ void nano::scheduler::component::stop ()
|
|||
priority.stop ();
|
||||
}
|
||||
|
||||
bool nano::scheduler::component::contains (nano::block_hash const & hash) const
|
||||
{
|
||||
return manual.contains (hash) || priority.contains (hash);
|
||||
}
|
||||
|
||||
nano::container_info nano::scheduler::component::container_info () const
|
||||
{
|
||||
nano::container_info info;
|
||||
|
|
|
|||
|
|
@ -10,12 +10,15 @@ namespace nano::scheduler
|
|||
class component final
|
||||
{
|
||||
public:
|
||||
component (nano::node_config &, nano::node &, nano::ledger &, nano::block_processor &, nano::active_elections &, nano::online_reps &, nano::vote_cache &, nano::confirming_set &, nano::stats &, nano::logger &);
|
||||
component (nano::node_config &, nano::node &, nano::ledger &, nano::bucketing &, nano::block_processor &, nano::active_elections &, nano::online_reps &, nano::vote_cache &, nano::confirming_set &, nano::stats &, nano::logger &);
|
||||
~component ();
|
||||
|
||||
void start ();
|
||||
void stop ();
|
||||
|
||||
/// Does the block exist in any of the schedulers
|
||||
bool contains (nano::block_hash const & hash) const;
|
||||
|
||||
nano::container_info container_info () const;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -46,6 +46,14 @@ void nano::scheduler::manual::push (std::shared_ptr<nano::block> const & block_a
|
|||
notify ();
|
||||
}
|
||||
|
||||
bool nano::scheduler::manual::contains (nano::block_hash const & hash) const
|
||||
{
|
||||
nano::lock_guard<nano::mutex> lock{ mutex };
|
||||
return std::any_of (queue.cbegin (), queue.cend (), [&hash] (auto const & item) {
|
||||
return std::get<0> (item)->hash () == hash;
|
||||
});
|
||||
}
|
||||
|
||||
bool nano::scheduler::manual::predicate () const
|
||||
{
|
||||
return !queue.empty ();
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ public:
|
|||
// Call action with confirmed block, may be different than what we started with
|
||||
void push (std::shared_ptr<nano::block> const &, boost::optional<nano::uint128_t> const & = boost::none);
|
||||
|
||||
bool contains (nano::block_hash const &) const;
|
||||
|
||||
nano::container_info container_info () const;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <nano/lib/blocks.hpp>
|
||||
#include <nano/node/active_elections.hpp>
|
||||
#include <nano/node/bucketing.hpp>
|
||||
#include <nano/node/election.hpp>
|
||||
#include <nano/node/node.hpp>
|
||||
#include <nano/node/scheduler/priority.hpp>
|
||||
|
|
@ -7,44 +8,20 @@
|
|||
#include <nano/secure/ledger_set_any.hpp>
|
||||
#include <nano/secure/ledger_set_confirmed.hpp>
|
||||
|
||||
nano::scheduler::priority::priority (nano::node_config & node_config, nano::node & node_a, nano::ledger & ledger_a, nano::block_processor & block_processor_a, nano::active_elections & active_a, nano::confirming_set & confirming_set_a, nano::stats & stats_a, nano::logger & logger_a) :
|
||||
nano::scheduler::priority::priority (nano::node_config & node_config, nano::node & node_a, nano::ledger & ledger_a, nano::bucketing & bucketing_a, nano::block_processor & block_processor_a, nano::active_elections & active_a, nano::confirming_set & confirming_set_a, nano::stats & stats_a, nano::logger & logger_a) :
|
||||
config{ node_config.priority_scheduler },
|
||||
node{ node_a },
|
||||
ledger{ ledger_a },
|
||||
bucketing{ bucketing_a },
|
||||
block_processor{ block_processor_a },
|
||||
active{ active_a },
|
||||
confirming_set{ confirming_set_a },
|
||||
stats{ stats_a },
|
||||
logger{ logger_a }
|
||||
{
|
||||
std::vector<nano::uint128_t> minimums;
|
||||
|
||||
auto build_region = [&minimums] (uint128_t const & begin, uint128_t const & end, size_t count) {
|
||||
auto width = (end - begin) / count;
|
||||
for (auto i = 0; i < count; ++i)
|
||||
{
|
||||
minimums.push_back (begin + i * width);
|
||||
}
|
||||
};
|
||||
|
||||
minimums.push_back (uint128_t{ 0 });
|
||||
build_region (uint128_t{ 1 } << 79, uint128_t{ 1 } << 88, 1);
|
||||
build_region (uint128_t{ 1 } << 88, uint128_t{ 1 } << 92, 2);
|
||||
build_region (uint128_t{ 1 } << 92, uint128_t{ 1 } << 96, 4);
|
||||
build_region (uint128_t{ 1 } << 96, uint128_t{ 1 } << 100, 8);
|
||||
build_region (uint128_t{ 1 } << 100, uint128_t{ 1 } << 104, 16);
|
||||
build_region (uint128_t{ 1 } << 104, uint128_t{ 1 } << 108, 16);
|
||||
build_region (uint128_t{ 1 } << 108, uint128_t{ 1 } << 112, 8);
|
||||
build_region (uint128_t{ 1 } << 112, uint128_t{ 1 } << 116, 4);
|
||||
build_region (uint128_t{ 1 } << 116, uint128_t{ 1 } << 120, 2);
|
||||
minimums.push_back (uint128_t{ 1 } << 120);
|
||||
|
||||
logger.debug (nano::log::type::election_scheduler, "Number of buckets: {}", minimums.size ());
|
||||
|
||||
for (size_t i = 0u, n = minimums.size (); i < n; ++i)
|
||||
for (auto const & index : bucketing.bucket_indices ())
|
||||
{
|
||||
auto bucket = std::make_unique<scheduler::bucket> (minimums[i], node_config.priority_bucket, active, stats);
|
||||
buckets.emplace_back (std::move (bucket));
|
||||
buckets[index] = std::make_unique<scheduler::bucket> (index, node_config.priority_bucket, active, stats);
|
||||
}
|
||||
|
||||
// Activate accounts with fresh blocks
|
||||
|
|
@ -144,14 +121,14 @@ bool nano::scheduler::priority::activate (secure::transaction const & transactio
|
|||
|
||||
if (ledger.dependents_confirmed (transaction, *block))
|
||||
{
|
||||
auto const balance = block->balance ();
|
||||
auto const previous_balance = ledger.any.block_balance (transaction, conf_info.frontier).value_or (0);
|
||||
auto const balance_priority = std::max (balance, previous_balance);
|
||||
auto const [priority_balance, priority_timestamp] = ledger.block_priority (transaction, *block);
|
||||
auto const bucket_index = bucketing.bucket_index (priority_balance);
|
||||
|
||||
bool added = false;
|
||||
{
|
||||
auto & bucket = find_bucket (balance_priority);
|
||||
added = bucket.push (account_info.modified, block);
|
||||
auto const & bucket = buckets.at (bucket_index);
|
||||
release_assert (bucket);
|
||||
added = bucket->push (account_info.modified, block);
|
||||
}
|
||||
if (added)
|
||||
{
|
||||
|
|
@ -160,7 +137,8 @@ bool nano::scheduler::priority::activate (secure::transaction const & transactio
|
|||
nano::log::arg{ "account", account.to_account () }, // TODO: Convert to lazy eval
|
||||
nano::log::arg{ "block", block },
|
||||
nano::log::arg{ "time", account_info.modified },
|
||||
nano::log::arg{ "priority", balance_priority });
|
||||
nano::log::arg{ "priority_balance", priority_balance },
|
||||
nano::log::arg{ "priority_timestamp", priority_timestamp });
|
||||
|
||||
notify ();
|
||||
}
|
||||
|
|
@ -187,6 +165,13 @@ bool nano::scheduler::priority::activate_successors (secure::transaction const &
|
|||
return result;
|
||||
}
|
||||
|
||||
bool nano::scheduler::priority::contains (nano::block_hash const & hash) const
|
||||
{
|
||||
return std::any_of (buckets.begin (), buckets.end (), [&hash] (auto const & bucket) {
|
||||
return bucket.second->contains (hash);
|
||||
});
|
||||
}
|
||||
|
||||
void nano::scheduler::priority::notify ()
|
||||
{
|
||||
condition.notify_all ();
|
||||
|
|
@ -195,21 +180,21 @@ void nano::scheduler::priority::notify ()
|
|||
std::size_t nano::scheduler::priority::size () const
|
||||
{
|
||||
return std::accumulate (buckets.begin (), buckets.end (), std::size_t{ 0 }, [] (auto const & sum, auto const & bucket) {
|
||||
return sum + bucket->size ();
|
||||
return sum + bucket.second->size ();
|
||||
});
|
||||
}
|
||||
|
||||
bool nano::scheduler::priority::empty () const
|
||||
{
|
||||
return std::all_of (buckets.begin (), buckets.end (), [] (auto const & bucket) {
|
||||
return bucket->empty ();
|
||||
return bucket.second->empty ();
|
||||
});
|
||||
}
|
||||
|
||||
bool nano::scheduler::priority::predicate () const
|
||||
{
|
||||
return std::any_of (buckets.begin (), buckets.end (), [] (auto const & bucket) {
|
||||
return bucket->available ();
|
||||
return bucket.second->available ();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -228,7 +213,7 @@ void nano::scheduler::priority::run ()
|
|||
|
||||
lock.unlock ();
|
||||
|
||||
for (auto & bucket : buckets)
|
||||
for (auto const & [index, bucket] : buckets)
|
||||
{
|
||||
if (bucket->available ())
|
||||
{
|
||||
|
|
@ -255,7 +240,7 @@ void nano::scheduler::priority::run_cleanup ()
|
|||
|
||||
lock.unlock ();
|
||||
|
||||
for (auto & bucket : buckets)
|
||||
for (auto const & [index, bucket] : buckets)
|
||||
{
|
||||
bucket->update ();
|
||||
}
|
||||
|
|
@ -265,34 +250,22 @@ void nano::scheduler::priority::run_cleanup ()
|
|||
}
|
||||
}
|
||||
|
||||
auto nano::scheduler::priority::find_bucket (nano::uint128_t priority) -> bucket &
|
||||
{
|
||||
auto it = std::upper_bound (buckets.begin (), buckets.end (), priority, [] (nano::uint128_t const & priority, std::unique_ptr<bucket> const & bucket) {
|
||||
return priority < bucket->minimum_balance;
|
||||
});
|
||||
release_assert (it != buckets.begin ()); // There should always be a bucket with a minimum_balance of 0
|
||||
it = std::prev (it);
|
||||
return **it;
|
||||
}
|
||||
|
||||
nano::container_info nano::scheduler::priority::container_info () const
|
||||
{
|
||||
auto collect_blocks = [&] () {
|
||||
nano::container_info info;
|
||||
for (auto i = 0; i < buckets.size (); ++i)
|
||||
for (auto const & [index, bucket] : buckets)
|
||||
{
|
||||
auto const & bucket = buckets[i];
|
||||
info.put (std::to_string (i), bucket->size ());
|
||||
info.put (std::to_string (index), bucket->size ());
|
||||
}
|
||||
return info;
|
||||
};
|
||||
|
||||
auto collect_elections = [&] () {
|
||||
nano::container_info info;
|
||||
for (auto i = 0; i < buckets.size (); ++i)
|
||||
for (auto const & [index, bucket] : buckets)
|
||||
{
|
||||
auto const & bucket = buckets[i];
|
||||
info.put (std::to_string (i), bucket->election_count ());
|
||||
info.put (std::to_string (index), bucket->election_count ());
|
||||
}
|
||||
return info;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
|
@ -26,7 +27,7 @@ public:
|
|||
class priority final
|
||||
{
|
||||
public:
|
||||
priority (nano::node_config &, nano::node &, nano::ledger &, nano::block_processor &, nano::active_elections &, nano::confirming_set &, nano::stats &, nano::logger &);
|
||||
priority (nano::node_config &, nano::node &, nano::ledger &, nano::bucketing &, nano::block_processor &, nano::active_elections &, nano::confirming_set &, nano::stats &, nano::logger &);
|
||||
~priority ();
|
||||
|
||||
void start ();
|
||||
|
|
@ -40,6 +41,7 @@ public:
|
|||
bool activate (nano::secure::transaction const &, nano::account const &, nano::account_info const &, nano::confirmation_height_info const &);
|
||||
bool activate_successors (nano::secure::transaction const &, nano::block const &);
|
||||
|
||||
bool contains (nano::block_hash const &) const;
|
||||
void notify ();
|
||||
std::size_t size () const;
|
||||
bool empty () const;
|
||||
|
|
@ -50,6 +52,7 @@ private: // Dependencies
|
|||
priority_config const & config;
|
||||
nano::node & node;
|
||||
nano::ledger & ledger;
|
||||
nano::bucketing & bucketing;
|
||||
nano::block_processor & block_processor;
|
||||
nano::active_elections & active;
|
||||
nano::confirming_set & confirming_set;
|
||||
|
|
@ -60,10 +63,9 @@ private:
|
|||
void run ();
|
||||
void run_cleanup ();
|
||||
bool predicate () const;
|
||||
bucket & find_bucket (nano::uint128_t priority);
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<bucket>> buckets;
|
||||
std::map<nano::bucket_index, std::unique_ptr<scheduler::bucket>> buckets;
|
||||
|
||||
bool stopped{ false };
|
||||
nano::condition_variable condition;
|
||||
|
|
|
|||
|
|
@ -202,6 +202,14 @@ std::vector<std::shared_ptr<nano::vote>> nano::vote_cache::find (const nano::blo
|
|||
return {};
|
||||
}
|
||||
|
||||
bool nano::vote_cache::contains (const nano::block_hash & hash) const
|
||||
{
|
||||
nano::lock_guard<nano::mutex> lock{ mutex };
|
||||
|
||||
auto & cache_by_hash = cache.get<tag_hash> ();
|
||||
return cache_by_hash.find (hash) != cache_by_hash.end ();
|
||||
}
|
||||
|
||||
bool nano::vote_cache::erase (const nano::block_hash & hash)
|
||||
{
|
||||
nano::lock_guard<nano::mutex> lock{ mutex };
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ public:
|
|||
* Tries to find an entry associated with block hash
|
||||
*/
|
||||
std::vector<std::shared_ptr<nano::vote>> find (nano::block_hash const & hash) const;
|
||||
bool contains (nano::block_hash const & hash) const;
|
||||
|
||||
/**
|
||||
* Removes an entry associated with block hash, does nothing if entry does not exist
|
||||
|
|
|
|||
|
|
@ -156,6 +156,13 @@ std::shared_ptr<nano::election> nano::vote_router::election (nano::block_hash co
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// This is meant to be a fast check and may return false positives if weak pointers have expired, but we don't care about that here
|
||||
bool nano::vote_router::contains (nano::block_hash const & hash) const
|
||||
{
|
||||
std::shared_lock lock{ mutex };
|
||||
return elections.contains (hash);
|
||||
}
|
||||
|
||||
void nano::vote_router::start ()
|
||||
{
|
||||
thread = std::thread{ [this] () {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ public:
|
|||
vote_router (nano::vote_cache & cache, nano::recently_confirmed_cache & recently_confirmed);
|
||||
~vote_router ();
|
||||
|
||||
void start ();
|
||||
void stop ();
|
||||
|
||||
// Add a route for 'hash' to 'election'
|
||||
// Existing routes will be replaced
|
||||
// Election must hold the block for the hash being passed in
|
||||
|
|
@ -55,9 +58,7 @@ public:
|
|||
std::unordered_map<nano::block_hash, nano::vote_code> vote (std::shared_ptr<nano::vote> const &, nano::vote_source = nano::vote_source::live, nano::block_hash filter = { 0 });
|
||||
bool active (nano::block_hash const & hash) const;
|
||||
std::shared_ptr<nano::election> election (nano::block_hash const & hash) const;
|
||||
|
||||
void start ();
|
||||
void stop ();
|
||||
bool contains (nano::block_hash const & hash) const;
|
||||
|
||||
using vote_processed_event_t = nano::observer_set<std::shared_ptr<nano::vote> const &, nano::vote_source, std::unordered_map<nano::block_hash, nano::vote_code> const &>;
|
||||
vote_processed_event_t vote_processed;
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ nano::ledger_constants::ledger_constants (nano::work_thresholds & work, nano::ne
|
|||
/* successor (block_hash) */ nano::block_hash{ 0 },
|
||||
/* balance (amount) */ nano::amount{ std::numeric_limits<nano::uint128_t>::max () },
|
||||
/* height */ uint64_t{ 1 },
|
||||
/* local_timestamp */ nano::seconds_since_epoch (),
|
||||
/* local_timestamp */ 0,
|
||||
/* epoch */ nano::epoch::epoch_0,
|
||||
/* is_send */ false,
|
||||
/* is_receive */ false,
|
||||
|
|
@ -155,7 +155,7 @@ nano::ledger_constants::ledger_constants (nano::work_thresholds & work, nano::ne
|
|||
/* successor (block_hash) */ nano::block_hash{ 0 },
|
||||
/* balance (amount) */ nano::amount{ std::numeric_limits<nano::uint128_t>::max () },
|
||||
/* height */ uint64_t{ 1 },
|
||||
/* local_timestamp */ nano::seconds_since_epoch (),
|
||||
/* local_timestamp */ 0,
|
||||
/* epoch */ nano::epoch::epoch_0,
|
||||
/* is_send */ false,
|
||||
/* is_receive */ false,
|
||||
|
|
@ -167,7 +167,7 @@ nano::ledger_constants::ledger_constants (nano::work_thresholds & work, nano::ne
|
|||
/* successor (block_hash) */ nano::block_hash{ 0 },
|
||||
/* balance (amount) */ nano::amount{ std::numeric_limits<nano::uint128_t>::max () },
|
||||
/* height */ uint64_t{ 1 },
|
||||
/* local_timestamp */ nano::seconds_since_epoch (),
|
||||
/* local_timestamp */ 0,
|
||||
/* epoch */ nano::epoch::epoch_0,
|
||||
/* is_send */ false,
|
||||
/* is_receive */ false,
|
||||
|
|
@ -179,7 +179,7 @@ nano::ledger_constants::ledger_constants (nano::work_thresholds & work, nano::ne
|
|||
/* successor (block_hash) */ nano::block_hash{ 0 },
|
||||
/* balance (amount) */ nano::amount{ std::numeric_limits<nano::uint128_t>::max () },
|
||||
/* height */ uint64_t{ 1 },
|
||||
/* local_timestamp */ nano::seconds_since_epoch (),
|
||||
/* local_timestamp */ 0,
|
||||
/* epoch */ nano::epoch::epoch_0,
|
||||
/* is_send */ false,
|
||||
/* is_receive */ false,
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace nano
|
||||
{
|
||||
class account_info;
|
||||
class keypair;
|
||||
class ledger;
|
||||
class ledger_cache;
|
||||
class ledger_constants;
|
||||
|
|
|
|||
|
|
@ -1254,6 +1254,21 @@ uint64_t nano::ledger::pruning_action (secure::write_transaction & transaction_a
|
|||
return pruned_count;
|
||||
}
|
||||
|
||||
auto nano::ledger::block_priority (nano::secure::transaction const & transaction, nano::block const & block) const -> block_priority_result
|
||||
{
|
||||
auto const balance = block.balance ();
|
||||
auto const previous_block = !block.previous ().is_zero () ? any.block_get (transaction, block.previous ()) : nullptr;
|
||||
auto const previous_balance = previous_block ? previous_block->balance () : 0;
|
||||
|
||||
// Handle full send case nicely where the balance would otherwise be 0
|
||||
auto const priority_balance = std::max (balance, block.is_send () ? previous_balance : 0);
|
||||
|
||||
// Use previous block timestamp as priority timestamp for least recently used prioritization within the same bucket
|
||||
// Account info timestamp is not used here because it will get out of sync when rollbacks happen
|
||||
auto const priority_timestamp = previous_block ? previous_block->sideband ().timestamp : block.sideband ().timestamp;
|
||||
return { priority_balance, priority_timestamp };
|
||||
}
|
||||
|
||||
// A precondition is that the store is an LMDB store
|
||||
bool nano::ledger::migrate_lmdb_to_rocksdb (std::filesystem::path const & data_path_a) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -75,13 +75,20 @@ public:
|
|||
nano::link const & epoch_link (nano::epoch) const;
|
||||
bool migrate_lmdb_to_rocksdb (std::filesystem::path const &) const;
|
||||
bool bootstrap_weight_reached () const;
|
||||
|
||||
static nano::epoch version (nano::block const & block);
|
||||
nano::epoch version (secure::transaction const &, nano::block_hash const & hash) const;
|
||||
|
||||
uint64_t cemented_count () const;
|
||||
uint64_t block_count () const;
|
||||
uint64_t account_count () const;
|
||||
uint64_t pruned_count () const;
|
||||
|
||||
// Returned priority balance is maximum of block balance and previous block balance to handle full account balance send cases
|
||||
// Returned timestamp is the previous block timestamp or the current timestamp if there's no previous block
|
||||
using block_priority_result = std::pair<nano::amount, nano::priority_timestamp>;
|
||||
block_priority_result block_priority (secure::transaction const &, nano::block const &) const;
|
||||
|
||||
nano::container_info container_info () const;
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <nano/lib/locks.hpp>
|
||||
#include <nano/lib/timer.hpp>
|
||||
#include <nano/node/fwd.hpp>
|
||||
#include <nano/node/transport/fwd.hpp>
|
||||
#include <nano/secure/account_info.hpp>
|
||||
#include <nano/store/fwd.hpp>
|
||||
|
|
@ -159,20 +160,6 @@ private:
|
|||
/* Convenience globals for gtest projects */
|
||||
namespace nano
|
||||
{
|
||||
class node;
|
||||
using uint128_t = boost::multiprecision::uint128_t;
|
||||
class keypair;
|
||||
class public_key;
|
||||
class block_hash;
|
||||
class telemetry_data;
|
||||
class network_params;
|
||||
class vote;
|
||||
class block;
|
||||
class election;
|
||||
class ledger;
|
||||
|
||||
extern nano::uint128_t const & genesis_amount;
|
||||
|
||||
namespace test
|
||||
{
|
||||
class system;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue