Add iterators for receivable entries to nano::ledger.
This commit is contained in:
parent
ea579c76c0
commit
b7888ac265
5 changed files with 209 additions and 0 deletions
|
|
@ -5559,3 +5559,98 @@ TEST (ledger, head_block)
|
|||
auto tx = store.tx_begin_read ();
|
||||
ASSERT_EQ (*nano::dev::genesis, *ledger.head_block (tx, nano::dev::genesis_key.pub));
|
||||
}
|
||||
|
||||
// Test that nullopt can be returned when there are no receivable entries
|
||||
TEST (ledger_receivable, upper_bound_account_none)
|
||||
{
|
||||
auto ctx = nano::test::context::ledger_empty ();
|
||||
ASSERT_EQ (ctx.ledger ().receivable_end (), ctx.ledger ().receivable_upper_bound (ctx.store ().tx_begin_read (), 0));
|
||||
}
|
||||
|
||||
// Test behavior of ledger::receivable_upper_bound when there are receivable entries for multiple accounts
|
||||
TEST (ledger_receivable, upper_bound_account_key)
|
||||
{
|
||||
auto ctx = nano::test::context::ledger_empty ();
|
||||
nano::block_builder builder;
|
||||
nano::keypair key;
|
||||
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 - nano::Gxrb_ratio)
|
||||
.link (key.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*ctx.pool ().generate (nano::dev::genesis->hash ()))
|
||||
.build ();
|
||||
ASSERT_EQ (nano::block_status::progress, ctx.ledger ().process (ctx.store ().tx_begin_write (), send1));
|
||||
auto send2 = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (send1->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 2 * nano::Gxrb_ratio)
|
||||
.link (nano::dev::genesis_key.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*ctx.pool ().generate (send1->hash ()))
|
||||
.build ();
|
||||
ASSERT_EQ (nano::block_status::progress, ctx.ledger ().process (ctx.store ().tx_begin_write (), send2));
|
||||
auto tx = ctx.store ().tx_begin_read ();
|
||||
auto & ledger = ctx.ledger ();
|
||||
auto next1 = ledger.receivable_upper_bound (tx, nano::dev::genesis_key.pub);
|
||||
auto next2 = ledger.receivable_upper_bound (tx, key.pub);
|
||||
// Depending on which is greater but only one should have a value
|
||||
ASSERT_TRUE (next1 == ledger.receivable_end () xor next2 == ledger.receivable_end ());
|
||||
// The account returned should be after the one we searched for
|
||||
ASSERT_TRUE (next1 == ledger.receivable_end () || next1->first.account == key.pub);
|
||||
ASSERT_TRUE (next2 == ledger.receivable_end () || next2->first.account == nano::dev::genesis_key.pub);
|
||||
auto next3 = ledger.receivable_upper_bound (tx, nano::dev::genesis_key.pub, 0);
|
||||
auto next4 = ledger.receivable_upper_bound (tx, key.pub, 0);
|
||||
// Neither account has more than one receivable
|
||||
ASSERT_TRUE (next3 != ledger.receivable_end () && next4 != ledger.receivable_end ());
|
||||
auto next5 = ledger.receivable_upper_bound (tx, next3->first.account, next3->first.hash);
|
||||
auto next6 = ledger.receivable_upper_bound (tx, next4->first.account, next4->first.hash);
|
||||
ASSERT_TRUE (next5 == ledger.receivable_end () && next6 == ledger.receivable_end ());
|
||||
ASSERT_EQ (ledger.receivable_end (), ++next3);
|
||||
ASSERT_EQ (ledger.receivable_end (), ++next4);
|
||||
}
|
||||
|
||||
// Test that multiple receivable entries for the same account
|
||||
TEST (ledger_receivable, key_two)
|
||||
{
|
||||
auto ctx = nano::test::context::ledger_empty ();
|
||||
nano::block_builder builder;
|
||||
nano::keypair key;
|
||||
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 - nano::Gxrb_ratio)
|
||||
.link (key.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*ctx.pool ().generate (nano::dev::genesis->hash ()))
|
||||
.build ();
|
||||
ASSERT_EQ (nano::block_status::progress, ctx.ledger ().process (ctx.store ().tx_begin_write (), send1));
|
||||
auto send2 = builder
|
||||
.state ()
|
||||
.account (nano::dev::genesis_key.pub)
|
||||
.previous (send1->hash ())
|
||||
.representative (nano::dev::genesis_key.pub)
|
||||
.balance (nano::dev::constants.genesis_amount - 2 * nano::Gxrb_ratio)
|
||||
.link (key.pub)
|
||||
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
||||
.work (*ctx.pool ().generate (send1->hash ()))
|
||||
.build ();
|
||||
ASSERT_EQ (nano::block_status::progress, ctx.ledger ().process (ctx.store ().tx_begin_write (), send2));
|
||||
auto tx = ctx.store ().tx_begin_read ();
|
||||
auto & ledger = ctx.ledger ();
|
||||
auto next1 = ledger.receivable_upper_bound (tx, key.pub, 0);
|
||||
ASSERT_TRUE (next1 != ledger.receivable_end () && next1->first.account == key.pub);
|
||||
auto next2 = ledger.receivable_upper_bound (tx, key.pub, next1->first.hash);
|
||||
ASSERT_TRUE (next2 != ledger.receivable_end () && next2->first.account == key.pub);
|
||||
ASSERT_NE (next1->first.hash, next2->first.hash);
|
||||
ASSERT_EQ (next2, ++next1);
|
||||
ASSERT_EQ (ledger.receivable_end (), ++next1);
|
||||
ASSERT_EQ (ledger.receivable_end (), ++next2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1545,6 +1545,36 @@ uint64_t nano::ledger::height (store::transaction const & transaction, nano::blo
|
|||
return block_l->sideband ().height;
|
||||
}
|
||||
|
||||
std::optional<std::pair<nano::pending_key, nano::pending_info>> nano::ledger::receivable_lower_bound (store::transaction const & tx, nano::account const & account, nano::block_hash const & hash) const
|
||||
{
|
||||
auto result = store.pending.begin (tx, { account, hash });
|
||||
if (result == store.pending.end ())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
return *result;
|
||||
}
|
||||
|
||||
nano::receivable_iterator nano::ledger::receivable_end () const
|
||||
{
|
||||
return nano::receivable_iterator{};
|
||||
}
|
||||
|
||||
nano::receivable_iterator nano::ledger::receivable_upper_bound (store::transaction const & tx, nano::account const & account) const
|
||||
{
|
||||
return receivable_iterator{ *this, tx, receivable_lower_bound (tx, account.number () + 1, 0) };
|
||||
}
|
||||
|
||||
nano::receivable_iterator nano::ledger::receivable_upper_bound (store::transaction const & tx, nano::account const & account, nano::block_hash const & hash) const
|
||||
{
|
||||
auto result = receivable_lower_bound (tx, account, hash.number () + 1);
|
||||
if (!result || result.value ().first.account != account)
|
||||
{
|
||||
return nano::receivable_iterator{ *this, tx, std::nullopt };
|
||||
}
|
||||
return nano::receivable_iterator{ *this, tx, result };
|
||||
}
|
||||
|
||||
nano::uncemented_info::uncemented_info (nano::block_hash const & cemented_frontier, nano::block_hash const & frontier, nano::account const & account) :
|
||||
cemented_frontier (cemented_frontier), frontier (frontier), account (account)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <nano/secure/account_info.hpp>
|
||||
#include <nano/secure/generate_cache_flags.hpp>
|
||||
#include <nano/secure/ledger_cache.hpp>
|
||||
#include <nano/secure/pending_info.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
|
|
@ -36,6 +37,8 @@ public:
|
|||
|
||||
class ledger final
|
||||
{
|
||||
friend class receivable_iterator;
|
||||
|
||||
public:
|
||||
ledger (nano::store::component &, nano::stats &, nano::ledger_constants & constants, nano::generate_cache_flags const & = nano::generate_cache_flags{});
|
||||
/**
|
||||
|
|
@ -84,6 +87,11 @@ public:
|
|||
static nano::epoch version (nano::block const & block);
|
||||
nano::epoch version (store::transaction const & transaction, nano::block_hash const & hash) const;
|
||||
uint64_t height (store::transaction const & transaction, nano::block_hash const & hash) const;
|
||||
nano::receivable_iterator receivable_end () const;
|
||||
// Returns the next receivable entry for an account greater than 'account'
|
||||
nano::receivable_iterator receivable_upper_bound (store::transaction const & tx, nano::account const & account) const;
|
||||
// Returns the next receivable entry for the account 'account' with hash greater than 'hash'
|
||||
nano::receivable_iterator receivable_upper_bound (store::transaction const & tx, nano::account const & account, nano::block_hash const & hash) const;
|
||||
static nano::uint128_t const unit;
|
||||
nano::ledger_constants & constants;
|
||||
nano::store::component & store;
|
||||
|
|
@ -95,6 +103,8 @@ public:
|
|||
bool pruning{ false };
|
||||
|
||||
private:
|
||||
// Returns the next receivable entry equal or greater than 'key'
|
||||
std::optional<std::pair<nano::pending_key, nano::pending_info>> receivable_lower_bound (store::transaction const & tx, nano::account const & account, nano::block_hash const & hash) const;
|
||||
void initialize (nano::generate_cache_flags const &);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <nano/secure/ledger.hpp>
|
||||
#include <nano/secure/pending_info.hpp>
|
||||
|
||||
nano::pending_info::pending_info (nano::account const & source_a, nano::amount const & amount_a, nano::epoch epoch_a) :
|
||||
|
|
@ -70,3 +71,47 @@ bool nano::pending_key::operator< (nano::pending_key const & other_a) const
|
|||
{
|
||||
return account == other_a.account ? hash < other_a.hash : account < other_a.account;
|
||||
}
|
||||
|
||||
nano::receivable_iterator::receivable_iterator (nano::ledger const & ledger, nano::store::transaction const & tx, std::optional<std::pair<nano::pending_key, nano::pending_info>> item) :
|
||||
ledger{ &ledger },
|
||||
tx{ &tx },
|
||||
item{ item }
|
||||
{
|
||||
if (item.has_value ())
|
||||
{
|
||||
account = item.value ().first.account;
|
||||
}
|
||||
}
|
||||
|
||||
bool nano::receivable_iterator::operator== (receivable_iterator const & other) const
|
||||
{
|
||||
debug_assert (ledger == nullptr || other.ledger == nullptr || ledger == other.ledger);
|
||||
debug_assert (tx == nullptr || other.tx == nullptr || tx == other.tx);
|
||||
debug_assert (account.is_zero () || other.account.is_zero () || account == other.account);
|
||||
return item == other.item;
|
||||
}
|
||||
|
||||
bool nano::receivable_iterator::operator!= (receivable_iterator const & other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
nano::receivable_iterator & nano::receivable_iterator::operator++ ()
|
||||
{
|
||||
item = ledger->receivable_lower_bound (*tx, item.value ().first.account, item.value ().first.hash.number () + 1);
|
||||
if (item && item.value ().first.account != account)
|
||||
{
|
||||
item = std::nullopt;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::pair<nano::pending_key, nano::pending_info> const & nano::receivable_iterator::operator* () const
|
||||
{
|
||||
return item.value ();
|
||||
}
|
||||
|
||||
std::pair<nano::pending_key, nano::pending_info> const * nano::receivable_iterator::operator->() const
|
||||
{
|
||||
return &item.value ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,16 @@
|
|||
#include <nano/lib/numbers.hpp>
|
||||
#include <nano/lib/stream.hpp>
|
||||
|
||||
namespace nano
|
||||
{
|
||||
class ledger;
|
||||
}
|
||||
|
||||
namespace nano::store
|
||||
{
|
||||
class transaction;
|
||||
}
|
||||
|
||||
namespace nano
|
||||
{
|
||||
/**
|
||||
|
|
@ -33,6 +43,25 @@ public:
|
|||
nano::account account{};
|
||||
nano::block_hash hash{ 0 };
|
||||
};
|
||||
// This class iterates receivable enttries for an account
|
||||
class receivable_iterator
|
||||
{
|
||||
public:
|
||||
receivable_iterator () = default;
|
||||
receivable_iterator (nano::ledger const & ledger, nano::store::transaction const & tx, std::optional<std::pair<nano::pending_key, nano::pending_info>> item);
|
||||
bool operator== (receivable_iterator const & other) const;
|
||||
bool operator!= (receivable_iterator const & other) const;
|
||||
// Advances to the next receivable entry for the same account
|
||||
receivable_iterator & operator++ ();
|
||||
std::pair<nano::pending_key, nano::pending_info> const & operator* () const;
|
||||
std::pair<nano::pending_key, nano::pending_info> const * operator->() const;
|
||||
|
||||
private:
|
||||
nano::ledger const * ledger{ nullptr };
|
||||
nano::store::transaction const * tx{ nullptr };
|
||||
nano::account account{ 0 };
|
||||
std::optional<std::pair<nano::pending_key, nano::pending_info>> item;
|
||||
};
|
||||
} // namespace nano
|
||||
|
||||
namespace std
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue