6028 lines
No EOL
239 KiB
C++
6028 lines
No EOL
239 KiB
C++
#include <nano/lib/blocks.hpp>
|
|
#include <nano/lib/logging.hpp>
|
|
#include <nano/lib/numbers.hpp>
|
|
#include <nano/lib/stats.hpp>
|
|
#include <nano/lib/threading.hpp>
|
|
#include <nano/node/active_elections.hpp>
|
|
#include <nano/node/election.hpp>
|
|
#include <nano/node/make_store.hpp>
|
|
#include <nano/node/scheduler/component.hpp>
|
|
#include <nano/node/scheduler/priority.hpp>
|
|
#include <nano/node/transport/inproc.hpp>
|
|
#include <nano/node/vote_router.hpp>
|
|
#include <nano/secure/ledger_set_any.hpp>
|
|
#include <nano/secure/ledger_set_confirmed.hpp>
|
|
#include <nano/secure/vote.hpp>
|
|
#include <nano/store/rocksdb/rocksdb.hpp>
|
|
#include <nano/test_common/ledger_context.hpp>
|
|
#include <nano/test_common/make_store.hpp>
|
|
#include <nano/test_common/system.hpp>
|
|
#include <nano/test_common/testutil.hpp>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <limits>
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
// Init returns an error if it can't open files at the path
|
|
TEST (ledger, store_error)
|
|
{
|
|
if (nano::rocksdb_config::using_rocksdb_in_tests ())
|
|
{
|
|
// Don't test this in rocksdb mode
|
|
GTEST_SKIP ();
|
|
}
|
|
auto ctx = nano::test::ledger_empty ();
|
|
}
|
|
|
|
// Ledger can be initialized and returns a basic query for an empty account
|
|
TEST (ledger, empty)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_read ();
|
|
nano::account account;
|
|
auto balance (ledger.any.account_balance (transaction, account));
|
|
ASSERT_FALSE (balance);
|
|
}
|
|
|
|
// Ledger can be initialized and returns a basic query for an empty account
|
|
TEST (ledger, confirmed_unconfirmed_view)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & unconfirmed = ledger;
|
|
auto & confirmed = ledger.confirmed;
|
|
}
|
|
|
|
// Genesis account should have the max balance on empty initialization
|
|
TEST (ledger, genesis_balance)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto balance = ledger.any.account_balance (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, balance);
|
|
auto info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info);
|
|
ASSERT_EQ (1, ledger.account_count ());
|
|
// Frontier time should have been updated when genesis balance was added
|
|
ASSERT_GE (nano::seconds_since_epoch (), info->modified);
|
|
ASSERT_LT (nano::seconds_since_epoch () - info->modified, 10);
|
|
// Genesis block should be confirmed by default
|
|
nano::confirmation_height_info confirmation_height_info;
|
|
ASSERT_FALSE (store.confirmation_height.get (transaction, nano::dev::genesis_key.pub, confirmation_height_info));
|
|
ASSERT_EQ (confirmation_height_info.height, 1);
|
|
ASSERT_EQ (confirmation_height_info.frontier, nano::dev::genesis->hash ());
|
|
}
|
|
|
|
TEST (ledger, process_modifies_sideband)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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 (ledger.tx_begin_write (), send1));
|
|
ASSERT_EQ (send1->sideband ().timestamp, ledger.any.block_get (ledger.tx_begin_read (), send1->hash ())->sideband ().timestamp);
|
|
}
|
|
|
|
// Create a send block and publish it.
|
|
TEST (ledger, process_send)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
auto info1 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info1);
|
|
nano::keypair key2;
|
|
nano::block_builder builder;
|
|
auto send = builder
|
|
.send ()
|
|
.previous (info1->head)
|
|
.destination (key2.pub)
|
|
.balance (50)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
nano::block_hash hash1 = send->hash ();
|
|
ASSERT_EQ (1, info1->block_count);
|
|
// This was a valid block, it should progress.
|
|
auto return1 = ledger.process (transaction, send);
|
|
ASSERT_EQ (nano::block_status::progress, return1);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, send->sideband ().account);
|
|
ASSERT_EQ (2, send->sideband ().height);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.any.block_amount (transaction, hash1));
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, send->account ());
|
|
ASSERT_EQ (50, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub).value ().number ());
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.account_receivable (transaction, key2.pub));
|
|
auto info2 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info2);
|
|
ASSERT_EQ (2, info2->block_count);
|
|
auto latest6 = ledger.any.block_get (transaction, info2->head);
|
|
ASSERT_NE (nullptr, latest6);
|
|
auto latest7 = dynamic_cast<nano::send_block *> (latest6.get ());
|
|
ASSERT_NE (nullptr, latest7);
|
|
ASSERT_EQ (*send, *latest7);
|
|
// Create an open block opening an account accepting the send we just created
|
|
auto open = builder
|
|
.open ()
|
|
.source (hash1)
|
|
.representative (key2.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
nano::block_hash hash2 (open->hash ());
|
|
// This was a valid block, it should progress.
|
|
auto return2 = ledger.process (transaction, open);
|
|
ASSERT_EQ (nano::block_status::progress, return2);
|
|
ASSERT_EQ (key2.pub, open->sideband ().account);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, open->sideband ().balance.number ());
|
|
ASSERT_EQ (1, open->sideband ().height);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.any.block_amount (transaction, hash2));
|
|
ASSERT_EQ (nano::block_status::progress, return2);
|
|
ASSERT_EQ (key2.pub, open->account ());
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.any.block_amount (transaction, hash2));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.any.account_balance (transaction, key2.pub));
|
|
ASSERT_EQ (0, ledger.account_receivable (transaction, key2.pub));
|
|
ASSERT_EQ (50, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.weight (key2.pub));
|
|
auto info3 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info3);
|
|
auto latest2 = ledger.any.block_get (transaction, info3->head);
|
|
ASSERT_NE (nullptr, latest2);
|
|
auto latest3 = dynamic_cast<nano::send_block *> (latest2.get ());
|
|
ASSERT_NE (nullptr, latest3);
|
|
ASSERT_EQ (*send, *latest3);
|
|
auto info4 = ledger.any.account_get (transaction, key2.pub);
|
|
ASSERT_TRUE (info4);
|
|
auto latest4 = ledger.any.block_get (transaction, info4->head);
|
|
ASSERT_NE (nullptr, latest4);
|
|
auto latest5 = dynamic_cast<nano::open_block *> (latest4.get ());
|
|
ASSERT_NE (nullptr, latest5);
|
|
ASSERT_EQ (*open, *latest5);
|
|
ASSERT_FALSE (ledger.rollback (transaction, hash2));
|
|
auto info5 = ledger.any.account_get (transaction, key2.pub);
|
|
ASSERT_FALSE (info5);
|
|
auto pending1 = ledger.any.pending_get (transaction, nano::pending_key (key2.pub, hash1));
|
|
ASSERT_TRUE (pending1);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, pending1->source);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, pending1->amount.number ());
|
|
ASSERT_FALSE (ledger.any.account_balance (transaction, key2.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.account_receivable (transaction, key2.pub));
|
|
ASSERT_EQ (50, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub).value ().number ());
|
|
ASSERT_EQ (50, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
auto info6 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info6);
|
|
ASSERT_EQ (hash1, info6->head);
|
|
ASSERT_FALSE (ledger.rollback (transaction, info6->head));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
auto info7 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info7);
|
|
ASSERT_EQ (1, info7->block_count);
|
|
ASSERT_EQ (info1->head, info7->head);
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key (key2.pub, hash1)));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub).value ().number ());
|
|
ASSERT_EQ (0, ledger.account_receivable (transaction, key2.pub));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, process_receive)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
auto info1 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info1);
|
|
nano::keypair key2;
|
|
nano::block_builder builder;
|
|
auto send = builder
|
|
.send ()
|
|
.previous (info1->head)
|
|
.destination (key2.pub)
|
|
.balance (50)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
nano::block_hash hash1 (send->hash ());
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
|
nano::keypair key3;
|
|
auto open = builder
|
|
.open ()
|
|
.source (hash1)
|
|
.representative (key3.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
nano::block_hash hash2 (open->hash ());
|
|
auto return1 = ledger.process (transaction, open);
|
|
ASSERT_EQ (nano::block_status::progress, return1);
|
|
ASSERT_EQ (key2.pub, open->account ());
|
|
ASSERT_EQ (key2.pub, open->sideband ().account);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, open->sideband ().balance.number ());
|
|
ASSERT_EQ (1, open->sideband ().height);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.any.block_amount (transaction, hash2));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.weight (key3.pub));
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (hash1)
|
|
.destination (key2.pub)
|
|
.balance (25)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (hash1))
|
|
.build ();
|
|
nano::block_hash hash3 = send2->hash ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
auto receive = builder
|
|
.receive ()
|
|
.previous (hash2)
|
|
.source (hash3)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (hash2))
|
|
.build ();
|
|
auto hash4 = receive->hash ();
|
|
auto return2 = ledger.process (transaction, receive);
|
|
ASSERT_EQ (key2.pub, receive->sideband ().account);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 25, receive->sideband ().balance.number ());
|
|
ASSERT_EQ (2, receive->sideband ().height);
|
|
ASSERT_EQ (25, ledger.any.block_amount (transaction, hash4).value ().number ());
|
|
ASSERT_EQ (nano::block_status::progress, return2);
|
|
ASSERT_EQ (key2.pub, receive->account ());
|
|
ASSERT_EQ (hash4, ledger.any.account_head (transaction, key2.pub));
|
|
ASSERT_EQ (25, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub).value ().number ());
|
|
ASSERT_EQ (0, ledger.account_receivable (transaction, key2.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 25, ledger.any.account_balance (transaction, key2.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 25, ledger.weight (key3.pub));
|
|
ASSERT_FALSE (ledger.rollback (transaction, hash4));
|
|
ASSERT_FALSE (ledger.any.block_successor (transaction, hash2));
|
|
ASSERT_EQ (25, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub).value ().number ());
|
|
ASSERT_EQ (25, ledger.account_receivable (transaction, key2.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.any.account_balance (transaction, key2.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.weight (key3.pub));
|
|
ASSERT_EQ (hash2, ledger.any.account_head (transaction, key2.pub));
|
|
auto pending1 = ledger.any.pending_get (transaction, nano::pending_key (key2.pub, hash3));
|
|
ASSERT_TRUE (pending1);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, pending1->source);
|
|
ASSERT_EQ (25, pending1->amount.number ());
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, rollback_receiver)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
auto info1 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info1);
|
|
nano::keypair key2;
|
|
nano::block_builder builder;
|
|
auto send = builder
|
|
.send ()
|
|
.previous (info1->head)
|
|
.destination (key2.pub)
|
|
.balance (50)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
nano::block_hash hash1 (send->hash ());
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
|
nano::keypair key3;
|
|
auto open = builder
|
|
.open ()
|
|
.source (hash1)
|
|
.representative (key3.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
nano::block_hash hash2 (open->hash ());
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open));
|
|
ASSERT_EQ (hash2, ledger.any.account_head (transaction, key2.pub));
|
|
ASSERT_EQ (50, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub).value ().number ());
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.any.account_balance (transaction, key2.pub));
|
|
ASSERT_EQ (50, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.weight (key3.pub));
|
|
ASSERT_FALSE (ledger.rollback (transaction, hash1));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub));
|
|
ASSERT_FALSE (ledger.any.account_balance (transaction, key2.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
ASSERT_EQ (0, ledger.weight (key3.pub));
|
|
ASSERT_FALSE (ledger.any.account_get (transaction, key2.pub));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ key2.pub, hash1 }));
|
|
}
|
|
|
|
TEST (ledger, rollback_representation)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key5;
|
|
nano::block_builder builder;
|
|
auto change1 = builder
|
|
.change ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (key5.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, change1));
|
|
nano::keypair key3;
|
|
auto change2 = builder
|
|
.change ()
|
|
.previous (change1->hash ())
|
|
.representative (key3.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (change1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, change2));
|
|
nano::keypair key2;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (change2->hash ())
|
|
.destination (key2.pub)
|
|
.balance (50)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (change2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
|
|
nano::keypair key4;
|
|
auto open = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (key4.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open));
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (send1->hash ())
|
|
.destination (key2.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (open->hash ())
|
|
.source (send2->hash ())
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (open->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_EQ (1, ledger.weight (key3.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 1, ledger.weight (key4.pub));
|
|
auto info1 = ledger.any.account_get (transaction, key2.pub);
|
|
ASSERT_TRUE (info1);
|
|
ASSERT_EQ (key4.pub, info1->representative);
|
|
ASSERT_FALSE (ledger.rollback (transaction, receive1->hash ()));
|
|
auto info2 = ledger.any.account_get (transaction, key2.pub);
|
|
ASSERT_TRUE (info2);
|
|
ASSERT_EQ (key4.pub, info2->representative);
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.weight (key4.pub));
|
|
ASSERT_FALSE (ledger.rollback (transaction, open->hash ()));
|
|
ASSERT_EQ (1, ledger.weight (key3.pub));
|
|
ASSERT_EQ (0, ledger.weight (key4.pub));
|
|
ledger.rollback (transaction, send1->hash ());
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (key3.pub));
|
|
auto info3 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info3);
|
|
ASSERT_EQ (key3.pub, info3->representative);
|
|
ASSERT_FALSE (ledger.rollback (transaction, change2->hash ()));
|
|
auto info4 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info4);
|
|
ASSERT_EQ (key5.pub, info4->representative);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (key5.pub));
|
|
ASSERT_EQ (0, ledger.weight (key3.pub));
|
|
}
|
|
|
|
TEST (ledger, receive_rollback)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
auto send = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.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));
|
|
auto receive = builder
|
|
.receive ()
|
|
.previous (send->hash ())
|
|
.source (send->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive));
|
|
ASSERT_FALSE (ledger.rollback (transaction, receive->hash ()));
|
|
}
|
|
|
|
TEST (ledger, process_duplicate)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
auto info1 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info1);
|
|
nano::keypair key2;
|
|
nano::block_builder builder;
|
|
auto send = builder
|
|
.send ()
|
|
.previous (info1->head)
|
|
.destination (key2.pub)
|
|
.balance (50)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
nano::block_hash hash1 (send->hash ());
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
|
ASSERT_EQ (nano::block_status::old, ledger.process (transaction, send));
|
|
auto open = builder
|
|
.open ()
|
|
.source (hash1)
|
|
.representative (1)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open));
|
|
ASSERT_EQ (nano::block_status::old, ledger.process (transaction, open));
|
|
}
|
|
|
|
TEST (ledger, representative_genesis)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto latest = ledger.any.account_head (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_FALSE (latest.is_zero ());
|
|
ASSERT_EQ (nano::dev::genesis->hash (), ledger.representative (transaction, latest));
|
|
}
|
|
|
|
TEST (ledger, weight)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
}
|
|
|
|
TEST (ledger, representative_change)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::keypair key2;
|
|
auto & pool = ctx.pool ();
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
auto info1 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info1);
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.change ()
|
|
.previous (info1->head)
|
|
.representative (key2.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
auto return1 (ledger.process (transaction, block));
|
|
ASSERT_EQ (nano::block_status::progress, return1);
|
|
ASSERT_EQ (0, ledger.any.block_amount (transaction, block->hash ()).value ().number ());
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, block->account ());
|
|
ASSERT_EQ (0, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (key2.pub));
|
|
auto info2 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info2);
|
|
ASSERT_EQ (block->hash (), info2->head);
|
|
ASSERT_FALSE (ledger.rollback (transaction, info2->head));
|
|
auto info3 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info3);
|
|
ASSERT_EQ (info1->head, info3->head);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
}
|
|
|
|
TEST (ledger, send_fork)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
nano::keypair key2;
|
|
nano::keypair key3;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
auto info1 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info1);
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.send ()
|
|
.previous (info1->head)
|
|
.destination (key2.pub)
|
|
.balance (100)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block));
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (info1->head)
|
|
.destination (key3.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, block2));
|
|
}
|
|
|
|
TEST (ledger, receive_fork)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
nano::keypair key2;
|
|
nano::keypair key3;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
auto info1 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info1);
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.send ()
|
|
.previous (info1->head)
|
|
.destination (key2.pub)
|
|
.balance (100)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block));
|
|
auto block2 = builder
|
|
.open ()
|
|
.source (block->hash ())
|
|
.representative (key2.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block2));
|
|
auto block3 = builder
|
|
.change ()
|
|
.previous (block2->hash ())
|
|
.representative (key3.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (block2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block3));
|
|
auto block4 = builder
|
|
.send ()
|
|
.previous (block->hash ())
|
|
.destination (key2.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block4));
|
|
auto block5 = builder
|
|
.receive ()
|
|
.previous (block2->hash ())
|
|
.source (block4->hash ())
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (block2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, block5));
|
|
}
|
|
|
|
TEST (ledger, open_fork)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
nano::keypair key2;
|
|
nano::keypair key3;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
auto info1 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info1);
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.send ()
|
|
.previous (info1->head)
|
|
.destination (key2.pub)
|
|
.balance (100)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block));
|
|
auto block2 = builder
|
|
.open ()
|
|
.source (block->hash ())
|
|
.representative (key2.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block2));
|
|
auto block3 = builder
|
|
.open ()
|
|
.source (block->hash ())
|
|
.representative (key3.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, block3));
|
|
}
|
|
|
|
TEST (ledger, representation_changes)
|
|
{
|
|
auto store{ nano::test::make_store () };
|
|
nano::keypair key1;
|
|
nano::rep_weights rep_weights{ store->rep_weight };
|
|
ASSERT_EQ (0, rep_weights.get (key1.pub));
|
|
rep_weights.put (key1.pub, 1);
|
|
ASSERT_EQ (1, rep_weights.get (key1.pub));
|
|
rep_weights.put (key1.pub, 2);
|
|
ASSERT_EQ (2, rep_weights.get (key1.pub));
|
|
}
|
|
|
|
TEST (ledger, delete_rep_weight_of_zero)
|
|
{
|
|
auto store{ nano::test::make_store () };
|
|
nano::rep_weights rep_weights{ store->rep_weight };
|
|
auto txn{ store->tx_begin_write () };
|
|
rep_weights.add (txn, 1, 100);
|
|
rep_weights.add (txn, 2, 200);
|
|
ASSERT_EQ (2, rep_weights.size ());
|
|
rep_weights.move_add_sub (txn, 2, 100, 3, 120);
|
|
ASSERT_EQ (3, rep_weights.size ());
|
|
ASSERT_EQ (3, store->rep_weight.count (txn));
|
|
|
|
// Reduce rep weights to 0
|
|
rep_weights.sub (txn, 1, 100);
|
|
ASSERT_EQ (2, rep_weights.size ());
|
|
ASSERT_EQ (2, store->rep_weight.count (txn));
|
|
|
|
rep_weights.move_add_sub (txn, 3, 120, 2, 100);
|
|
ASSERT_EQ (1, rep_weights.size ());
|
|
ASSERT_EQ (1, store->rep_weight.count (txn));
|
|
|
|
rep_weights.sub (txn, 2, 200);
|
|
ASSERT_EQ (0, rep_weights.size ());
|
|
ASSERT_EQ (0, store->rep_weight.count (txn));
|
|
}
|
|
|
|
TEST (ledger, rep_cache_min_weight)
|
|
{
|
|
auto store{ nano::test::make_store () };
|
|
nano::uint128_t min_weight{ 10 };
|
|
nano::rep_weights rep_weights{ store->rep_weight, min_weight };
|
|
auto txn{ store->tx_begin_write () };
|
|
|
|
// one below min weight
|
|
rep_weights.add (txn, 1, 9);
|
|
ASSERT_EQ (0, rep_weights.size ());
|
|
ASSERT_EQ (1, store->rep_weight.count (txn));
|
|
|
|
// exactly min weight
|
|
rep_weights.add (txn, 1, 1);
|
|
ASSERT_EQ (1, rep_weights.size ());
|
|
ASSERT_EQ (1, store->rep_weight.count (txn));
|
|
|
|
// above min weight
|
|
rep_weights.add (txn, 1, 1);
|
|
ASSERT_EQ (1, rep_weights.size ());
|
|
ASSERT_EQ (1, store->rep_weight.count (txn));
|
|
|
|
// fall blow min weight
|
|
rep_weights.sub (txn, 1, 5);
|
|
ASSERT_EQ (0, rep_weights.size ());
|
|
ASSERT_EQ (1, store->rep_weight.count (txn));
|
|
}
|
|
|
|
TEST (ledger, representation)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto & rep_weights = ledger.rep_weights;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, rep_weights.get (nano::dev::genesis_key.pub));
|
|
nano::keypair key2;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key2.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 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, block1));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, rep_weights.get (nano::dev::genesis_key.pub));
|
|
nano::keypair key3;
|
|
auto block2 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (key3.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block2));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key2.pub));
|
|
ASSERT_EQ (100, rep_weights.get (key3.pub));
|
|
auto block3 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key2.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 200)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block3));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 200, rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key2.pub));
|
|
ASSERT_EQ (100, rep_weights.get (key3.pub));
|
|
auto block4 = builder
|
|
.receive ()
|
|
.previous (block2->hash ())
|
|
.source (block3->hash ())
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (block2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block4));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 200, rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key2.pub));
|
|
ASSERT_EQ (200, rep_weights.get (key3.pub));
|
|
nano::keypair key4;
|
|
auto block5 = builder
|
|
.change ()
|
|
.previous (block4->hash ())
|
|
.representative (key4.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (block4->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block5));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 200, rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key2.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key3.pub));
|
|
ASSERT_EQ (200, rep_weights.get (key4.pub));
|
|
nano::keypair key5;
|
|
auto block6 = builder
|
|
.send ()
|
|
.previous (block5->hash ())
|
|
.destination (key5.pub)
|
|
.balance (100)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (block5->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block6));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 200, rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key2.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key3.pub));
|
|
ASSERT_EQ (100, rep_weights.get (key4.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key5.pub));
|
|
nano::keypair key6;
|
|
auto block7 = builder
|
|
.open ()
|
|
.source (block6->hash ())
|
|
.representative (key6.pub)
|
|
.account (key5.pub)
|
|
.sign (key5.prv, key5.pub)
|
|
.work (*pool.generate (key5.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block7));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 200, rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key2.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key3.pub));
|
|
ASSERT_EQ (100, rep_weights.get (key4.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key5.pub));
|
|
ASSERT_EQ (100, rep_weights.get (key6.pub));
|
|
auto block8 = builder
|
|
.send ()
|
|
.previous (block6->hash ())
|
|
.destination (key5.pub)
|
|
.balance (0)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (block6->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block8));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 200, rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key2.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key3.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key4.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key5.pub));
|
|
ASSERT_EQ (100, rep_weights.get (key6.pub));
|
|
auto block9 = builder
|
|
.receive ()
|
|
.previous (block7->hash ())
|
|
.source (block8->hash ())
|
|
.sign (key5.prv, key5.pub)
|
|
.work (*pool.generate (block7->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block9));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 200, rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key2.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key3.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key4.pub));
|
|
ASSERT_EQ (0, rep_weights.get (key5.pub));
|
|
ASSERT_EQ (200, rep_weights.get (key6.pub));
|
|
}
|
|
|
|
TEST (ledger, double_open)
|
|
{
|
|
nano::logger logger;
|
|
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
|
|
ASSERT_TRUE (!store->init_error ());
|
|
nano::stats stats{ logger };
|
|
nano::ledger ledger (*store, nano::dev::constants, stats, logger);
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::keypair key2;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key2.pub)
|
|
.balance (1)
|
|
.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));
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (key2.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
auto open2 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, open2));
|
|
}
|
|
|
|
TEST (ledger, double_receive)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key2;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key2.pub)
|
|
.balance (1)
|
|
.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));
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (key2.pub)
|
|
.account (key2.pub)
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (open1->hash ())
|
|
.source (send1->hash ())
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (open1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::unreceivable, ledger.process (transaction, receive1));
|
|
}
|
|
|
|
TEST (votes, check_signature)
|
|
{
|
|
nano::test::system system;
|
|
nano::node_config node_config = system.default_config ();
|
|
node_config.online_weight_minimum = std::numeric_limits<nano::uint128_t>::max ();
|
|
auto & node1 = *system.add_node (node_config);
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 100)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
{
|
|
auto transaction = node1.ledger.tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, send1));
|
|
}
|
|
auto election1 = nano::test::start_election (system, node1, send1->hash ());
|
|
ASSERT_EQ (1, election1->votes ().size ());
|
|
auto vote1 = nano::test::make_vote (nano::dev::genesis_key, { send1 }, nano::vote::timestamp_min * 1, 0);
|
|
vote1->signature.bytes[0] ^= 1;
|
|
ASSERT_EQ (nano::vote_code::invalid, node1.vote_processor.vote_blocking (vote1, std::make_shared<nano::transport::inproc::channel> (node1, node1)));
|
|
vote1->signature.bytes[0] ^= 1;
|
|
ASSERT_EQ (nano::vote_code::vote, node1.vote_processor.vote_blocking (vote1, std::make_shared<nano::transport::inproc::channel> (node1, node1)));
|
|
ASSERT_EQ (nano::vote_code::replay, node1.vote_processor.vote_blocking (vote1, std::make_shared<nano::transport::inproc::channel> (node1, node1)));
|
|
}
|
|
|
|
TEST (votes, add_one)
|
|
{
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 100)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
auto transaction = node1.ledger.tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, send1));
|
|
node1.start_election (send1);
|
|
ASSERT_TIMELY (5s, node1.active.election (send1->qualified_root ()));
|
|
auto election1 = node1.active.election (send1->qualified_root ());
|
|
ASSERT_EQ (1, election1->votes ().size ());
|
|
auto vote1 = nano::test::make_vote (nano::dev::genesis_key, { send1 }, nano::vote::timestamp_min * 1, 0);
|
|
ASSERT_EQ (nano::vote_code::vote, node1.vote_router.vote (vote1).at (send1->hash ()));
|
|
auto vote2 = nano::test::make_vote (nano::dev::genesis_key, { send1 }, nano::vote::timestamp_min * 2, 0);
|
|
ASSERT_EQ (nano::vote_code::ignored, node1.vote_router.vote (vote2).at (send1->hash ())); // Ignored due to vote cooldown
|
|
ASSERT_EQ (2, election1->votes ().size ());
|
|
auto votes1 (election1->votes ());
|
|
auto existing1 (votes1.find (nano::dev::genesis_key.pub));
|
|
ASSERT_NE (votes1.end (), existing1);
|
|
ASSERT_EQ (send1->hash (), existing1->second.hash);
|
|
nano::lock_guard<nano::mutex> guard{ node1.active.mutex };
|
|
auto winner (*election1->tally ().begin ());
|
|
ASSERT_EQ (*send1, *winner.second);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, winner.first);
|
|
}
|
|
|
|
namespace nano
|
|
{
|
|
// Higher timestamps change the vote
|
|
TEST (votes, add_existing)
|
|
{
|
|
nano::test::system system;
|
|
nano::node_config node_config = system.default_config ();
|
|
node_config.online_weight_minimum = nano::dev::constants.genesis_amount;
|
|
node_config.backlog_scan.enable = false;
|
|
auto & node1 = *system.add_node (node_config);
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
std::shared_ptr<nano::block> send1 = builder.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (nano::dev::genesis_key.pub) // No representative, blocks can't confirm
|
|
.balance (nano::dev::constants.genesis_amount / 2 - nano::Knano_ratio)
|
|
.link (key1.pub)
|
|
.work (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (node1.ledger.tx_begin_write (), send1));
|
|
auto election1 = nano::test::start_election (system, node1, send1->hash ());
|
|
auto vote1 = nano::test::make_vote (nano::dev::genesis_key, { send1 }, nano::vote::timestamp_min * 1, 0);
|
|
ASSERT_EQ (nano::vote_code::vote, node1.vote_router.vote (vote1).at (send1->hash ()));
|
|
// Block is already processed from vote
|
|
ASSERT_TRUE (node1.active.publish (send1));
|
|
ASSERT_EQ (nano::vote::timestamp_min * 1, election1->last_votes[nano::dev::genesis_key.pub].timestamp);
|
|
nano::keypair key2;
|
|
std::shared_ptr<nano::block> send2 = builder.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (nano::dev::genesis_key.pub) // No representative, blocks can't confirm
|
|
.balance (nano::dev::constants.genesis_amount / 2 - nano::Knano_ratio)
|
|
.link (key2.pub)
|
|
.work (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.build ();
|
|
node1.work_generate_blocking (*send2);
|
|
ASSERT_FALSE (node1.active.publish (send2));
|
|
ASSERT_TIMELY (5s, node1.active.active (*send2));
|
|
auto vote2 = nano::test::make_vote (nano::dev::genesis_key, { send2 }, nano::vote::timestamp_min * 2, 0);
|
|
// Pretend we've waited the timeout
|
|
auto vote_info1 = election1->get_last_vote (nano::dev::genesis_key.pub);
|
|
vote_info1.time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
|
|
election1->set_last_vote (nano::dev::genesis_key.pub, vote_info1);
|
|
ASSERT_EQ (nano::vote_code::vote, node1.vote_router.vote (vote2).at (send2->hash ()));
|
|
ASSERT_EQ (nano::vote::timestamp_min * 2, election1->last_votes[nano::dev::genesis_key.pub].timestamp);
|
|
// Also resend the old vote, and see if we respect the timestamp
|
|
auto vote_info2 = election1->get_last_vote (nano::dev::genesis_key.pub);
|
|
vote_info2.time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
|
|
election1->set_last_vote (nano::dev::genesis_key.pub, vote_info2);
|
|
ASSERT_EQ (nano::vote_code::replay, node1.vote_router.vote (vote1).at (send1->hash ()));
|
|
ASSERT_EQ (nano::vote::timestamp_min * 2, election1->votes ()[nano::dev::genesis_key.pub].timestamp);
|
|
auto votes (election1->votes ());
|
|
ASSERT_EQ (2, votes.size ());
|
|
ASSERT_NE (votes.end (), votes.find (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (send2->hash (), votes[nano::dev::genesis_key.pub].hash);
|
|
ASSERT_EQ (*send2, *election1->tally ().begin ()->second);
|
|
}
|
|
|
|
// Lower timestamps are ignored
|
|
TEST (votes, add_old)
|
|
{
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
auto transaction = node1.ledger.tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, send1));
|
|
node1.start_election (send1);
|
|
ASSERT_TIMELY (5s, node1.active.election (send1->qualified_root ()));
|
|
auto election1 = node1.active.election (send1->qualified_root ());
|
|
auto vote1 = nano::test::make_vote (nano::dev::genesis_key, { send1 }, nano::vote::timestamp_min * 2, 0);
|
|
auto channel (std::make_shared<nano::transport::inproc::channel> (node1, node1));
|
|
node1.vote_processor.vote_blocking (vote1, channel);
|
|
nano::keypair key2;
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key2.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send2);
|
|
auto vote2 = std::make_shared<nano::vote> (nano::dev::genesis_key.pub, nano::dev::genesis_key.prv, nano::vote::timestamp_min * 1, 0, std::vector<nano::block_hash>{ send2->hash () });
|
|
auto vote_info = election1->get_last_vote (nano::dev::genesis_key.pub);
|
|
vote_info.time = std::chrono::steady_clock::now () - std::chrono::seconds (20);
|
|
election1->set_last_vote (nano::dev::genesis_key.pub, vote_info);
|
|
node1.vote_processor.vote_blocking (vote2, channel);
|
|
ASSERT_EQ (2, election1->votes ().size ());
|
|
auto votes (election1->votes ());
|
|
ASSERT_NE (votes.end (), votes.find (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (send1->hash (), votes[nano::dev::genesis_key.pub].hash);
|
|
ASSERT_EQ (*send1, *election1->winner ());
|
|
}
|
|
}
|
|
|
|
// Lower timestamps are accepted for different accounts
|
|
// Test disabled because it's failing intermittently.
|
|
// PR in which it got disabled: https://github.com/nanocurrency/nano-node/pull/3629
|
|
// Issue for investigating it: https://github.com/nanocurrency/nano-node/issues/3631
|
|
TEST (votes, DISABLED_add_old_different_account)
|
|
{
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (send1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send2);
|
|
ASSERT_EQ (nano::block_status::progress, node1.process (send1));
|
|
ASSERT_EQ (nano::block_status::progress, node1.process (send2));
|
|
ASSERT_TRUE (nano::test::start_elections (system, node1, { send1, send2 }));
|
|
auto election1 = node1.active.election (send1->qualified_root ());
|
|
ASSERT_NE (nullptr, election1);
|
|
auto election2 = node1.active.election (send2->qualified_root ());
|
|
ASSERT_NE (nullptr, election2);
|
|
ASSERT_EQ (1, election1->votes ().size ());
|
|
ASSERT_EQ (1, election2->votes ().size ());
|
|
auto vote1 = nano::test::make_vote (nano::dev::genesis_key, { send1 }, nano::vote::timestamp_min * 2, 0);
|
|
auto channel (std::make_shared<nano::transport::inproc::channel> (node1, node1));
|
|
auto vote_result1 (node1.vote_processor.vote_blocking (vote1, channel));
|
|
ASSERT_EQ (nano::vote_code::vote, vote_result1);
|
|
ASSERT_EQ (2, election1->votes ().size ());
|
|
ASSERT_EQ (1, election2->votes ().size ());
|
|
auto vote2 = nano::test::make_vote (nano::dev::genesis_key, { send2 }, nano::vote::timestamp_min * 1, 0);
|
|
auto vote_result2 (node1.vote_processor.vote_blocking (vote2, channel));
|
|
ASSERT_EQ (nano::vote_code::vote, vote_result2);
|
|
ASSERT_EQ (2, election1->votes ().size ());
|
|
ASSERT_EQ (2, election2->votes ().size ());
|
|
auto votes1 (election1->votes ());
|
|
auto votes2 (election2->votes ());
|
|
ASSERT_NE (votes1.end (), votes1.find (nano::dev::genesis_key.pub));
|
|
ASSERT_NE (votes2.end (), votes2.find (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (send1->hash (), votes1[nano::dev::genesis_key.pub].hash);
|
|
ASSERT_EQ (send2->hash (), votes2[nano::dev::genesis_key.pub].hash);
|
|
ASSERT_EQ (*send1, *election1->winner ());
|
|
ASSERT_EQ (*send2, *election2->winner ());
|
|
}
|
|
|
|
// The voting cooldown is respected
|
|
TEST (votes, add_cooldown)
|
|
{
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
auto transaction = node1.ledger.tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, send1));
|
|
node1.start_election (send1);
|
|
ASSERT_TIMELY (5s, node1.active.election (send1->qualified_root ()));
|
|
auto election1 = node1.active.election (send1->qualified_root ());
|
|
auto vote1 = nano::test::make_vote (nano::dev::genesis_key, { send1 }, nano::vote::timestamp_min * 1, 0);
|
|
auto channel (std::make_shared<nano::transport::inproc::channel> (node1, node1));
|
|
node1.vote_processor.vote_blocking (vote1, channel);
|
|
nano::keypair key2;
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key2.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send2);
|
|
auto vote2 = nano::test::make_vote (nano::dev::genesis_key, { send2 }, nano::vote::timestamp_min * 2, 0);
|
|
node1.vote_processor.vote_blocking (vote2, channel);
|
|
ASSERT_EQ (2, election1->votes ().size ());
|
|
auto votes (election1->votes ());
|
|
ASSERT_NE (votes.end (), votes.find (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (send1->hash (), votes[nano::dev::genesis_key.pub].hash);
|
|
ASSERT_EQ (*send1, *election1->winner ());
|
|
}
|
|
|
|
// Query for block successor
|
|
TEST (ledger, successor)
|
|
{
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
auto transaction = node1.ledger.tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, send1));
|
|
ASSERT_EQ (*send1, *node1.ledger.any.block_get (transaction, node1.ledger.any.block_successor (transaction, nano::qualified_root (nano::root (0), nano::dev::genesis->hash ())).value ()));
|
|
ASSERT_EQ (*nano::dev::genesis, *node1.ledger.any.block_get (transaction, node1.ledger.any.block_successor (transaction, nano::dev::genesis->qualified_root ()).value ()));
|
|
ASSERT_FALSE (node1.ledger.any.block_successor (transaction, nano::qualified_root (0)));
|
|
}
|
|
|
|
TEST (ledger, fail_change_old)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.change ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (key1.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
auto result2 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::old, result2);
|
|
}
|
|
|
|
TEST (ledger, fail_change_gap_previous)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.change ()
|
|
.previous (1)
|
|
.representative (key1.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::root (1)))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::gap_previous, result1);
|
|
}
|
|
|
|
TEST (ledger, fail_state_bad_signature)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (0)
|
|
.link (nano::dev::genesis_key.pub)
|
|
.sign (nano::keypair ().prv, 0)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::bad_signature, result1);
|
|
}
|
|
|
|
TEST (ledger, fail_epoch_bad_signature)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
auto block = 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)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
block->signature.bytes[0] ^= 1;
|
|
auto result1 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::bad_signature, result1); // Fails epoch signature
|
|
block->signature.bytes[0] ^= 1;
|
|
auto result2 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::progress, result2); // Succeeds with epoch signature
|
|
}
|
|
|
|
TEST (ledger, fail_change_bad_signature)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.change ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (key1.pub)
|
|
.sign (nano::keypair ().prv, 0)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::bad_signature, result1);
|
|
}
|
|
|
|
TEST (ledger, fail_change_fork)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.change ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (key1.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block1);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
nano::keypair key2;
|
|
auto block2 = builder
|
|
.change ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (key2.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result2 = ledger.process (transaction, block2);
|
|
ASSERT_EQ (nano::block_status::fork, result2);
|
|
}
|
|
|
|
TEST (ledger, fail_send_old)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
auto result2 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::old, result2);
|
|
}
|
|
|
|
TEST (ledger, fail_send_gap_previous)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.send ()
|
|
.previous (1)
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::root (1)))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::gap_previous, result1);
|
|
}
|
|
|
|
TEST (ledger, fail_send_bad_signature)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::keypair ().prv, 0)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block);
|
|
ASSERT_EQ (nano::block_status::bad_signature, result1);
|
|
}
|
|
|
|
TEST (ledger, fail_send_negative_spend)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.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, block1));
|
|
nano::keypair key2;
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key2.pub)
|
|
.balance (2)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::negative_spend, ledger.process (transaction, block2));
|
|
}
|
|
|
|
TEST (ledger, fail_send_fork)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.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, block1));
|
|
nano::keypair key2;
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key2.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, block2));
|
|
}
|
|
|
|
TEST (ledger, fail_open_old)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.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, block1));
|
|
auto block2 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block2));
|
|
ASSERT_EQ (nano::block_status::old, ledger.process (transaction, block2));
|
|
}
|
|
|
|
TEST (ledger, fail_open_gap_source)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block2 = builder
|
|
.open ()
|
|
.source (1)
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto result2 = ledger.process (transaction, block2);
|
|
ASSERT_EQ (nano::block_status::gap_source, result2);
|
|
}
|
|
|
|
TEST (ledger, fail_open_bad_signature)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.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, block1));
|
|
auto block2 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
block2->signature.clear ();
|
|
ASSERT_EQ (nano::block_status::bad_signature, ledger.process (transaction, block2));
|
|
}
|
|
|
|
TEST (ledger, fail_open_fork_previous)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.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, block1));
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block2));
|
|
auto block3 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block3));
|
|
auto block4 = builder
|
|
.open ()
|
|
.source (block2->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, block4));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, fail_open_account_mismatch)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.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, block1));
|
|
nano::keypair badkey;
|
|
auto block2 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (badkey.pub)
|
|
.sign (badkey.prv, badkey.pub)
|
|
.work (*pool.generate (badkey.pub))
|
|
.build ();
|
|
ASSERT_NE (nano::block_status::progress, ledger.process (transaction, block2));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, fail_receive_old)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.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, block1));
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block2));
|
|
auto block3 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block3));
|
|
auto block4 = builder
|
|
.receive ()
|
|
.previous (block3->hash ())
|
|
.source (block2->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (block3->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block4));
|
|
ASSERT_EQ (nano::block_status::old, ledger.process (transaction, block4));
|
|
}
|
|
|
|
TEST (ledger, fail_receive_gap_source)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block1);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
auto result2 = ledger.process (transaction, block2);
|
|
ASSERT_EQ (nano::block_status::progress, result2);
|
|
auto block3 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto result3 = ledger.process (transaction, block3);
|
|
ASSERT_EQ (nano::block_status::progress, result3);
|
|
auto block4 = builder
|
|
.receive ()
|
|
.previous (block3->hash ())
|
|
.source (1)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (block3->hash ()))
|
|
.build ();
|
|
auto result4 = ledger.process (transaction, block4);
|
|
ASSERT_EQ (nano::block_status::gap_source, result4);
|
|
}
|
|
|
|
TEST (ledger, fail_receive_overreceive)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block1);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
auto block2 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto result3 = ledger.process (transaction, block2);
|
|
ASSERT_EQ (nano::block_status::progress, result3);
|
|
auto block3 = builder
|
|
.receive ()
|
|
.previous (block2->hash ())
|
|
.source (block1->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (block2->hash ()))
|
|
.build ();
|
|
auto result4 = ledger.process (transaction, block3);
|
|
ASSERT_EQ (nano::block_status::unreceivable, result4);
|
|
}
|
|
|
|
TEST (ledger, fail_receive_bad_signature)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block1);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
auto result2 = ledger.process (transaction, block2);
|
|
ASSERT_EQ (nano::block_status::progress, result2);
|
|
auto block3 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto result3 = ledger.process (transaction, block3);
|
|
ASSERT_EQ (nano::block_status::progress, result3);
|
|
auto block4 = builder
|
|
.receive ()
|
|
.previous (block3->hash ())
|
|
.source (block2->hash ())
|
|
.sign (nano::keypair ().prv, 0)
|
|
.work (*pool.generate (block3->hash ()))
|
|
.build ();
|
|
auto result4 = ledger.process (transaction, block4);
|
|
ASSERT_EQ (nano::block_status::bad_signature, result4);
|
|
}
|
|
|
|
TEST (ledger, fail_receive_gap_previous_opened)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block1);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
auto result2 = ledger.process (transaction, block2);
|
|
ASSERT_EQ (nano::block_status::progress, result2);
|
|
auto block3 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto result3 = ledger.process (transaction, block3);
|
|
ASSERT_EQ (nano::block_status::progress, result3);
|
|
auto block4 = builder
|
|
.receive ()
|
|
.previous (1)
|
|
.source (block2->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (nano::root (1)))
|
|
.build ();
|
|
auto result4 = ledger.process (transaction, block4);
|
|
ASSERT_EQ (nano::block_status::gap_previous, result4);
|
|
}
|
|
|
|
TEST (ledger, fail_receive_gap_previous_unopened)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block1);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
auto result2 = ledger.process (transaction, block2);
|
|
ASSERT_EQ (nano::block_status::progress, result2);
|
|
auto block3 = builder
|
|
.receive ()
|
|
.previous (1)
|
|
.source (block2->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (nano::root (1)))
|
|
.build ();
|
|
auto result3 = ledger.process (transaction, block3);
|
|
ASSERT_EQ (nano::block_status::gap_previous, result3);
|
|
}
|
|
|
|
TEST (ledger, fail_receive_fork_previous)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block1);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
auto result2 = ledger.process (transaction, block2);
|
|
ASSERT_EQ (nano::block_status::progress, result2);
|
|
auto block3 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto result3 = ledger.process (transaction, block3);
|
|
ASSERT_EQ (nano::block_status::progress, result3);
|
|
nano::keypair key2;
|
|
auto block4 = builder
|
|
.send ()
|
|
.previous (block3->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (block3->hash ()))
|
|
.build ();
|
|
auto result4 = ledger.process (transaction, block4);
|
|
ASSERT_EQ (nano::block_status::progress, result4);
|
|
auto block5 = builder
|
|
.receive ()
|
|
.previous (block3->hash ())
|
|
.source (block2->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (block3->hash ()))
|
|
.build ();
|
|
auto result5 = ledger.process (transaction, block5);
|
|
ASSERT_EQ (nano::block_status::fork, result5);
|
|
}
|
|
|
|
TEST (ledger, fail_receive_received_source)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (2)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto result1 = ledger.process (transaction, block1);
|
|
ASSERT_EQ (nano::block_status::progress, result1);
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
auto result2 = ledger.process (transaction, block2);
|
|
ASSERT_EQ (nano::block_status::progress, result2);
|
|
auto block6 = builder
|
|
.send ()
|
|
.previous (block2->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block2->hash ()))
|
|
.build ();
|
|
auto result6 = ledger.process (transaction, block6);
|
|
ASSERT_EQ (nano::block_status::progress, result6);
|
|
auto block3 = builder
|
|
.open ()
|
|
.source (block1->hash ())
|
|
.representative (1)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto result3 = ledger.process (transaction, block3);
|
|
ASSERT_EQ (nano::block_status::progress, result3);
|
|
nano::keypair key2;
|
|
auto block4 = builder
|
|
.send ()
|
|
.previous (block3->hash ())
|
|
.destination (key1.pub)
|
|
.balance (1)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (block3->hash ()))
|
|
.build ();
|
|
auto result4 = ledger.process (transaction, block4);
|
|
ASSERT_EQ (nano::block_status::progress, result4);
|
|
auto block5 = builder
|
|
.receive ()
|
|
.previous (block4->hash ())
|
|
.source (block2->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (block4->hash ()))
|
|
.build ();
|
|
auto result5 = ledger.process (transaction, block5);
|
|
ASSERT_EQ (nano::block_status::progress, result5);
|
|
auto block7 = builder
|
|
.receive ()
|
|
.previous (block3->hash ())
|
|
.source (block2->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (block3->hash ()))
|
|
.build ();
|
|
auto result7 = ledger.process (transaction, block7);
|
|
ASSERT_EQ (nano::block_status::fork, result7);
|
|
}
|
|
|
|
TEST (ledger, latest_empty)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
nano::keypair key;
|
|
auto transaction = ledger.tx_begin_read ();
|
|
auto latest = ledger.any.account_head (transaction, key.pub);
|
|
ASSERT_TRUE (latest.is_zero ());
|
|
}
|
|
|
|
TEST (ledger, latest_root)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key;
|
|
ASSERT_EQ (key.pub, ledger.latest_root (transaction, key.pub).as_account ());
|
|
auto hash1 = ledger.any.account_head (transaction, nano::dev::genesis_key.pub);
|
|
nano::block_builder builder;
|
|
auto send = builder
|
|
.send ()
|
|
.previous (hash1)
|
|
.destination (0)
|
|
.balance (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (hash1))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
|
ASSERT_EQ (send->hash (), ledger.latest_root (transaction, nano::dev::genesis_key.pub).as_block_hash ());
|
|
}
|
|
|
|
TEST (ledger, change_representative_move_representation)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
nano::keypair key1;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
nano::block_builder builder;
|
|
auto send = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (0)
|
|
.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));
|
|
ASSERT_EQ (0, ledger.weight (nano::dev::genesis_key.pub));
|
|
nano::keypair key2;
|
|
auto change = builder
|
|
.change ()
|
|
.previous (send->hash ())
|
|
.representative (key2.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, change));
|
|
nano::keypair key3;
|
|
auto open = builder
|
|
.open ()
|
|
.source (send->hash ())
|
|
.representative (key3.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));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (key3.pub));
|
|
}
|
|
|
|
TEST (ledger, send_open_receive_rollback)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
auto info1 = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (info1);
|
|
nano::keypair key1;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (info1->head)
|
|
.destination (key1.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 50)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (info1->head))
|
|
.build ();
|
|
auto return1 = ledger.process (transaction, send1);
|
|
ASSERT_EQ (nano::block_status::progress, return1);
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (send1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 100)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
auto return2 = ledger.process (transaction, send2);
|
|
ASSERT_EQ (nano::block_status::progress, return2);
|
|
nano::keypair key2;
|
|
auto open = builder
|
|
.open ()
|
|
.source (send2->hash ())
|
|
.representative (key2.pub)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto return4 = ledger.process (transaction, open);
|
|
ASSERT_EQ (nano::block_status::progress, return4);
|
|
auto receive = builder
|
|
.receive ()
|
|
.previous (open->hash ())
|
|
.source (send1->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (open->hash ()))
|
|
.build ();
|
|
auto return5 = ledger.process (transaction, receive);
|
|
ASSERT_EQ (nano::block_status::progress, return5);
|
|
nano::keypair key3;
|
|
ASSERT_EQ (100, ledger.weight (key2.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (key3.pub));
|
|
auto change1 = builder
|
|
.change ()
|
|
.previous (send2->hash ())
|
|
.representative (key3.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send2->hash ()))
|
|
.build ();
|
|
auto return6 = ledger.process (transaction, change1);
|
|
ASSERT_EQ (nano::block_status::progress, return6);
|
|
ASSERT_EQ (100, ledger.weight (key2.pub));
|
|
ASSERT_EQ (0, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, ledger.weight (key3.pub));
|
|
ASSERT_FALSE (ledger.rollback (transaction, receive->hash ()));
|
|
ASSERT_EQ (50, ledger.weight (key2.pub));
|
|
ASSERT_EQ (0, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, ledger.weight (key3.pub));
|
|
ASSERT_FALSE (ledger.rollback (transaction, open->hash ()));
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
ASSERT_EQ (0, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, ledger.weight (key3.pub));
|
|
ASSERT_FALSE (ledger.rollback (transaction, change1->hash ()));
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
ASSERT_EQ (0, ledger.weight (key3.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 100, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_FALSE (ledger.rollback (transaction, send2->hash ()));
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
ASSERT_EQ (0, ledger.weight (key3.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 50, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_FALSE (ledger.rollback (transaction, send1->hash ()));
|
|
ASSERT_EQ (0, ledger.weight (key2.pub));
|
|
ASSERT_EQ (0, ledger.weight (key3.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - 0, ledger.weight (nano::dev::genesis_key.pub));
|
|
}
|
|
|
|
TEST (ledger, bootstrap_weights)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto & pool = ctx.pool ();
|
|
|
|
nano::keypair rep_key1, rep_key2, throwaway;
|
|
|
|
// Genesis key has all the voting weight
|
|
ASSERT_EQ (std::numeric_limits<nano::uint128_t>::max (), ledger.weight (nano::dev::genesis_key.pub));
|
|
|
|
// Throwaway transaction to reduce genesis weight
|
|
{
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto genesis_info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (genesis_info);
|
|
nano::block_builder builder;
|
|
auto send = builder
|
|
.send ()
|
|
.previous (genesis_info->head)
|
|
.destination (throwaway.pub)
|
|
.balance (std::numeric_limits<nano::uint128_t>::max () - 50)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (genesis_info->head))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
|
}
|
|
|
|
// Override bootstrap weights
|
|
ledger.bootstrap_weight_max_blocks = 4;
|
|
ledger.bootstrap_weights[rep_key1.pub] = 1000;
|
|
|
|
// Should use bootstrap weights
|
|
ASSERT_EQ (2, ledger.block_count ());
|
|
ASSERT_FALSE (ledger.bootstrap_height_reached ());
|
|
ASSERT_EQ (0, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (1000, ledger.weight (rep_key1.pub));
|
|
{
|
|
auto snapshot = ledger.rep_weights_snapshot ();
|
|
ASSERT_EQ (1, snapshot.size ());
|
|
ASSERT_EQ (1000, snapshot[rep_key1.pub]);
|
|
}
|
|
|
|
// Open normal representative account, should not use bootstrap weights anymore
|
|
{
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto genesis_info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (genesis_info);
|
|
nano::block_builder builder;
|
|
auto send = builder
|
|
.send ()
|
|
.previous (genesis_info->head)
|
|
.destination (rep_key2.pub)
|
|
.balance (std::numeric_limits<nano::uint128_t>::max () - 100)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (genesis_info->head))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
|
|
|
auto open = builder
|
|
.open ()
|
|
.source (send->hash ())
|
|
.representative (rep_key2.pub)
|
|
.account (rep_key2.pub)
|
|
.sign (rep_key2.prv, rep_key2.pub)
|
|
.work (*pool.generate (rep_key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open));
|
|
}
|
|
ASSERT_EQ (4, ledger.block_count ());
|
|
ASSERT_TRUE (ledger.bootstrap_height_reached ());
|
|
ASSERT_EQ (std::numeric_limits<nano::uint128_t>::max () - 100, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (rep_key1.pub));
|
|
ASSERT_EQ (50, ledger.weight (rep_key2.pub));
|
|
{
|
|
auto snapshot = ledger.rep_weights_snapshot ();
|
|
ASSERT_EQ (2, snapshot.size ());
|
|
ASSERT_EQ (std::numeric_limits<nano::uint128_t>::max () - 100, snapshot[nano::dev::genesis_key.pub]);
|
|
ASSERT_EQ (50, snapshot[rep_key2.pub]);
|
|
}
|
|
}
|
|
|
|
TEST (ledger, block_destination_source)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair dest;
|
|
nano::uint128_t balance (nano::dev::constants.genesis_amount);
|
|
balance -= nano::Knano_ratio;
|
|
nano::block_builder builder;
|
|
auto block1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (dest.pub)
|
|
.balance (balance)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
balance -= nano::Knano_ratio;
|
|
auto block2 = builder
|
|
.send ()
|
|
.previous (block1->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (balance)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block1->hash ()))
|
|
.build ();
|
|
balance += nano::Knano_ratio;
|
|
auto block3 = builder
|
|
.receive ()
|
|
.previous (block2->hash ())
|
|
.source (block2->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block2->hash ()))
|
|
.build ();
|
|
balance -= nano::Knano_ratio;
|
|
auto block4 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (block3->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (balance)
|
|
.link (dest.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block3->hash ()))
|
|
.build ();
|
|
balance -= nano::Knano_ratio;
|
|
auto block5 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (block4->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (balance)
|
|
.link (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block4->hash ()))
|
|
.build ();
|
|
balance += nano::Knano_ratio;
|
|
auto block6 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (block5->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (balance)
|
|
.link (block5->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (block5->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block1));
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block2));
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block3));
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block4));
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block5));
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, block6));
|
|
ASSERT_EQ (balance, ledger.any.block_balance (transaction, block6->hash ()));
|
|
ASSERT_EQ (dest.pub, block1->destination ());
|
|
ASSERT_FALSE (block1->source_field ());
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, block2->destination ());
|
|
ASSERT_FALSE (block2->source_field ());
|
|
ASSERT_FALSE (block3->destination_field ());
|
|
ASSERT_EQ (block2->hash (), block3->source ());
|
|
ASSERT_EQ (dest.pub, block4->destination ());
|
|
ASSERT_FALSE (block4->source_field ());
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, block5->destination ());
|
|
ASSERT_FALSE (block5->source_field ());
|
|
ASSERT_FALSE (block6->destination_field ());
|
|
ASSERT_EQ (block5->hash (), block6->source ());
|
|
}
|
|
|
|
TEST (ledger, state_account)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, ledger.any.block_account (transaction, send1->hash ()).value ());
|
|
}
|
|
|
|
TEST (ledger, state_send_receive)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send2 = ledger.any.block_get (transaction, send1->hash ());
|
|
ASSERT_NE (nullptr, send2);
|
|
ASSERT_EQ (*send1, *send2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.block_balance (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_TRUE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_EQ (2, send2->sideband ().height);
|
|
ASSERT_TRUE (send2->is_send ());
|
|
ASSERT_FALSE (send2->is_receive ());
|
|
ASSERT_FALSE (send2->sideband ().details.is_epoch);
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, receive1->hash ()));
|
|
auto receive2 = ledger.any.block_get (transaction, receive1->hash ());
|
|
ASSERT_NE (nullptr, receive2);
|
|
ASSERT_EQ (*receive1, *receive2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.block_balance (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
ASSERT_EQ (3, receive2->sideband ().height);
|
|
ASSERT_FALSE (receive2->is_send ());
|
|
ASSERT_TRUE (receive2->is_receive ());
|
|
ASSERT_FALSE (receive2->sideband ().details.is_epoch);
|
|
}
|
|
|
|
TEST (ledger, state_receive)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send2 = ledger.any.block_get (transaction, send1->hash ());
|
|
ASSERT_NE (nullptr, send2);
|
|
ASSERT_EQ (*send1, *send2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.block_balance (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, receive1->hash ()));
|
|
auto receive2 = ledger.any.block_get (transaction, receive1->hash ());
|
|
ASSERT_NE (nullptr, receive2);
|
|
ASSERT_EQ (*receive1, *receive2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.block_balance (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (3, receive2->sideband ().height);
|
|
ASSERT_FALSE (receive2->is_send ());
|
|
ASSERT_TRUE (receive2->is_receive ());
|
|
ASSERT_FALSE (receive2->sideband ().details.is_epoch);
|
|
}
|
|
|
|
TEST (ledger, state_rep_change)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair rep;
|
|
nano::block_builder builder;
|
|
auto change1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (rep.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (0)
|
|
.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, change1));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, change1->hash ()));
|
|
auto change2 = ledger.any.block_get (transaction, change1->hash ());
|
|
ASSERT_NE (nullptr, change2);
|
|
ASSERT_EQ (*change1, *change2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.block_balance (transaction, change1->hash ()));
|
|
ASSERT_EQ (0, ledger.any.block_amount (transaction, change1->hash ()).value ().number ());
|
|
ASSERT_EQ (0, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (rep.pub));
|
|
ASSERT_EQ (2, change2->sideband ().height);
|
|
ASSERT_FALSE (change2->is_send ());
|
|
ASSERT_FALSE (change2->is_receive ());
|
|
ASSERT_FALSE (change2->sideband ().details.is_epoch);
|
|
}
|
|
|
|
TEST (ledger, state_open)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send2 = ledger.any.block_get (transaction, send1->hash ());
|
|
ASSERT_NE (nullptr, send2);
|
|
ASSERT_EQ (*send1, *send2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.block_balance (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_TRUE (ledger.any.pending_get (transaction, nano::pending_key{ destination.pub, send1->hash () }));
|
|
auto open1 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ destination.pub, send1->hash () }));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, open1->hash ()));
|
|
auto open2 = ledger.any.block_get (transaction, open1->hash ());
|
|
ASSERT_NE (nullptr, open2);
|
|
ASSERT_EQ (*open1, *open2);
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_balance (transaction, open1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, open1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (ledger.account_count (), store.account.count (transaction));
|
|
ASSERT_EQ (1, open2->sideband ().height);
|
|
ASSERT_FALSE (open2->is_send ());
|
|
ASSERT_TRUE (open2->is_receive ());
|
|
ASSERT_FALSE (open2->sideband ().details.is_epoch);
|
|
}
|
|
|
|
// Make sure old block types can't be inserted after a state block.
|
|
TEST (ledger, send_after_state_fail)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (send1->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - (2 * nano::Knano_ratio))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, send2));
|
|
}
|
|
|
|
// Make sure old block types can't be inserted after a state block.
|
|
TEST (ledger, receive_after_state_fail)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (send1->hash ())
|
|
.source (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, receive1));
|
|
}
|
|
|
|
// Make sure old block types can't be inserted after a state block.
|
|
TEST (ledger, change_after_state_fail)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
nano::keypair rep;
|
|
auto change1 = builder
|
|
.change ()
|
|
.previous (send1->hash ())
|
|
.representative (rep.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, change1));
|
|
}
|
|
|
|
TEST (ledger, state_unreceivable_fail)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send2 = ledger.any.block_get (transaction, send1->hash ());
|
|
ASSERT_NE (nullptr, send2);
|
|
ASSERT_EQ (*send1, *send2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.block_balance (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::gap_source, ledger.process (transaction, receive1));
|
|
}
|
|
|
|
TEST (ledger, state_receive_bad_amount_fail)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send2 = ledger.any.block_get (transaction, send1->hash ());
|
|
ASSERT_NE (nullptr, send2);
|
|
ASSERT_EQ (*send1, *send2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.block_balance (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::balance_mismatch, ledger.process (transaction, receive1));
|
|
}
|
|
|
|
TEST (ledger, state_no_link_amount_fail)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
nano::keypair rep;
|
|
auto change1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (rep.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::balance_mismatch, ledger.process (transaction, change1));
|
|
}
|
|
|
|
TEST (ledger, state_receive_wrong_account_fail)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send2 = ledger.any.block_get (transaction, send1->hash ());
|
|
ASSERT_NE (nullptr, send2);
|
|
ASSERT_EQ (*send1, *send2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.block_balance (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
nano::keypair key;
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (key.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (key.prv, key.pub)
|
|
.work (*pool.generate (key.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::unreceivable, ledger.process (transaction, receive1));
|
|
}
|
|
|
|
TEST (ledger, state_open_state_fork)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.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));
|
|
auto open1 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
auto open2 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, open2));
|
|
ASSERT_EQ (open1->root (), open2->root ());
|
|
}
|
|
|
|
TEST (ledger, state_state_open_fork)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.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));
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
auto open2 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, open2));
|
|
ASSERT_EQ (open1->root (), open2->root ());
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, state_open_previous_fail)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.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));
|
|
auto open1 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (1)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (1))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::gap_previous, ledger.process (transaction, open1));
|
|
}
|
|
|
|
TEST (ledger, state_open_source_fail)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.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));
|
|
auto open1 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (0)
|
|
.link (0)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::gap_source, ledger.process (transaction, open1));
|
|
}
|
|
|
|
TEST (ledger, state_send_change)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair rep;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (rep.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send2 = ledger.any.block_get (transaction, send1->hash ());
|
|
ASSERT_NE (nullptr, send2);
|
|
ASSERT_EQ (*send1, *send2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.block_balance (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, send1->hash ()));
|
|
ASSERT_EQ (0, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (rep.pub));
|
|
ASSERT_EQ (2, send2->sideband ().height);
|
|
ASSERT_TRUE (send2->is_send ());
|
|
ASSERT_FALSE (send2->is_receive ());
|
|
ASSERT_FALSE (send2->sideband ().details.is_epoch);
|
|
}
|
|
|
|
TEST (ledger, state_receive_change)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send2 = ledger.any.block_get (transaction, send1->hash ());
|
|
ASSERT_NE (nullptr, send2);
|
|
ASSERT_EQ (*send1, *send2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.block_balance (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
nano::keypair rep;
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (rep.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, receive1->hash ()));
|
|
auto receive2 = ledger.any.block_get (transaction, receive1->hash ());
|
|
ASSERT_NE (nullptr, receive2);
|
|
ASSERT_EQ (*receive1, *receive2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.block_balance (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, receive1->hash ()));
|
|
ASSERT_EQ (0, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (rep.pub));
|
|
ASSERT_EQ (3, receive2->sideband ().height);
|
|
ASSERT_FALSE (receive2->is_send ());
|
|
ASSERT_TRUE (receive2->is_receive ());
|
|
ASSERT_FALSE (receive2->sideband ().details.is_epoch);
|
|
}
|
|
|
|
TEST (ledger, state_open_old)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.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));
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_balance (transaction, open1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, open1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
}
|
|
|
|
TEST (ledger, state_receive_old)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.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));
|
|
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::Knano_ratio))
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (open1->hash ())
|
|
.source (send2->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (open1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_EQ (2 * nano::Knano_ratio, ledger.any.block_balance (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
}
|
|
|
|
TEST (ledger, state_rollback_send)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send2 = ledger.any.block_get (transaction, send1->hash ());
|
|
ASSERT_NE (nullptr, send2);
|
|
ASSERT_EQ (*send1, *send2);
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
auto info = ledger.any.pending_get (transaction, nano::pending_key (nano::dev::genesis_key.pub, send1->hash ()));
|
|
ASSERT_TRUE (info);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, info->source);
|
|
ASSERT_EQ (nano::Knano_ratio, info->amount.number ());
|
|
ASSERT_FALSE (ledger.rollback (transaction, send1->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_FALSE (ledger.any.block_successor (transaction, nano::dev::genesis->hash ()));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, state_rollback_receive)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, receive1->hash () }));
|
|
ASSERT_FALSE (ledger.rollback (transaction, receive1->hash ()));
|
|
auto info = ledger.any.pending_get (transaction, nano::pending_key (nano::dev::genesis_key.pub, send1->hash ()));
|
|
ASSERT_TRUE (info);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, info->source);
|
|
ASSERT_EQ (nano::Knano_ratio, info->amount.number ());
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, state_rollback_received_send)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (key.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));
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (key.pub)
|
|
.previous (0)
|
|
.representative (key.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (key.prv, key.pub)
|
|
.work (*pool.generate (key.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, receive1->hash () }));
|
|
ASSERT_FALSE (ledger.rollback (transaction, send1->hash ()));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_FALSE (ledger.any.account_balance (transaction, key.pub));
|
|
ASSERT_EQ (0, ledger.weight (key.pub));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, state_rep_change_rollback)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair rep;
|
|
nano::block_builder builder;
|
|
auto change1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (rep.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (0)
|
|
.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, change1));
|
|
ASSERT_FALSE (ledger.rollback (transaction, change1->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, change1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (rep.pub));
|
|
}
|
|
|
|
TEST (ledger, state_open_rollback)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.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));
|
|
auto open1 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
ASSERT_FALSE (ledger.rollback (transaction, open1->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, open1->hash ()));
|
|
ASSERT_FALSE (ledger.any.account_balance (transaction, destination.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
auto info = ledger.any.pending_get (transaction, nano::pending_key (destination.pub, send1->hash ()));
|
|
ASSERT_TRUE (info);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, info->source);
|
|
ASSERT_EQ (nano::Knano_ratio, info->amount.number ());
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, state_send_change_rollback)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair rep;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (rep.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_FALSE (ledger.rollback (transaction, send1->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (rep.pub));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, state_receive_change_rollback)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
nano::keypair rep;
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (rep.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_FALSE (ledger.rollback (transaction, receive1->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, receive1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.any.account_balance (transaction, nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, ledger.weight (rep.pub));
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, rollback_depth_exceeded)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
|
|
// Chain: G->A0->A1
|
|
nano::keypair key1, key2;
|
|
nano::keypair rep1, rep2;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.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));
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (key1.pub)
|
|
.previous (0)
|
|
.representative (rep1.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
auto send2 = builder
|
|
.state ()
|
|
.account (key1.pub)
|
|
.previous (receive1->hash ())
|
|
.representative (rep1.pub)
|
|
.balance (0)
|
|
.link (key2.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (receive1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
auto receive2 = builder
|
|
.state ()
|
|
.account (key2.pub)
|
|
.previous (0)
|
|
.representative (rep2.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send2->hash ())
|
|
.sign (key2.prv, key2.pub)
|
|
.work (*pool.generate (key2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive2));
|
|
|
|
// This call should fail because the rollback depth exceeds the limit
|
|
std::deque<std::shared_ptr<nano::block>> rollback_list;
|
|
ASSERT_TRUE (ledger.rollback (transaction, send1->hash (), rollback_list, 0, 1));
|
|
ASSERT_EQ (rollback_list.size (), 0);
|
|
ASSERT_EQ (ledger.any.account_balance (transaction, key1.pub), 0);
|
|
ASSERT_EQ (ledger.any.account_balance (transaction, key2.pub), nano::Knano_ratio);
|
|
ASSERT_EQ (ledger.any.account_balance (transaction, nano::dev::genesis_key.pub), nano::dev::constants.genesis_amount - nano::Knano_ratio);
|
|
ASSERT_EQ (ledger.weight (rep1.pub), 0);
|
|
ASSERT_EQ (ledger.weight (rep2.pub), nano::Knano_ratio);
|
|
ASSERT_EQ (ledger.weight (nano::dev::genesis_key.pub), nano::dev::constants.genesis_amount - nano::Knano_ratio);
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key (key1.pub, send1->hash ())));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key (key2.pub, send2->hash ())));
|
|
}
|
|
|
|
TEST (ledger, epoch_blocks_v1_general)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
auto epoch1 = 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)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.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, epoch1));
|
|
ASSERT_FALSE (epoch1->is_send ());
|
|
ASSERT_FALSE (epoch1->is_receive ());
|
|
ASSERT_TRUE (epoch1->sideband ().details.is_epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_1, epoch1->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch1->sideband ().source_epoch); // Not used for epoch blocks
|
|
auto epoch2 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (epoch1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, epoch2));
|
|
auto genesis_info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (genesis_info);
|
|
ASSERT_EQ (genesis_info->epoch (), nano::epoch::epoch_1);
|
|
ASSERT_FALSE (ledger.rollback (transaction, epoch1->hash ()));
|
|
genesis_info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (genesis_info);
|
|
ASSERT_EQ (genesis_info->epoch (), nano::epoch::epoch_0);
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch1));
|
|
genesis_info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (genesis_info);
|
|
ASSERT_EQ (genesis_info->epoch (), nano::epoch::epoch_1);
|
|
ASSERT_FALSE (epoch1->is_send ());
|
|
ASSERT_FALSE (epoch1->is_receive ());
|
|
ASSERT_TRUE (epoch1->sideband ().details.is_epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_1, epoch1->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch1->sideband ().source_epoch); // Not used for epoch blocks
|
|
auto change1 = builder
|
|
.change ()
|
|
.previous (epoch1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, change1));
|
|
auto send1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (epoch1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
|
|
ASSERT_TRUE (send1->is_send ());
|
|
ASSERT_FALSE (send1->is_receive ());
|
|
ASSERT_FALSE (send1->sideband ().details.is_epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_1, send1->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, send1->sideband ().source_epoch); // Not used for send blocks
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::unreceivable, ledger.process (transaction, open1));
|
|
auto epoch3 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (0)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::representative_mismatch, ledger.process (transaction, epoch3));
|
|
auto epoch4 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (0)
|
|
.balance (0)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch4));
|
|
ASSERT_FALSE (epoch4->is_send ());
|
|
ASSERT_FALSE (epoch4->is_receive ());
|
|
ASSERT_TRUE (epoch4->sideband ().details.is_epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_1, epoch4->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch4->sideband ().source_epoch); // Not used for epoch blocks
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (epoch4->hash ())
|
|
.source (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (epoch4->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, receive1));
|
|
auto receive2 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (epoch4->hash ())
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (epoch4->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive2));
|
|
ASSERT_EQ (nano::epoch::epoch_1, receive2->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_1, receive2->sideband ().source_epoch);
|
|
ASSERT_EQ (0, ledger.any.block_balance (transaction, epoch4->hash ()).value ().number ());
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_balance (transaction, receive2->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, receive2->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.weight (destination.pub));
|
|
ASSERT_FALSE (receive2->is_send ());
|
|
ASSERT_TRUE (receive2->is_receive ());
|
|
ASSERT_FALSE (receive2->sideband ().details.is_epoch);
|
|
}
|
|
|
|
TEST (ledger, epoch_blocks_v2_general)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
auto epoch1 = 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)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_2))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
// Trying to upgrade from epoch 0 to epoch 2. It is a requirement epoch upgrades are sequential unless the account is unopened
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, epoch1));
|
|
// Set it to the first epoch and it should now succeed
|
|
epoch1 = 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)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (epoch1->work)
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch1));
|
|
ASSERT_EQ (nano::epoch::epoch_1, epoch1->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch1->sideband ().source_epoch); // Not used for epoch blocks
|
|
auto epoch2 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (epoch1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_2))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch2));
|
|
ASSERT_EQ (nano::epoch::epoch_2, epoch2->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch2->sideband ().source_epoch); // Not used for epoch blocks
|
|
auto epoch3 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (epoch2->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_2))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, epoch3));
|
|
auto genesis_info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (genesis_info);
|
|
ASSERT_EQ (genesis_info->epoch (), nano::epoch::epoch_2);
|
|
ASSERT_FALSE (ledger.rollback (transaction, epoch1->hash ()));
|
|
genesis_info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (genesis_info);
|
|
ASSERT_EQ (genesis_info->epoch (), nano::epoch::epoch_0);
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch1));
|
|
genesis_info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (genesis_info);
|
|
ASSERT_EQ (genesis_info->epoch (), nano::epoch::epoch_1);
|
|
auto change1 = builder
|
|
.change ()
|
|
.previous (epoch1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, change1));
|
|
auto send1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (epoch1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
|
|
ASSERT_EQ (nano::epoch::epoch_1, send1->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, send1->sideband ().source_epoch); // Not used for send blocks
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::unreceivable, ledger.process (transaction, open1));
|
|
auto epoch4 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (0)
|
|
.balance (0)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch4));
|
|
ASSERT_EQ (nano::epoch::epoch_1, epoch4->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch4->sideband ().source_epoch); // Not used for epoch blocks
|
|
auto epoch5 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (epoch4->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (0)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_2))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch4->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::representative_mismatch, ledger.process (transaction, epoch5));
|
|
auto epoch6 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (epoch4->hash ())
|
|
.representative (0)
|
|
.balance (0)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_2))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch4->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch6));
|
|
ASSERT_EQ (nano::epoch::epoch_2, epoch6->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch6->sideband ().source_epoch); // Not used for epoch blocks
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (epoch6->hash ())
|
|
.source (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (epoch6->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::block_position, ledger.process (transaction, receive1));
|
|
auto receive2 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (epoch6->hash ())
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (epoch6->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive2));
|
|
ASSERT_EQ (nano::epoch::epoch_2, receive2->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_1, receive2->sideband ().source_epoch);
|
|
ASSERT_EQ (0, ledger.any.block_balance (transaction, epoch6->hash ()).value ().number ());
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_balance (transaction, receive2->hash ()));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.any.block_amount (transaction, receive2->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio, ledger.weight (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::Knano_ratio, ledger.weight (destination.pub));
|
|
}
|
|
|
|
TEST (ledger, epoch_blocks_receive_upgrade)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.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));
|
|
auto epoch1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch1));
|
|
auto send2 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (epoch1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio * 2)
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
ASSERT_EQ (nano::epoch::epoch_1, send2->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, send2->sideband ().source_epoch); // Not used for send blocks
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (destination.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (destination.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
ASSERT_EQ (nano::epoch::epoch_0, open1->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, open1->sideband ().source_epoch);
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (open1->hash ())
|
|
.source (send2->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (open1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::unreceivable, ledger.process (transaction, receive1));
|
|
auto receive2 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (open1->hash ())
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio * 2)
|
|
.link (send2->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (open1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive2));
|
|
ASSERT_EQ (nano::epoch::epoch_1, receive2->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_1, receive2->sideband ().source_epoch);
|
|
auto destination_info = ledger.any.account_get (transaction, destination.pub);
|
|
ASSERT_TRUE (destination_info);
|
|
ASSERT_EQ (destination_info->epoch (), nano::epoch::epoch_1);
|
|
ASSERT_FALSE (ledger.rollback (transaction, receive2->hash ()));
|
|
destination_info = ledger.any.account_get (transaction, destination.pub);
|
|
ASSERT_TRUE (destination_info);
|
|
ASSERT_EQ (destination_info->epoch (), nano::epoch::epoch_0);
|
|
auto pending_send2 = ledger.any.pending_get (transaction, nano::pending_key (destination.pub, send2->hash ()));
|
|
ASSERT_TRUE (pending_send2);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, pending_send2->source);
|
|
ASSERT_EQ (nano::Knano_ratio, pending_send2->amount.number ());
|
|
ASSERT_EQ (nano::epoch::epoch_1, pending_send2->epoch);
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive2));
|
|
ASSERT_EQ (nano::epoch::epoch_1, receive2->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_1, receive2->sideband ().source_epoch);
|
|
destination_info = ledger.any.account_get (transaction, destination.pub);
|
|
ASSERT_TRUE (destination_info);
|
|
ASSERT_EQ (destination_info->epoch (), nano::epoch::epoch_1);
|
|
nano::keypair destination2;
|
|
auto send3 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (receive2->hash ())
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (destination2.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (receive2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send3));
|
|
auto open2 = builder
|
|
.open ()
|
|
.source (send3->hash ())
|
|
.representative (destination2.pub)
|
|
.account (destination2.pub)
|
|
.sign (destination2.prv, destination2.pub)
|
|
.work (*pool.generate (destination2.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::unreceivable, ledger.process (transaction, open2));
|
|
// Upgrade to epoch 2 and send to destination. Try to create an open block from an epoch 2 source block.
|
|
nano::keypair destination3;
|
|
auto epoch2 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send2->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio * 2)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_2))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch2));
|
|
auto send4 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (epoch2->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio * 3)
|
|
.link (destination3.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send4));
|
|
auto open3 = builder
|
|
.open ()
|
|
.source (send4->hash ())
|
|
.representative (destination3.pub)
|
|
.account (destination3.pub)
|
|
.sign (destination3.prv, destination3.pub)
|
|
.work (*pool.generate (destination3.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::unreceivable, ledger.process (transaction, open3));
|
|
// Send it to an epoch 1 account
|
|
auto send5 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send4->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio * 4)
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send4->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send5));
|
|
destination_info = ledger.any.account_get (transaction, destination.pub);
|
|
ASSERT_TRUE (destination_info);
|
|
ASSERT_EQ (destination_info->epoch (), nano::epoch::epoch_1);
|
|
auto receive3 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (send3->hash ())
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio * 2)
|
|
.link (send5->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (*pool.generate (send3->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive3));
|
|
ASSERT_EQ (nano::epoch::epoch_2, receive3->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_2, receive3->sideband ().source_epoch);
|
|
destination_info = ledger.any.account_get (transaction, destination.pub);
|
|
ASSERT_TRUE (destination_info);
|
|
ASSERT_EQ (destination_info->epoch (), nano::epoch::epoch_2);
|
|
// Upgrade an unopened account straight to epoch 2
|
|
nano::keypair destination4;
|
|
auto send6 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send5->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio * 5)
|
|
.link (destination4.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send5->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send6));
|
|
auto epoch4 = builder
|
|
.state ()
|
|
.account (destination4.pub)
|
|
.previous (0)
|
|
.representative (0)
|
|
.balance (0)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_2))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (destination4.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch4));
|
|
ASSERT_EQ (nano::epoch::epoch_2, epoch4->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch4->sideband ().source_epoch); // Not used for epoch blocks
|
|
ASSERT_EQ (store.account.count (transaction), ledger.account_count ());
|
|
}
|
|
|
|
TEST (ledger, epoch_blocks_fork)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (nano::account{})
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.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));
|
|
auto epoch1 = 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)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, epoch1));
|
|
auto epoch2 = 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)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_2))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, epoch2));
|
|
auto epoch3 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, epoch3));
|
|
ASSERT_EQ (nano::epoch::epoch_1, epoch3->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch3->sideband ().source_epoch); // Not used for epoch state blocks
|
|
auto epoch4 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_2))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::fork, ledger.process (transaction, epoch2));
|
|
}
|
|
|
|
TEST (ledger, successor_epoch)
|
|
{
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::keypair key1;
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (key1.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 1)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto open = builder
|
|
.state ()
|
|
.account (key1.pub)
|
|
.previous (0)
|
|
.representative (key1.pub)
|
|
.balance (1)
|
|
.link (send1->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto change = builder
|
|
.state ()
|
|
.account (key1.pub)
|
|
.previous (open->hash ())
|
|
.representative (key1.pub)
|
|
.balance (1)
|
|
.link (0)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (open->hash ()))
|
|
.build ();
|
|
auto open_hash = open->hash ();
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (send1->hash ())
|
|
.destination (reinterpret_cast<nano::account const &> (open_hash))
|
|
.balance (nano::dev::constants.genesis_amount - 2)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
auto epoch_open = builder
|
|
.state ()
|
|
.account (reinterpret_cast<nano::account const &> (open_hash))
|
|
.previous (0)
|
|
.representative (0)
|
|
.balance (0)
|
|
.link (node1.ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (open->hash ()))
|
|
.build ();
|
|
auto transaction = node1.ledger.tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, send1));
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, open));
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, change));
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, send2));
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, epoch_open));
|
|
ASSERT_EQ (*change, *node1.ledger.any.block_get (transaction, node1.ledger.any.block_successor (transaction, change->qualified_root ()).value ()));
|
|
ASSERT_EQ (*epoch_open, *node1.ledger.any.block_get (transaction, node1.ledger.any.block_successor (transaction, epoch_open->qualified_root ()).value ()));
|
|
ASSERT_EQ (nano::epoch::epoch_1, epoch_open->sideband ().details.epoch);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch_open->sideband ().source_epoch); // Not used for epoch state blocks
|
|
}
|
|
|
|
TEST (ledger, epoch_open_pending)
|
|
{
|
|
nano::block_builder builder{};
|
|
nano::test::system system{ 1 };
|
|
auto & node1 = *system.nodes[0];
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::keypair key1{};
|
|
auto epoch_open = builder.state ()
|
|
.account (key1.pub)
|
|
.previous (0)
|
|
.representative (0)
|
|
.balance (0)
|
|
.link (node1.ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
auto process_result = node1.ledger.process (node1.ledger.tx_begin_write (), epoch_open);
|
|
ASSERT_EQ (nano::block_status::gap_epoch_open_pending, process_result);
|
|
node1.block_processor.add (epoch_open);
|
|
// Waits for the block to get saved in the database
|
|
ASSERT_TIMELY_EQ (10s, 1, node1.unchecked.count ());
|
|
ASSERT_FALSE (node1.block_or_pruned_exists (epoch_open->hash ()));
|
|
// Open block should be inserted into unchecked
|
|
auto blocks = node1.unchecked.get (nano::hash_or_account (epoch_open->account_field ().value ()).hash);
|
|
ASSERT_EQ (blocks.size (), 1);
|
|
ASSERT_EQ (blocks[0].block->full_hash (), epoch_open->full_hash ());
|
|
// New block to process epoch open
|
|
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 ();
|
|
node1.block_processor.add (send1);
|
|
ASSERT_TIMELY (10s, node1.block_or_pruned_exists (epoch_open->hash ()));
|
|
}
|
|
|
|
TEST (ledger, block_hash_account_conflict)
|
|
{
|
|
nano::block_builder builder;
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::keypair key1;
|
|
nano::keypair key2;
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
|
|
/*
|
|
* Generate a send block whose destination is a block hash already
|
|
* in the ledger and not an account
|
|
*/
|
|
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 ();
|
|
|
|
auto receive1 = builder.state ()
|
|
.account (key1.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (100)
|
|
.link (send1->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
|
|
/*
|
|
* Note that the below link is a block hash when this is intended
|
|
* to represent a send state block. This can generally never be
|
|
* received , except by epoch blocks, which can sign an open block
|
|
* for arbitrary accounts.
|
|
*/
|
|
auto send2 = builder.state ()
|
|
.account (key1.pub)
|
|
.previous (receive1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (90)
|
|
.link (receive1->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (receive1->hash ()))
|
|
.build ();
|
|
|
|
/*
|
|
* Generate an epoch open for the account with the same value as the block hash
|
|
*/
|
|
auto receive1_hash = receive1->hash ();
|
|
auto open_epoch1 = builder.state ()
|
|
.account (reinterpret_cast<nano::account const &> (receive1_hash))
|
|
.previous (0)
|
|
.representative (0)
|
|
.balance (0)
|
|
.link (node1.ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (receive1->hash ()))
|
|
.build ();
|
|
|
|
node1.work_generate_blocking (*send1);
|
|
node1.work_generate_blocking (*receive1);
|
|
node1.work_generate_blocking (*send2);
|
|
node1.work_generate_blocking (*open_epoch1);
|
|
ASSERT_EQ (nano::block_status::progress, node1.process (send1));
|
|
ASSERT_EQ (nano::block_status::progress, node1.process (receive1));
|
|
ASSERT_EQ (nano::block_status::progress, node1.process (send2));
|
|
ASSERT_EQ (nano::block_status::progress, node1.process (open_epoch1));
|
|
ASSERT_TRUE (nano::test::start_elections (system, node1, { send1, receive1, send2, open_epoch1 }));
|
|
auto election1 = node1.active.election (send1->qualified_root ());
|
|
ASSERT_NE (nullptr, election1);
|
|
auto election2 = node1.active.election (receive1->qualified_root ());
|
|
ASSERT_NE (nullptr, election2);
|
|
auto election3 = node1.active.election (send2->qualified_root ());
|
|
ASSERT_NE (nullptr, election3);
|
|
auto election4 = node1.active.election (open_epoch1->qualified_root ());
|
|
ASSERT_NE (nullptr, election4);
|
|
auto winner1 (election1->winner ());
|
|
auto winner2 (election2->winner ());
|
|
auto winner3 (election3->winner ());
|
|
auto winner4 (election4->winner ());
|
|
ASSERT_EQ (*send1, *winner1);
|
|
ASSERT_EQ (*receive1, *winner2);
|
|
ASSERT_EQ (*send2, *winner3);
|
|
ASSERT_EQ (*open_epoch1, *winner4);
|
|
}
|
|
|
|
TEST (ledger, unchecked_epoch)
|
|
{
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
auto open1 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*open1);
|
|
auto epoch1 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (open1->hash ())
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (node1.ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*epoch1);
|
|
node1.block_processor.add (epoch1);
|
|
{
|
|
// Waits for the epoch1 block to pass through block_processor and unchecked.put queues
|
|
ASSERT_TIMELY_EQ (10s, 1, node1.unchecked.count ());
|
|
auto blocks = node1.unchecked.get (epoch1->previous ());
|
|
ASSERT_EQ (blocks.size (), 1);
|
|
}
|
|
node1.block_processor.add (send1);
|
|
node1.block_processor.add (open1);
|
|
ASSERT_TIMELY (5s, node1.ledger.any.block_exists (node1.ledger.tx_begin_read (), epoch1->hash ()));
|
|
{
|
|
// Waits for the last blocks to pass through block_processor and unchecked.put queues
|
|
ASSERT_TIMELY_EQ (10s, 0, node1.unchecked.count ());
|
|
auto info = node1.ledger.any.account_get (node1.ledger.tx_begin_read (), destination.pub);
|
|
ASSERT_TRUE (info);
|
|
ASSERT_EQ (info->epoch (), nano::epoch::epoch_1);
|
|
}
|
|
}
|
|
|
|
TEST (ledger, unchecked_epoch_invalid)
|
|
{
|
|
nano::test::system system;
|
|
nano::node_config node_config = system.default_config ();
|
|
node_config.backlog_scan.enable = false;
|
|
auto & node1 (*system.add_node (node_config));
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
auto open1 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (0)
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*open1);
|
|
// Epoch block with account own signature
|
|
auto epoch1 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (open1->hash ())
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio)
|
|
.link (node1.ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (destination.prv, destination.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*epoch1);
|
|
// Pseudo epoch block (send subtype, destination - epoch link)
|
|
auto epoch2 = builder
|
|
.state ()
|
|
.account (destination.pub)
|
|
.previous (open1->hash ())
|
|
.representative (destination.pub)
|
|
.balance (nano::Knano_ratio - 1)
|
|
.link (node1.ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (destination.prv, destination.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*epoch2);
|
|
node1.block_processor.add (epoch1);
|
|
node1.block_processor.add (epoch2);
|
|
{
|
|
// Waits for the last blocks to pass through block_processor and unchecked.put queues
|
|
ASSERT_TIMELY_EQ (10s, 2, node1.unchecked.count ());
|
|
auto blocks = node1.unchecked.get (epoch1->previous ());
|
|
ASSERT_EQ (blocks.size (), 2);
|
|
}
|
|
node1.block_processor.add (send1);
|
|
node1.block_processor.add (open1);
|
|
// Waits for the last blocks to pass through block_processor and unchecked.put queues
|
|
ASSERT_TIMELY (10s, node1.ledger.any.block_exists (node1.ledger.tx_begin_read (), epoch2->hash ()));
|
|
{
|
|
auto transaction = node1.ledger.tx_begin_read ();
|
|
ASSERT_FALSE (node1.ledger.any.block_exists (transaction, epoch1->hash ()));
|
|
auto unchecked_count = node1.unchecked.count ();
|
|
ASSERT_EQ (unchecked_count, 0);
|
|
ASSERT_EQ (unchecked_count, node1.unchecked.count ());
|
|
auto info = node1.ledger.any.account_get (transaction, destination.pub);
|
|
ASSERT_TRUE (info);
|
|
ASSERT_NE (info->epoch (), nano::epoch::epoch_1);
|
|
auto epoch2_store = node1.ledger.any.block_get (transaction, epoch2->hash ());
|
|
ASSERT_NE (nullptr, epoch2_store);
|
|
ASSERT_EQ (nano::epoch::epoch_0, epoch2_store->sideband ().details.epoch);
|
|
ASSERT_TRUE (epoch2_store->is_send ());
|
|
ASSERT_FALSE (epoch2_store->sideband ().details.is_epoch);
|
|
ASSERT_FALSE (epoch2_store->is_receive ());
|
|
}
|
|
}
|
|
|
|
TEST (ledger, unchecked_open)
|
|
{
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::keypair destination;
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send1);
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (destination.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*open1);
|
|
// Invalid signature for open block
|
|
auto open2 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*open2);
|
|
open2->signature.bytes[0] ^= 1;
|
|
node1.block_processor.add (open2); // Insert open2 in to the queue before open1
|
|
node1.block_processor.add (open1);
|
|
{
|
|
// Waits for the last blocks to pass through block_processor and unchecked.put queues
|
|
ASSERT_TIMELY_EQ (10s, 1, node1.unchecked.count ());
|
|
// Get the next peer for attempting a tcp bootstrap connection
|
|
auto blocks = node1.unchecked.get (open1->source_field ().value ());
|
|
ASSERT_EQ (blocks.size (), 1);
|
|
}
|
|
node1.block_processor.add (send1);
|
|
// Waits for the send1 block to pass through block_processor and unchecked.put queues
|
|
ASSERT_TIMELY (5s, node1.ledger.any.block_exists (node1.ledger.tx_begin_read (), open1->hash ()));
|
|
ASSERT_EQ (0, node1.unchecked.count ());
|
|
}
|
|
|
|
TEST (ledger, unchecked_receive)
|
|
{
|
|
nano::test::system system{ 1 };
|
|
auto & node1 = *system.nodes[0];
|
|
nano::keypair destination{};
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*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::Knano_ratio)
|
|
.link (destination.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*send2);
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (destination.pub)
|
|
.account (destination.pub)
|
|
.sign (destination.prv, destination.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*open1);
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (open1->hash ())
|
|
.source (send2->hash ())
|
|
.sign (destination.prv, destination.pub)
|
|
.work (0)
|
|
.build ();
|
|
node1.work_generate_blocking (*receive1);
|
|
node1.block_processor.add (send1);
|
|
node1.block_processor.add (receive1);
|
|
auto check_block_is_listed = [&] (nano::store::transaction const & transaction_a, nano::block_hash const & block_hash_a) {
|
|
return !node1.unchecked.get (block_hash_a).empty ();
|
|
};
|
|
// Previous block for receive1 is unknown, signature cannot be validated
|
|
{
|
|
// Waits for the last blocks to pass through block_processor and unchecked.put queues
|
|
ASSERT_TIMELY (15s, check_block_is_listed (node1.store.tx_begin_read (), receive1->previous ()));
|
|
auto blocks = node1.unchecked.get (receive1->previous ());
|
|
ASSERT_EQ (blocks.size (), 1);
|
|
}
|
|
// Waits for the open1 block to pass through block_processor and unchecked.put queues
|
|
node1.block_processor.add (open1);
|
|
ASSERT_TIMELY (15s, check_block_is_listed (node1.store.tx_begin_read (), receive1->source_field ().value ()));
|
|
// Previous block for receive1 is known, signature was validated
|
|
{
|
|
auto transaction = node1.store.tx_begin_read ();
|
|
auto blocks (node1.unchecked.get (receive1->source_field ().value ()));
|
|
ASSERT_EQ (blocks.size (), 1);
|
|
}
|
|
node1.block_processor.add (send2);
|
|
ASSERT_TIMELY (10s, node1.ledger.any.block_exists (node1.ledger.tx_begin_read (), receive1->hash ()));
|
|
ASSERT_EQ (0, node1.unchecked.count ());
|
|
}
|
|
|
|
TEST (ledger, confirmation_height_not_updated)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
auto & pool = ctx.pool ();
|
|
auto account_info = ledger.any.account_get (transaction, nano::dev::genesis_key.pub);
|
|
ASSERT_TRUE (account_info);
|
|
nano::keypair key;
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (account_info->head)
|
|
.destination (key.pub)
|
|
.balance (50)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (account_info->head))
|
|
.build ();
|
|
nano::confirmation_height_info confirmation_height_info;
|
|
ASSERT_FALSE (store.confirmation_height.get (transaction, nano::dev::genesis_key.pub, confirmation_height_info));
|
|
ASSERT_EQ (1, confirmation_height_info.height);
|
|
ASSERT_EQ (nano::dev::genesis->hash (), confirmation_height_info.frontier);
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
|
|
ASSERT_FALSE (store.confirmation_height.get (transaction, nano::dev::genesis_key.pub, confirmation_height_info));
|
|
ASSERT_EQ (1, confirmation_height_info.height);
|
|
ASSERT_EQ (nano::dev::genesis->hash (), confirmation_height_info.frontier);
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (key.pub)
|
|
.sign (key.prv, key.pub)
|
|
.work (*pool.generate (key.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
ASSERT_TRUE (store.confirmation_height.get (transaction, key.pub, confirmation_height_info));
|
|
ASSERT_EQ (0, confirmation_height_info.height);
|
|
ASSERT_EQ (nano::block_hash (0), confirmation_height_info.frontier);
|
|
}
|
|
|
|
TEST (ledger, zero_rep)
|
|
{
|
|
nano::test::system system (1);
|
|
auto & node1 (*system.nodes[0]);
|
|
nano::block_builder builder;
|
|
auto block1 = builder.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (0)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*system.work.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
auto transaction = node1.ledger.tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, block1));
|
|
ASSERT_EQ (0, node1.ledger.rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, node1.ledger.rep_weights.get (0));
|
|
auto block2 = builder.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (block1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (0)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*system.work.generate (block1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, node1.ledger.process (transaction, block2));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount, node1.ledger.rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (0, node1.ledger.rep_weights.get (0));
|
|
}
|
|
|
|
TEST (ledger, work_validation)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
auto gen = nano::dev::genesis_key;
|
|
nano::keypair key;
|
|
|
|
// With random work the block doesn't pass, then modifies the block with sufficient work and ensures a correct result
|
|
auto process_block = [&store, &ledger, &pool] (std::shared_ptr<nano::block> block_a, nano::block_details const details_a) {
|
|
auto threshold = nano::dev::network_params.work.threshold (block_a->work_version (), details_a);
|
|
// Rarely failed with random work, so modify until it doesn't have enough difficulty
|
|
while (nano::dev::network_params.work.difficulty (*block_a) >= threshold)
|
|
{
|
|
block_a->block_work_set (block_a->block_work () + 1);
|
|
}
|
|
EXPECT_EQ (nano::block_status::insufficient_work, ledger.process (ledger.tx_begin_write (), block_a));
|
|
block_a->block_work_set (*pool.generate (block_a->root (), threshold));
|
|
EXPECT_EQ (nano::block_status::progress, ledger.process (ledger.tx_begin_write (), block_a));
|
|
};
|
|
|
|
std::error_code ec;
|
|
|
|
auto send = builder.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (gen.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 1)
|
|
.sign (gen.prv, gen.pub)
|
|
.work (0)
|
|
.build (ec);
|
|
ASSERT_FALSE (ec);
|
|
|
|
auto receive = builder.receive ()
|
|
.previous (send->hash ())
|
|
.source (send->hash ())
|
|
.sign (gen.prv, gen.pub)
|
|
.work (0)
|
|
.build (ec);
|
|
ASSERT_FALSE (ec);
|
|
|
|
auto change = builder.change ()
|
|
.previous (receive->hash ())
|
|
.representative (key.pub)
|
|
.sign (gen.prv, gen.pub)
|
|
.work (0)
|
|
.build (ec);
|
|
ASSERT_FALSE (ec);
|
|
|
|
auto state = builder.state ()
|
|
.account (gen.pub)
|
|
.previous (change->hash ())
|
|
.representative (gen.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 1)
|
|
.link (key.pub)
|
|
.sign (gen.prv, gen.pub)
|
|
.work (0)
|
|
.build (ec);
|
|
ASSERT_FALSE (ec);
|
|
|
|
auto open = builder.open ()
|
|
.account (key.pub)
|
|
.source (state->hash ())
|
|
.representative (key.pub)
|
|
.sign (key.prv, key.pub)
|
|
.work (0)
|
|
.build (ec);
|
|
ASSERT_FALSE (ec);
|
|
|
|
auto epoch = builder.state ()
|
|
.account (key.pub)
|
|
.previous (open->hash ())
|
|
.balance (1)
|
|
.representative (key.pub)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.sign (gen.prv, gen.pub)
|
|
.work (0)
|
|
.build (ec);
|
|
ASSERT_FALSE (ec);
|
|
|
|
process_block (send, {});
|
|
process_block (receive, {});
|
|
process_block (change, {});
|
|
process_block (state, nano::block_details (nano::epoch::epoch_0, true, false, false));
|
|
process_block (open, {});
|
|
process_block (epoch, nano::block_details (nano::epoch::epoch_1, false, false, true));
|
|
}
|
|
|
|
TEST (ledger, dependents_confirmed)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::block_builder builder;
|
|
ASSERT_TRUE (ledger.dependents_confirmed (transaction, *nano::dev::genesis));
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
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));
|
|
ASSERT_TRUE (ledger.dependents_confirmed (transaction, *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 - 200)
|
|
.link (key1.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
ASSERT_FALSE (ledger.dependents_confirmed (transaction, *send2));
|
|
auto receive1 = builder.state ()
|
|
.account (key1.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.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, receive1));
|
|
ASSERT_FALSE (ledger.dependents_confirmed (transaction, *receive1));
|
|
ledger.confirm (transaction, send1->hash ());
|
|
ASSERT_TRUE (ledger.dependents_confirmed (transaction, *receive1));
|
|
auto receive2 = builder.state ()
|
|
.account (key1.pub)
|
|
.previous (receive1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (200)
|
|
.link (send2->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (receive1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive2));
|
|
ASSERT_FALSE (ledger.dependents_confirmed (transaction, *receive2));
|
|
ledger.confirm (transaction, receive1->hash ());
|
|
ASSERT_FALSE (ledger.dependents_confirmed (transaction, *receive2));
|
|
ledger.confirm (transaction, send2->hash ());
|
|
ASSERT_TRUE (ledger.dependents_confirmed (transaction, *receive2));
|
|
}
|
|
|
|
TEST (ledger, dependents_confirmed_pruning)
|
|
{
|
|
nano::logger logger;
|
|
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
|
|
ASSERT_FALSE (store->init_error ());
|
|
nano::stats stats{ logger };
|
|
nano::ledger ledger (*store, nano::dev::constants, stats, logger);
|
|
ledger.pruning = true;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::block_builder builder;
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::keypair key1;
|
|
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));
|
|
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 - 200)
|
|
.link (key1.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
ledger.confirm (transaction, send2->hash ());
|
|
ASSERT_TRUE (ledger.confirmed.block_exists_or_pruned (transaction, send1->hash ()));
|
|
ASSERT_EQ (2, ledger.pruning_action (transaction, send2->hash (), 1));
|
|
auto receive1 = builder.state ()
|
|
.account (key1.pub)
|
|
.previous (0)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (100)
|
|
.link (send1->hash ())
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
ASSERT_TRUE (ledger.dependents_confirmed (transaction, *receive1));
|
|
}
|
|
|
|
TEST (ledger, block_confirmed)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::block_builder builder;
|
|
ASSERT_TRUE (ledger.confirmed.block_exists_or_pruned (transaction, nano::dev::genesis->hash ()));
|
|
auto & pool = ctx.pool ();
|
|
nano::keypair key1;
|
|
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 ();
|
|
// Must be safe against non-existing blocks
|
|
ASSERT_FALSE (ledger.confirmed.block_exists_or_pruned (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
|
|
ASSERT_FALSE (ledger.confirmed.block_exists_or_pruned (transaction, send1->hash ()));
|
|
ledger.confirm (transaction, send1->hash ());
|
|
ASSERT_TRUE (ledger.confirmed.block_exists_or_pruned (transaction, send1->hash ()));
|
|
}
|
|
|
|
TEST (ledger, cache)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto & stats = ctx.stats ();
|
|
auto & logger = ctx.logger ();
|
|
auto & pool = ctx.pool ();
|
|
nano::block_builder builder;
|
|
|
|
size_t const total = 100;
|
|
|
|
// Check existing ledger (incremental cache update) and reload on a new ledger
|
|
for (size_t i (0); i < total; ++i)
|
|
{
|
|
auto account_count = 1 + i;
|
|
auto block_count = 1 + 2 * (i + 1) - 2;
|
|
auto cemented_count = 1 + 2 * (i + 1) - 2;
|
|
auto genesis_weight = nano::dev::constants.genesis_amount - i;
|
|
auto pruned_count = i;
|
|
|
|
auto cache_check = [&, i] (nano::ledger const & ledger) {
|
|
ASSERT_EQ (account_count, ledger.account_count ());
|
|
ASSERT_EQ (block_count, ledger.block_count ());
|
|
ASSERT_EQ (cemented_count, ledger.cemented_count ());
|
|
ASSERT_EQ (genesis_weight, ledger.rep_weights.get (nano::dev::genesis_key.pub));
|
|
ASSERT_EQ (pruned_count, ledger.pruned_count ());
|
|
};
|
|
|
|
cache_check (ledger);
|
|
cache_check (nano::ledger (store, nano::dev::constants, stats, logger));
|
|
|
|
nano::keypair key;
|
|
auto const latest = ledger.any.account_head (ledger.tx_begin_read (), nano::dev::genesis_key.pub);
|
|
auto send = builder.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (latest)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - (i + 1))
|
|
.link (key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (latest))
|
|
.build ();
|
|
auto open = builder.state ()
|
|
.account (key.pub)
|
|
.previous (0)
|
|
.representative (key.pub)
|
|
.balance (1)
|
|
.link (send->hash ())
|
|
.sign (key.prv, key.pub)
|
|
.work (*pool.generate (key.pub))
|
|
.build ();
|
|
{
|
|
auto transaction = ledger.tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
|
}
|
|
|
|
++block_count;
|
|
--genesis_weight;
|
|
cache_check (ledger);
|
|
cache_check (nano::ledger (store, nano::dev::constants, stats, logger));
|
|
|
|
{
|
|
auto transaction = ledger.tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open));
|
|
}
|
|
|
|
++block_count;
|
|
++account_count;
|
|
cache_check (ledger);
|
|
cache_check (nano::ledger (store, nano::dev::constants, stats, logger));
|
|
|
|
{
|
|
auto transaction = ledger.tx_begin_write ();
|
|
ledger.confirm (transaction, send->hash ());
|
|
ASSERT_TRUE (ledger.confirmed.block_exists_or_pruned (transaction, send->hash ()));
|
|
}
|
|
|
|
++cemented_count;
|
|
cache_check (ledger);
|
|
cache_check (nano::ledger (store, nano::dev::constants, stats, logger));
|
|
|
|
{
|
|
auto transaction = ledger.tx_begin_write ();
|
|
ledger.confirm (transaction, open->hash ());
|
|
ASSERT_TRUE (ledger.confirmed.block_exists_or_pruned (transaction, open->hash ()));
|
|
}
|
|
|
|
++cemented_count;
|
|
cache_check (ledger);
|
|
cache_check (nano::ledger (store, nano::dev::constants, stats, logger));
|
|
|
|
{
|
|
auto transaction = ledger.tx_begin_write ();
|
|
ledger.pruning_action (transaction, open->hash (), 1);
|
|
}
|
|
++pruned_count;
|
|
cache_check (ledger);
|
|
cache_check (nano::ledger (store, nano::dev::constants, stats, logger));
|
|
}
|
|
}
|
|
|
|
TEST (ledger, pruning_action)
|
|
{
|
|
nano::logger logger;
|
|
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
|
|
ASSERT_TRUE (!store->init_error ());
|
|
nano::stats stats{ logger };
|
|
nano::ledger ledger (*store, nano::dev::constants, stats, logger);
|
|
ledger.pruning = true;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
auto send1_stored (store->block.get (transaction, send1->hash ()));
|
|
ASSERT_NE (nullptr, send1_stored);
|
|
ASSERT_EQ (*send1, *send1_stored);
|
|
ASSERT_TRUE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
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 - nano::Knano_ratio * 2)
|
|
.link (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
// Pruning action
|
|
ledger.confirm (transaction, send1->hash ());
|
|
ASSERT_EQ (1, ledger.pruning_action (transaction, send1->hash (), 1));
|
|
ASSERT_EQ (0, ledger.pruning_action (transaction, nano::dev::genesis->hash (), 1));
|
|
ASSERT_TRUE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists_or_pruned (transaction, send1->hash ()));
|
|
// Pruned ledger start without proper flags emulation
|
|
ledger.pruning = false;
|
|
ASSERT_TRUE (ledger.any.block_exists_or_pruned (transaction, send1->hash ()));
|
|
ledger.pruning = true;
|
|
ASSERT_TRUE (store->pruned.exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, nano::dev::genesis->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
// Receiving pruned block
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send2->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, receive1->hash ()));
|
|
auto receive1_stored (store->block.get (transaction, receive1->hash ()));
|
|
ASSERT_NE (nullptr, receive1_stored);
|
|
ASSERT_EQ (*receive1, *receive1_stored);
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_EQ (4, receive1_stored->sideband ().height);
|
|
ASSERT_FALSE (receive1_stored->is_send ());
|
|
ASSERT_TRUE (receive1_stored->is_receive ());
|
|
ASSERT_FALSE (receive1_stored->sideband ().details.is_epoch);
|
|
// Middle block pruning
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
ledger.confirm (transaction, send2->hash ());
|
|
ASSERT_EQ (1, ledger.pruning_action (transaction, send2->hash (), 1));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, send2->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
ASSERT_EQ (store->account.count (transaction), ledger.account_count ());
|
|
ASSERT_EQ (store->pruned.count (transaction), ledger.pruned_count ());
|
|
ASSERT_EQ (store->block.count (transaction), ledger.block_count () - ledger.pruned_count ());
|
|
}
|
|
|
|
TEST (ledger, pruning_large_chain)
|
|
{
|
|
nano::logger logger;
|
|
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
|
|
ASSERT_TRUE (!store->init_error ());
|
|
nano::stats stats{ logger };
|
|
nano::ledger ledger (*store, nano::dev::constants, stats, logger);
|
|
ledger.pruning = true;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
size_t send_receive_pairs (20);
|
|
auto last_hash (nano::dev::genesis->hash ());
|
|
nano::block_builder builder;
|
|
for (auto i (0); i < send_receive_pairs; i++)
|
|
{
|
|
auto send = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (last_hash)
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (last_hash))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send->hash ()));
|
|
auto receive = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount)
|
|
.link (send->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, receive->hash ()));
|
|
last_hash = receive->hash ();
|
|
}
|
|
ASSERT_EQ (0, store->pruned.count (transaction));
|
|
ASSERT_EQ (send_receive_pairs * 2 + 1, store->block.count (transaction));
|
|
ledger.confirm (transaction, last_hash);
|
|
// Pruning action
|
|
ASSERT_EQ (send_receive_pairs * 2, ledger.pruning_action (transaction, last_hash, 5));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, last_hash));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, nano::dev::genesis->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, last_hash));
|
|
ASSERT_EQ (store->pruned.count (transaction), ledger.pruned_count ());
|
|
ASSERT_EQ (store->block.count (transaction), ledger.block_count () - ledger.pruned_count ());
|
|
ASSERT_EQ (send_receive_pairs * 2, store->pruned.count (transaction));
|
|
ASSERT_EQ (1, store->block.count (transaction)); // Genesis
|
|
}
|
|
|
|
TEST (ledger, pruning_source_rollback)
|
|
{
|
|
nano::logger logger;
|
|
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
|
|
ASSERT_TRUE (!store->init_error ());
|
|
nano::stats stats{ logger };
|
|
nano::ledger ledger (*store, nano::dev::constants, stats, logger);
|
|
ledger.pruning = true;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::block_builder builder;
|
|
auto epoch1 = 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)
|
|
.link (ledger.epoch_link (nano::epoch::epoch_1))
|
|
.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, epoch1));
|
|
auto send1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (epoch1->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (epoch1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send1));
|
|
ASSERT_TRUE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
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 - nano::Knano_ratio * 2)
|
|
.link (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
ledger.confirm (transaction, send1->hash ());
|
|
// Pruning action
|
|
ASSERT_EQ (2, ledger.pruning_action (transaction, send1->hash (), 1));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, send1->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, epoch1->hash ()));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, epoch1->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, nano::dev::genesis->hash ()));
|
|
auto info = ledger.any.pending_get (transaction, nano::pending_key (nano::dev::genesis_key.pub, send1->hash ()));
|
|
ASSERT_TRUE (info);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, info->source);
|
|
ASSERT_EQ (nano::Knano_ratio, info->amount.number ());
|
|
ASSERT_EQ (nano::epoch::epoch_1, info->epoch);
|
|
// Receiving pruned block
|
|
auto receive1 = builder
|
|
.state ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (send2->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.link (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_EQ (2, ledger.pruned_count ());
|
|
ASSERT_EQ (5, ledger.block_count ());
|
|
// Rollback receive block
|
|
ASSERT_FALSE (ledger.rollback (transaction, receive1->hash ()));
|
|
auto info2 = ledger.any.pending_get (transaction, nano::pending_key (nano::dev::genesis_key.pub, send1->hash ()));
|
|
ASSERT_TRUE (info2);
|
|
ASSERT_NE (nano::dev::genesis_key.pub, info2->source); // Tradeoff to not store pruned blocks accounts
|
|
ASSERT_EQ (nano::Knano_ratio, info2->amount.number ());
|
|
ASSERT_EQ (nano::epoch::epoch_1, info2->epoch);
|
|
// Process receive block again
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_EQ (2, ledger.pruned_count ());
|
|
ASSERT_EQ (5, ledger.block_count ());
|
|
}
|
|
|
|
TEST (ledger, pruning_source_rollback_legacy)
|
|
{
|
|
nano::logger logger;
|
|
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
|
|
ASSERT_TRUE (!store->init_error ());
|
|
nano::stats stats{ logger };
|
|
nano::ledger ledger (*store, nano::dev::constants, stats, logger);
|
|
ledger.pruning = true;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.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));
|
|
ASSERT_TRUE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
nano::keypair key1;
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (send1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 2 * nano::Knano_ratio)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
ASSERT_TRUE (ledger.any.pending_get (transaction, nano::pending_key{ key1.pub, send2->hash () }));
|
|
auto send3 = builder
|
|
.send ()
|
|
.previous (send2->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - 3 * nano::Knano_ratio)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send2->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send3));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send3->hash ()));
|
|
ASSERT_TRUE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send3->hash () }));
|
|
ledger.confirm (transaction, send2->hash ());
|
|
// Pruning action
|
|
ASSERT_EQ (2, ledger.pruning_action (transaction, send2->hash (), 1));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, send2->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, nano::dev::genesis->hash ()));
|
|
auto info1 = ledger.any.pending_get (transaction, nano::pending_key (nano::dev::genesis_key.pub, send1->hash ()));
|
|
ASSERT_TRUE (info1);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, info1->source);
|
|
ASSERT_EQ (nano::Knano_ratio, info1->amount.number ());
|
|
ASSERT_EQ (nano::epoch::epoch_0, info1->epoch);
|
|
auto info2 = ledger.any.pending_get (transaction, nano::pending_key (key1.pub, send2->hash ()));
|
|
ASSERT_TRUE (info2);
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, info2->source);
|
|
ASSERT_EQ (nano::Knano_ratio, info2->amount.number ());
|
|
ASSERT_EQ (nano::epoch::epoch_0, info2->epoch);
|
|
// Receiving pruned block
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (send3->hash ())
|
|
.source (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send3->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_EQ (2, ledger.pruned_count ());
|
|
ASSERT_EQ (5, ledger.block_count ());
|
|
// Rollback receive block
|
|
ASSERT_FALSE (ledger.rollback (transaction, receive1->hash ()));
|
|
auto info3 = ledger.any.pending_get (transaction, nano::pending_key (nano::dev::genesis_key.pub, send1->hash ()));
|
|
ASSERT_TRUE (info3);
|
|
ASSERT_NE (nano::dev::genesis_key.pub, info3->source); // Tradeoff to not store pruned blocks accounts
|
|
ASSERT_EQ (nano::Knano_ratio, info3->amount.number ());
|
|
ASSERT_EQ (nano::epoch::epoch_0, info3->epoch);
|
|
// Process receive block again
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
ASSERT_EQ (2, ledger.pruned_count ());
|
|
ASSERT_EQ (5, ledger.block_count ());
|
|
// Receiving pruned block (open)
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send2->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ key1.pub, send2->hash () }));
|
|
ASSERT_EQ (2, ledger.pruned_count ());
|
|
ASSERT_EQ (6, ledger.block_count ());
|
|
// Rollback open block
|
|
ASSERT_FALSE (ledger.rollback (transaction, open1->hash ()));
|
|
auto info4 = ledger.any.pending_get (transaction, nano::pending_key (key1.pub, send2->hash ()));
|
|
ASSERT_TRUE (info4);
|
|
ASSERT_NE (nano::dev::genesis_key.pub, info4->source); // Tradeoff to not store pruned blocks accounts
|
|
ASSERT_EQ (nano::Knano_ratio, info4->amount.number ());
|
|
ASSERT_EQ (nano::epoch::epoch_0, info4->epoch);
|
|
// Process open block again
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
ASSERT_FALSE (ledger.any.pending_get (transaction, nano::pending_key{ key1.pub, send2->hash () }));
|
|
ASSERT_EQ (2, ledger.pruned_count ());
|
|
ASSERT_EQ (6, ledger.block_count ());
|
|
}
|
|
|
|
TEST (ledger, pruning_legacy_blocks)
|
|
{
|
|
nano::logger logger;
|
|
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
|
|
ASSERT_TRUE (!store->init_error ());
|
|
nano::stats stats{ logger };
|
|
nano::ledger ledger (*store, nano::dev::constants, stats, logger);
|
|
ledger.pruning = true;
|
|
nano::keypair key1;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::block_builder builder;
|
|
auto send1 = builder
|
|
.send ()
|
|
.previous (nano::dev::genesis->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.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));
|
|
ASSERT_TRUE (ledger.any.pending_get (transaction, nano::pending_key{ nano::dev::genesis_key.pub, send1->hash () }));
|
|
auto receive1 = builder
|
|
.receive ()
|
|
.previous (send1->hash ())
|
|
.source (send1->hash ())
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, receive1));
|
|
auto change1 = builder
|
|
.change ()
|
|
.previous (receive1->hash ())
|
|
.representative (key1.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (receive1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, change1));
|
|
auto send2 = builder
|
|
.send ()
|
|
.previous (change1->hash ())
|
|
.destination (key1.pub)
|
|
.balance (nano::dev::constants.genesis_amount - nano::Knano_ratio)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (change1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
auto open1 = builder
|
|
.open ()
|
|
.source (send2->hash ())
|
|
.representative (nano::dev::genesis_key.pub)
|
|
.account (key1.pub)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (key1.pub))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, open1));
|
|
auto send3 = builder
|
|
.send ()
|
|
.previous (open1->hash ())
|
|
.destination (nano::dev::genesis_key.pub)
|
|
.balance (0)
|
|
.sign (key1.prv, key1.pub)
|
|
.work (*pool.generate (open1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send3));
|
|
ledger.confirm (transaction, open1->hash ());
|
|
// Pruning action
|
|
ASSERT_EQ (3, ledger.pruning_action (transaction, change1->hash (), 2));
|
|
ASSERT_EQ (1, ledger.pruning_action (transaction, open1->hash (), 1));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, nano::dev::genesis->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, send1->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, receive1->hash ()));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, receive1->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, change1->hash ()));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, change1->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, open1->hash ()));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, open1->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send3->hash ()));
|
|
ASSERT_EQ (4, ledger.pruned_count ());
|
|
ASSERT_EQ (7, ledger.block_count ());
|
|
ASSERT_EQ (store->pruned.count (transaction), ledger.pruned_count ());
|
|
ASSERT_EQ (store->block.count (transaction), ledger.block_count () - ledger.pruned_count ());
|
|
}
|
|
|
|
TEST (ledger, pruning_safe_functions)
|
|
{
|
|
nano::logger logger;
|
|
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
|
|
ASSERT_TRUE (!store->init_error ());
|
|
nano::stats stats{ logger };
|
|
nano::ledger ledger (*store, nano::dev::constants, stats, logger);
|
|
ledger.pruning = true;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
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 - nano::Knano_ratio * 2)
|
|
.link (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
ledger.confirm (transaction, send1->hash ());
|
|
// Pruning action
|
|
ASSERT_EQ (1, ledger.pruning_action (transaction, send1->hash (), 1));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists_or_pruned (transaction, send1->hash ())); // true for pruned
|
|
ASSERT_TRUE (store->pruned.exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, nano::dev::genesis->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
// Safe ledger actions
|
|
ASSERT_FALSE (ledger.any.block_balance (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::constants.genesis_amount - nano::Knano_ratio * 2, ledger.any.block_balance (transaction, send2->hash ()).value ().number ());
|
|
ASSERT_FALSE (ledger.any.block_amount (transaction, send2->hash ()));
|
|
ASSERT_FALSE (ledger.any.block_account (transaction, send1->hash ()));
|
|
ASSERT_EQ (nano::dev::genesis_key.pub, ledger.any.block_account (transaction, send2->hash ()).value ());
|
|
}
|
|
|
|
TEST (ledger, random_blocks)
|
|
{
|
|
nano::logger logger;
|
|
auto store = nano::make_store (logger, nano::unique_path (), nano::dev::constants);
|
|
ASSERT_TRUE (!store->init_error ());
|
|
nano::stats stats{ logger };
|
|
nano::ledger ledger (*store, nano::dev::constants, stats, logger);
|
|
ledger.pruning = true;
|
|
auto transaction = ledger.tx_begin_write ();
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
nano::block_builder builder;
|
|
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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.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));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
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 - nano::Knano_ratio * 2)
|
|
.link (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (send1->hash ()))
|
|
.build ();
|
|
ASSERT_EQ (nano::block_status::progress, ledger.process (transaction, send2));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
ledger.confirm (transaction, send1->hash ());
|
|
// Pruning action
|
|
ASSERT_EQ (1, ledger.pruning_action (transaction, send1->hash (), 1));
|
|
ASSERT_FALSE (ledger.any.block_exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (store->pruned.exists (transaction, send1->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, nano::dev::genesis->hash ()));
|
|
ASSERT_TRUE (ledger.any.block_exists (transaction, send2->hash ()));
|
|
// Prunned block will not be included in the random selection because it's not in the blocks set
|
|
{
|
|
bool done = false;
|
|
size_t iteration = 0;
|
|
while (!done && iteration < 42)
|
|
{
|
|
++iteration;
|
|
auto blocks = ledger.random_blocks (transaction, 10);
|
|
ASSERT_EQ (blocks.size (), 10); // Random blocks should repeat if the ledger is smaller than the requested count
|
|
auto first = blocks.front ();
|
|
done = (first->hash () == send1->hash ());
|
|
}
|
|
ASSERT_FALSE (done);
|
|
}
|
|
// Genesis and send2 should be included in the random selection
|
|
{
|
|
bool done = false;
|
|
size_t iteration = 0;
|
|
while (!done)
|
|
{
|
|
++iteration;
|
|
auto blocks = ledger.random_blocks (transaction, 1);
|
|
ASSERT_EQ (blocks.size (), 1);
|
|
auto first = blocks.front ();
|
|
done = (first->hash () == send2->hash ());
|
|
ASSERT_LE (iteration, 1000);
|
|
}
|
|
}
|
|
{
|
|
bool done = false;
|
|
size_t iteration = 0;
|
|
while (!done)
|
|
{
|
|
++iteration;
|
|
auto blocks = ledger.random_blocks (transaction, 1);
|
|
ASSERT_EQ (blocks.size (), 1);
|
|
auto first = blocks.front ();
|
|
done = (first->hash () == nano::dev::genesis->hash ());
|
|
ASSERT_LE (iteration, 1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST (ledger, migrate_lmdb_to_rocksdb)
|
|
{
|
|
nano::test::system system{};
|
|
auto path = nano::unique_path ();
|
|
nano::logger logger;
|
|
boost::asio::ip::address_v6 address (boost::asio::ip::make_address_v6 ("::ffff:127.0.0.1"));
|
|
uint16_t port = 100;
|
|
nano::store::lmdb::component store{ logger, path / "data.ldb", nano::dev::constants };
|
|
nano::ledger ledger{ store, nano::dev::constants, system.stats, system.logger };
|
|
nano::work_pool pool{ nano::dev::network_params.network, std::numeric_limits<unsigned>::max () };
|
|
|
|
std::shared_ptr<nano::block> send = nano::state_block_builder ()
|
|
.account (nano::dev::genesis_key.pub)
|
|
.previous (nano::dev::genesis->hash ())
|
|
.representative (0)
|
|
.link (nano::account (10))
|
|
.balance (nano::dev::constants.genesis_amount - 100)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*pool.generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
|
|
nano::endpoint_key endpoint_key (address.to_bytes (), port);
|
|
auto version = nano::store::component::version_current;
|
|
|
|
{
|
|
auto transaction = ledger.tx_begin_write ();
|
|
ASSERT_FALSE (store.init_error ());
|
|
|
|
// Lower the database to the max version unsupported for upgrades
|
|
store.confirmation_height.put (transaction, nano::dev::genesis_key.pub, { 2, send->hash () });
|
|
|
|
store.online_weight.put (transaction, 100, nano::amount (2));
|
|
store.peer.put (transaction, endpoint_key, 37);
|
|
|
|
store.pending.put (transaction, nano::pending_key (nano::dev::genesis_key.pub, send->hash ()), nano::pending_info (nano::dev::genesis_key.pub, 100, nano::epoch::epoch_0));
|
|
store.pruned.put (transaction, send->hash ());
|
|
store.version.put (transaction, version);
|
|
send->sideband_set ({});
|
|
store.block.put (transaction, send->hash (), *send);
|
|
store.final_vote.put (transaction, send->qualified_root (), nano::block_hash (2));
|
|
}
|
|
|
|
auto error = ledger.migrate_lmdb_to_rocksdb (path);
|
|
ASSERT_FALSE (error);
|
|
|
|
nano::store::rocksdb::component rocksdb_store{ logger, path / "rocksdb", nano::dev::constants };
|
|
auto rocksdb_transaction (rocksdb_store.tx_begin_read ());
|
|
|
|
ASSERT_TRUE (rocksdb_store.pending.get (rocksdb_transaction, nano::pending_key (nano::dev::genesis_key.pub, send->hash ())));
|
|
|
|
for (auto i = rocksdb_store.online_weight.begin (rocksdb_transaction); i != rocksdb_store.online_weight.end (rocksdb_transaction); ++i)
|
|
{
|
|
ASSERT_EQ (i->first, 100);
|
|
ASSERT_EQ (i->second, 2);
|
|
}
|
|
|
|
ASSERT_EQ (rocksdb_store.online_weight.count (rocksdb_transaction), 1);
|
|
|
|
auto block1 = rocksdb_store.block.get (rocksdb_transaction, send->hash ());
|
|
|
|
ASSERT_EQ (*send, *block1);
|
|
ASSERT_TRUE (rocksdb_store.peer.exists (rocksdb_transaction, endpoint_key));
|
|
ASSERT_EQ (rocksdb_store.version.get (rocksdb_transaction), version);
|
|
nano::confirmation_height_info confirmation_height_info;
|
|
ASSERT_FALSE (rocksdb_store.confirmation_height.get (rocksdb_transaction, nano::dev::genesis_key.pub, confirmation_height_info));
|
|
ASSERT_EQ (confirmation_height_info.height, 2);
|
|
ASSERT_EQ (confirmation_height_info.frontier, send->hash ());
|
|
ASSERT_TRUE (rocksdb_store.final_vote.get (rocksdb_transaction, send->qualified_root ()).has_value ());
|
|
ASSERT_EQ (rocksdb_store.final_vote.get (rocksdb_transaction, send->qualified_root ()).value (), nano::block_hash (2));
|
|
|
|
// Retry migration while rocksdb folder is still present
|
|
auto error_on_retry = ledger.migrate_lmdb_to_rocksdb (path);
|
|
ASSERT_EQ (error_on_retry, true);
|
|
}
|
|
|
|
TEST (ledger, is_send_genesis)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto tx = store.tx_begin_read ();
|
|
ASSERT_FALSE (nano::dev::genesis->is_send ());
|
|
}
|
|
|
|
TEST (ledger, is_send_state)
|
|
{
|
|
auto ctx = nano::test::ledger_send_receive ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto tx = store.tx_begin_read ();
|
|
ASSERT_TRUE (ctx.blocks ()[0]->is_send ());
|
|
ASSERT_FALSE (ctx.blocks ()[1]->is_send ());
|
|
}
|
|
|
|
TEST (ledger, is_send_legacy)
|
|
{
|
|
auto ctx = nano::test::ledger_send_receive_legacy ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto tx = store.tx_begin_read ();
|
|
ASSERT_TRUE (ctx.blocks ()[0]->is_send ());
|
|
ASSERT_FALSE (ctx.blocks ()[1]->is_send ());
|
|
}
|
|
|
|
TEST (ledger, head_block)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto & store = ctx.store ();
|
|
auto tx = ledger.tx_begin_read ();
|
|
ASSERT_EQ (*nano::dev::genesis, *ledger.any.block_get (tx, ledger.any.account_head (tx, nano::dev::genesis_key.pub)));
|
|
}
|
|
|
|
// Tests that a fairly complex ledger topology can be cemented in a single batch
|
|
TEST (ledger, cement_unbounded)
|
|
{
|
|
auto ctx = nano::test::ledger_diamond (5);
|
|
auto & ledger = ctx.ledger ();
|
|
auto bottom = ctx.blocks ().back ();
|
|
|
|
std::deque<std::shared_ptr<nano::block>> confirmed;
|
|
{
|
|
auto tx = ledger.tx_begin_write ();
|
|
confirmed = ledger.confirm (tx, bottom->hash ());
|
|
}
|
|
ASSERT_TRUE (ledger.confirmed.block_exists (ledger.tx_begin_read (), bottom->hash ()));
|
|
// Check that all blocks got confirmed in a single call
|
|
ASSERT_TRUE (std::all_of (ctx.blocks ().begin (), ctx.blocks ().end (), [&] (auto const & block) {
|
|
return std::find_if (confirmed.begin (), confirmed.end (), [&] (auto const & block2) {
|
|
return block2->hash () == block->hash ();
|
|
})
|
|
!= confirmed.end ();
|
|
}));
|
|
}
|
|
|
|
// Tests that bounded cementing works when recursion stack is large
|
|
TEST (ledger, cement_bounded)
|
|
{
|
|
auto ctx = nano::test::ledger_single_chain (64);
|
|
auto & ledger = ctx.ledger ();
|
|
auto bottom = ctx.blocks ().back ();
|
|
|
|
std::deque<std::shared_ptr<nano::block>> confirmed1, confirmed2, confirmed3;
|
|
|
|
{
|
|
// This should only cement some of the dependencies
|
|
auto tx = ledger.tx_begin_write ();
|
|
confirmed1 = ledger.confirm (tx, bottom->hash (), /* max cementing batch size */ 3);
|
|
}
|
|
ASSERT_FALSE (ledger.confirmed.block_exists (ledger.tx_begin_read (), bottom->hash ()));
|
|
ASSERT_EQ (confirmed1.size (), 3);
|
|
// Only topmost dependencies should get cemented during this call
|
|
ASSERT_TRUE (std::all_of (confirmed1.begin (), confirmed1.end (), [&] (auto const & block) {
|
|
return ledger.dependents_confirmed (ledger.tx_begin_read (), *block);
|
|
}));
|
|
|
|
{
|
|
// This should cement a few more dependencies
|
|
auto tx = ledger.tx_begin_write ();
|
|
confirmed2 = ledger.confirm (tx, bottom->hash (), /* max cementing batch size */ 16);
|
|
}
|
|
ASSERT_FALSE (ledger.confirmed.block_exists (ledger.tx_begin_read (), bottom->hash ()));
|
|
ASSERT_EQ (confirmed2.size (), 16);
|
|
// Only topmost dependencies should get cemented during this call
|
|
ASSERT_TRUE (std::all_of (confirmed2.begin (), confirmed2.end (), [&] (auto const & block) {
|
|
return ledger.dependents_confirmed (ledger.tx_begin_read (), *block);
|
|
}));
|
|
|
|
{
|
|
// This should cement the remaining dependencies
|
|
auto tx = ledger.tx_begin_write ();
|
|
confirmed3 = ledger.confirm (tx, bottom->hash (), /* max cementing batch size */ 64);
|
|
}
|
|
ASSERT_TRUE (ledger.confirmed.block_exists (ledger.tx_begin_read (), bottom->hash ()));
|
|
ASSERT_LE (confirmed3.size (), 64);
|
|
// Every block in the ledger should be cemented
|
|
ASSERT_TRUE (std::all_of (ctx.blocks ().begin (), ctx.blocks ().end (), [&] (auto const & block) {
|
|
return ledger.confirmed.block_exists (ledger.tx_begin_read (), block->hash ());
|
|
}));
|
|
}
|
|
|
|
// Tests that bounded cementing works when number of blocks is large but tree height is small (recursion stack is small)
|
|
TEST (ledger, cement_bounded_diamond)
|
|
{
|
|
auto ctx = nano::test::ledger_diamond (4);
|
|
auto & ledger = ctx.ledger ();
|
|
auto bottom = ctx.blocks ().back ();
|
|
|
|
std::deque<std::shared_ptr<nano::block>> confirmed1, confirmed2, confirmed3, confirmed4;
|
|
|
|
{
|
|
// This should only cement some of the dependencies
|
|
auto tx = ledger.tx_begin_write ();
|
|
confirmed1 = ledger.confirm (tx, bottom->hash (), /* max cementing batch size */ 3);
|
|
}
|
|
ASSERT_FALSE (ledger.confirmed.block_exists (ledger.tx_begin_read (), bottom->hash ()));
|
|
ASSERT_EQ (confirmed1.size (), 3);
|
|
// Only topmost dependencies should get cemented during this call
|
|
ASSERT_TRUE (std::all_of (confirmed1.begin (), confirmed1.end (), [&] (auto const & block) {
|
|
return ledger.dependents_confirmed (ledger.tx_begin_read (), *block);
|
|
}));
|
|
|
|
{
|
|
// This should cement a few more dependencies
|
|
auto tx = ledger.tx_begin_write ();
|
|
confirmed2 = ledger.confirm (tx, bottom->hash (), /* max cementing batch size */ 16);
|
|
}
|
|
ASSERT_FALSE (ledger.confirmed.block_exists (ledger.tx_begin_read (), bottom->hash ()));
|
|
ASSERT_EQ (confirmed2.size (), 16);
|
|
// Only topmost dependencies should get cemented during this call
|
|
ASSERT_TRUE (std::all_of (confirmed2.begin (), confirmed2.end (), [&] (auto const & block) {
|
|
return ledger.dependents_confirmed (ledger.tx_begin_read (), *block);
|
|
}));
|
|
|
|
{
|
|
// A few more bounded calls should confirm the whole tree
|
|
auto tx = ledger.tx_begin_write ();
|
|
confirmed3 = ledger.confirm (tx, bottom->hash (), /* max cementing batch size */ 64);
|
|
}
|
|
ASSERT_FALSE (ledger.confirmed.block_exists (ledger.tx_begin_read (), bottom->hash ()));
|
|
ASSERT_EQ (confirmed3.size (), 64);
|
|
// Only topmost dependencies should get cemented during this call
|
|
ASSERT_TRUE (std::all_of (confirmed2.begin (), confirmed2.end (), [&] (auto const & block) {
|
|
return ledger.dependents_confirmed (ledger.tx_begin_read (), *block);
|
|
}));
|
|
|
|
{
|
|
auto tx = ledger.tx_begin_write ();
|
|
confirmed4 = ledger.confirm (tx, bottom->hash (), /* max cementing batch size */ 64);
|
|
}
|
|
ASSERT_TRUE (ledger.confirmed.block_exists (ledger.tx_begin_read (), bottom->hash ()));
|
|
ASSERT_LT (confirmed4.size (), 64);
|
|
// Every block in the ledger should be cemented
|
|
ASSERT_TRUE (std::all_of (ctx.blocks ().begin (), ctx.blocks ().end (), [&] (auto const & block) {
|
|
return ledger.confirmed.block_exists (ledger.tx_begin_read (), block->hash ());
|
|
}));
|
|
}
|
|
|
|
// Test that nullopt can be returned when there are no receivable entries
|
|
TEST (ledger_receivable, upper_bound_account_none)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
ASSERT_EQ (ctx.ledger ().any.receivable_end (), ctx.ledger ().any.receivable_upper_bound (ctx.ledger ().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::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::Knano_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.ledger ().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::Knano_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.ledger ().tx_begin_write (), send2));
|
|
auto tx = ctx.ledger ().tx_begin_read ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto next1 = ledger.any.receivable_upper_bound (tx, nano::dev::genesis_key.pub);
|
|
auto next2 = ledger.any.receivable_upper_bound (tx, key.pub);
|
|
// Depending on which is greater but only one should have a value
|
|
ASSERT_TRUE (next1 == ledger.any.receivable_end () xor next2 == ledger.any.receivable_end ());
|
|
// The account returned should be after the one we searched for
|
|
ASSERT_TRUE (next1 == ledger.any.receivable_end () || next1->first.account == key.pub);
|
|
ASSERT_TRUE (next2 == ledger.any.receivable_end () || next2->first.account == nano::dev::genesis_key.pub);
|
|
auto next3 = ledger.any.receivable_upper_bound (tx, nano::dev::genesis_key.pub, 0);
|
|
auto next4 = ledger.any.receivable_upper_bound (tx, key.pub, 0);
|
|
// Neither account has more than one receivable
|
|
ASSERT_TRUE (next3 != ledger.any.receivable_end () && next4 != ledger.any.receivable_end ());
|
|
auto next5 = ledger.any.receivable_upper_bound (tx, next3->first.account, next3->first.hash);
|
|
auto next6 = ledger.any.receivable_upper_bound (tx, next4->first.account, next4->first.hash);
|
|
ASSERT_TRUE (next5 == ledger.any.receivable_end () && next6 == ledger.any.receivable_end ());
|
|
ASSERT_EQ (ledger.any.receivable_end (), ++next3);
|
|
ASSERT_EQ (ledger.any.receivable_end (), ++next4);
|
|
}
|
|
|
|
// Test that multiple receivable entries for the same account
|
|
TEST (ledger_receivable, key_two)
|
|
{
|
|
auto ctx = nano::test::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::Knano_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.ledger ().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::Knano_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.ledger ().tx_begin_write (), send2));
|
|
auto tx = ctx.ledger ().tx_begin_read ();
|
|
auto & ledger = ctx.ledger ();
|
|
auto next1 = ledger.any.receivable_upper_bound (tx, key.pub, 0);
|
|
ASSERT_TRUE (next1 != ledger.any.receivable_end () && next1->first.account == key.pub);
|
|
auto next2 = ledger.any.receivable_upper_bound (tx, key.pub, next1->first.hash);
|
|
ASSERT_TRUE (next2 != ledger.any.receivable_end () && next2->first.account == key.pub);
|
|
ASSERT_NE (next1->first.hash, next2->first.hash);
|
|
ASSERT_EQ (next2, ++next1);
|
|
ASSERT_EQ (ledger.any.receivable_end (), ++next1);
|
|
ASSERT_EQ (ledger.any.receivable_end (), ++next2);
|
|
}
|
|
|
|
TEST (ledger_receivable, any_none)
|
|
{
|
|
auto ctx = nano::test::ledger_empty ();
|
|
ASSERT_FALSE (ctx.ledger ().any.receivable_exists (ctx.ledger ().tx_begin_read (), nano::dev::genesis_key.pub));
|
|
}
|
|
|
|
TEST (ledger_receivable, any_one)
|
|
{
|
|
auto ctx = nano::test::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::Knano_ratio)
|
|
.link (nano::dev::genesis_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.ledger ().tx_begin_write (), send1));
|
|
ASSERT_TRUE (ctx.ledger ().any.receivable_exists (ctx.ledger ().tx_begin_read (), nano::dev::genesis_key.pub));
|
|
ASSERT_FALSE (ctx.ledger ().any.receivable_exists (ctx.ledger ().tx_begin_read (), key.pub));
|
|
}
|
|
|
|
TEST (ledger_transaction, write_refresh)
|
|
{
|
|
auto ctx = nano::test::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::Knano_ratio)
|
|
.link (nano::dev::genesis_key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*ctx.pool ().generate (nano::dev::genesis->hash ()))
|
|
.build ();
|
|
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::Knano_ratio)
|
|
.link (key.pub)
|
|
.sign (nano::dev::genesis_key.prv, nano::dev::genesis_key.pub)
|
|
.work (*ctx.pool ().generate (send1->hash ()))
|
|
.build ();
|
|
|
|
auto transaction = ctx.ledger ().tx_begin_write ();
|
|
ASSERT_EQ (nano::block_status::progress, ctx.ledger ().process (transaction, send1));
|
|
// Force refresh
|
|
ASSERT_TRUE (transaction.refresh_if_needed (0ms));
|
|
ASSERT_FALSE (transaction.refresh_if_needed ()); // Should not refresh again too soon
|
|
// Refreshed transaction should work just fine
|
|
ASSERT_EQ (nano::block_status::progress, ctx.ledger ().process (transaction, send2));
|
|
}
|
|
|
|
TEST (ledger_transaction, write_wait_order)
|
|
{
|
|
nano::test::system system;
|
|
|
|
auto ctx = nano::test::ledger_empty ();
|
|
|
|
std::atomic<bool> acquired1{ false };
|
|
std::atomic<bool> acquired2{ false };
|
|
std::atomic<bool> acquired3{ false };
|
|
|
|
std::latch latch1{ 1 };
|
|
std::latch latch2{ 1 };
|
|
std::latch latch3{ 1 };
|
|
|
|
auto fut1 = std::async (std::launch::async, [&] {
|
|
auto tx = ctx.ledger ().tx_begin_write (nano::store::writer::generic);
|
|
acquired1 = true;
|
|
latch1.wait (); // Wait for the signal to drop tx
|
|
});
|
|
WAIT (250ms); // Allow thread to start
|
|
|
|
auto fut2 = std::async (std::launch::async, [&ctx, &acquired2, &latch2] {
|
|
auto tx = ctx.ledger ().tx_begin_write (nano::store::writer::block_processor);
|
|
acquired2 = true;
|
|
latch2.wait (); // Wait for the signal to drop tx
|
|
});
|
|
WAIT (250ms); // Allow thread to start
|
|
|
|
auto fut3 = std::async (std::launch::async, [&ctx, &acquired3, &latch3] {
|
|
auto tx = ctx.ledger ().tx_begin_write (nano::store::writer::confirmation_height);
|
|
acquired3 = true;
|
|
latch3.wait (); // Wait for the signal to drop tx
|
|
});
|
|
WAIT (250ms); // Allow thread to start
|
|
|
|
// First transaction should be ready immediately, others should be waiting
|
|
ASSERT_TIMELY (5s, acquired1.load ());
|
|
ASSERT_NEVER (250ms, acquired2.load ());
|
|
ASSERT_NEVER (250ms, acquired3.load ());
|
|
|
|
// Signal to continue and drop the first transaction
|
|
latch1.count_down ();
|
|
ASSERT_TIMELY (5s, acquired2.load ());
|
|
ASSERT_NEVER (250ms, acquired3.load ());
|
|
|
|
// Signal to continue and drop the second transaction
|
|
latch2.count_down ();
|
|
ASSERT_TIMELY (5s, acquired3.load ());
|
|
|
|
// Signal to continue and drop the third transaction
|
|
latch3.count_down ();
|
|
}
|
|
|
|
TEST (ledger_transaction, multithreaded_interleaving)
|
|
{
|
|
nano::test::system system;
|
|
|
|
auto ctx = nano::test::ledger_empty ();
|
|
|
|
int constexpr num_threads = 2;
|
|
int constexpr num_iterations = 10;
|
|
int constexpr num_blocks = 10;
|
|
|
|
std::deque<std::thread> threads;
|
|
for (int i = 0; i < num_threads; ++i)
|
|
{
|
|
threads.emplace_back ([&] {
|
|
for (int n = 0; n < num_iterations; ++n)
|
|
{
|
|
auto tx = ctx.ledger ().tx_begin_write (nano::store::writer::testing);
|
|
for (unsigned k = 0; k < num_blocks; ++k)
|
|
{
|
|
ctx.store ().account.put (tx, nano::account{ k }, nano::account_info{});
|
|
}
|
|
for (unsigned k = 0; k < num_blocks; ++k)
|
|
{
|
|
ctx.store ().account.del (tx, nano::account{ k });
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
for (auto & thread : threads)
|
|
{
|
|
thread.join ();
|
|
}
|
|
} |