Add epoch blocks to disable old type blocks (#955)

* Add version field to account_info and min_version to pending_info

* Add epoch block support to ledger

* Add epoch block settings to config, and remove state canaries

* Add test for epoch blocks

* Add receive upgrade test for epoch blocks

* Ignore old nodes on the beta network

* Add min_version to RPC pending and wallet_pending

* Add account_version field to account_info RPC

* Fix formatting

* Remove epoch block config (de)serializing

* Mark epoch blocks in history (#968)

* Mark epoch blocks in history

* Extra info for raw

* Remove epoch block from non-raw RPC history

* Move raw check
This commit is contained in:
Lee Bousfield 2018-07-13 16:51:49 -06:00 committed by GitHub
commit 2608433c7b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 444 additions and 132 deletions

View file

@ -347,6 +347,8 @@ void rai::block_store::do_upgrades (MDB_txn * transaction_a)
case 10:
upgrade_v10_to_v11 (transaction_a);
case 11:
upgrade_v11_to_v12 (transaction_a);
case 12:
break;
default:
assert (false);
@ -412,7 +414,7 @@ void rai::block_store::upgrade_v3_to_v4 (MDB_txn * transaction_a)
{
rai::block_hash hash (i->first.uint256 ());
rai::pending_info_v3 info (i->second);
items.push (std::make_pair (rai::pending_key (info.destination, hash), rai::pending_info (info.source, info.amount)));
items.push (std::make_pair (rai::pending_key (info.destination, hash), rai::pending_info (info.source, info.amount, 0)));
}
mdb_drop (transaction_a, pending, 0);
while (!items.empty ())
@ -461,7 +463,7 @@ void rai::block_store::upgrade_v5_to_v6 (MDB_txn * transaction_a)
assert (block != nullptr);
hash = block->previous ();
}
rai::account_info info (info_old.head, info_old.rep_block, info_old.open_block, info_old.balance, info_old.modified, block_count);
rai::account_info info (info_old.head, info_old.rep_block, info_old.open_block, info_old.balance, info_old.modified, block_count, 0);
headers.push_back (std::make_pair (account, info));
}
for (auto i (headers.begin ()), n (headers.end ()); i != n; ++i)
@ -549,6 +551,32 @@ void rai::block_store::upgrade_v10_to_v11 (MDB_txn * transaction_a)
mdb_drop (transaction_a, unsynced, 1);
}
void rai::block_store::upgrade_v11_to_v12 (MDB_txn * transaction_a)
{
version_put (transaction_a, 12);
for (rai::store_iterator i (transaction_a, accounts), n (nullptr); i != n; ++i)
{
assert (i->second.size () + 1 == sizeof (account_info));
std::vector<uint8_t> bytes ((uint8_t *)i->second.data (), (uint8_t *)i->second.data () + i->second.size ());
bytes.push_back (0); // version field
mdb_cursor_put (i.cursor, i->first, rai::mdb_val (bytes.size (), bytes.data ()), MDB_CURRENT);
}
for (rai::store_iterator i (transaction_a, pending), n (nullptr); i != n; ++i)
{
assert (i->second.size () + 1 == sizeof (pending_info));
std::vector<uint8_t> bytes ((uint8_t *)i->second.data (), (uint8_t *)i->second.data () + i->second.size ());
bytes.push_back (0); // min_version field
mdb_cursor_put (i.cursor, i->first, rai::mdb_val (bytes.size (), bytes.data ()), MDB_CURRENT);
}
for (rai::store_iterator i (transaction_a, state_blocks), n (nullptr); i != n; ++i)
{
assert (i->second.size () == rai::state_block::size + sizeof (rai::block_hash));
std::vector<uint8_t> bytes ((uint8_t *)i->second.data (), (uint8_t *)i->second.data () + i->second.size ());
bytes.insert (bytes.begin () + rai::state_block::size, 0); // version field
mdb_cursor_put (i.cursor, i->first, rai::mdb_val (bytes.size (), bytes.data ()), MDB_CURRENT);
}
}
void rai::block_store::clear (MDB_dbi db_a)
{
rai::transaction transaction (environment, nullptr, true);
@ -563,6 +591,21 @@ rai::uint128_t rai::block_store::block_balance (MDB_txn * transaction_a, rai::bl
return visitor.balance;
}
uint8_t rai::block_store::block_version (MDB_txn * transaction_a, rai::block_hash const & hash_a)
{
rai::block_type type;
rai::mdb_val value;
auto status (mdb_get (transaction_a, state_blocks, rai::mdb_val (hash_a), value));
assert (status == 0 || status == MDB_NOTFOUND);
uint8_t result (0);
if (status == 0)
{
assert (value.size () > rai::state_block::size);
result = *(reinterpret_cast<uint8_t const *> (value.data ()) + rai::state_block::size);
}
return result;
}
void rai::block_store::representation_add (MDB_txn * transaction_a, rai::block_hash const & source_a, rai::uint128_t const & amount_a)
{
auto source_block (block_get (transaction_a, source_a));
@ -605,13 +648,21 @@ void rai::block_store::block_put_raw (MDB_txn * transaction_a, MDB_dbi database_
assert (status2 == 0);
}
void rai::block_store::block_put (MDB_txn * transaction_a, rai::block_hash const & hash_a, rai::block const & block_a, rai::block_hash const & successor_a)
void rai::block_store::block_put (MDB_txn * transaction_a, rai::block_hash const & hash_a, rai::block const & block_a, rai::block_hash const & successor_a, uint8_t version_a)
{
assert (successor_a.is_zero () || block_exists (transaction_a, successor_a));
if (block_a.type () != rai::block_type::state)
{
assert (version_a == 0);
}
std::vector<uint8_t> vector;
{
rai::vectorstream stream (vector);
block_a.serialize (stream);
if (block_a.type () == rai::block_type::state)
{
rai::write (stream, version_a);
}
rai::write (stream, successor_a.bytes);
}
block_put_raw (transaction_a, block_database (block_a.type ()), hash_a, { vector.size (), vector.data () });
@ -747,7 +798,8 @@ rai::block_hash rai::block_store::block_successor (MDB_txn * transaction_a, rai:
void rai::block_store::block_successor_clear (MDB_txn * transaction_a, rai::block_hash const & hash_a)
{
auto block (block_get (transaction_a, hash_a));
block_put (transaction_a, hash_a, *block);
auto version (block_version (transaction_a, hash_a));
block_put (transaction_a, hash_a, *block, version);
}
std::unique_ptr<rai::block> rai::block_store::block_get (MDB_txn * transaction_a, rai::block_hash const & hash_a)
@ -957,12 +1009,14 @@ bool rai::block_store::pending_get (MDB_txn * transaction_a, rai::pending_key co
else
{
result = false;
assert (value.size () == sizeof (pending_a.source.bytes) + sizeof (pending_a.amount.bytes));
assert (value.size () == sizeof (pending_a.source.bytes) + sizeof (pending_a.amount.bytes) + sizeof (pending_a.min_version));
rai::bufferstream stream (reinterpret_cast<uint8_t const *> (value.data ()), value.size ());
auto error1 (rai::read (stream, pending_a.source));
assert (!error1);
auto error2 (rai::read (stream, pending_a.amount));
assert (!error2);
auto error3 (rai::read (stream, pending_a.min_version));
assert (!error3);
}
return result;
}

View file

@ -38,7 +38,7 @@ public:
MDB_dbi block_database (rai::block_type);
void block_put_raw (MDB_txn *, MDB_dbi, rai::block_hash const &, MDB_val);
void block_put (MDB_txn *, rai::block_hash const &, rai::block const &, rai::block_hash const & = rai::block_hash (0));
void block_put (MDB_txn *, rai::block_hash const &, rai::block const &, rai::block_hash const & = rai::block_hash (0), uint8_t version = 0);
MDB_val block_get_raw (MDB_txn *, rai::block_hash const &, rai::block_type &);
rai::block_hash block_successor (MDB_txn *, rai::block_hash const &);
void block_successor_clear (MDB_txn *, rai::block_hash const &);
@ -79,6 +79,7 @@ public:
rai::store_iterator block_info_begin (MDB_txn *);
rai::store_iterator block_info_end ();
rai::uint128_t block_balance (MDB_txn *, rai::block_hash const &);
uint8_t block_version (MDB_txn *, rai::block_hash const &);
static size_t const block_info_max = 32;
rai::uint128_t representation_get (MDB_txn *, rai::account const &);
@ -128,6 +129,7 @@ public:
void upgrade_v8_to_v9 (MDB_txn *);
void upgrade_v9_to_v10 (MDB_txn *);
void upgrade_v10_to_v11 (MDB_txn *);
void upgrade_v11_to_v12 (MDB_txn *);
// Requires a write transaction
rai::raw_key get_node_id (MDB_txn *);

View file

@ -195,24 +195,26 @@ rep_block (0),
open_block (0),
balance (0),
modified (0),
block_count (0)
block_count (0),
version (0)
{
}
rai::account_info::account_info (MDB_val const & val_a)
{
assert (val_a.mv_size == sizeof (*this));
static_assert (sizeof (head) + sizeof (rep_block) + sizeof (open_block) + sizeof (balance) + sizeof (modified) + sizeof (block_count) == sizeof (*this), "Class not packed");
static_assert (sizeof (head) + sizeof (rep_block) + sizeof (open_block) + sizeof (balance) + sizeof (modified) + sizeof (block_count) + sizeof (version) == sizeof (*this), "Class not packed");
std::copy (reinterpret_cast<uint8_t const *> (val_a.mv_data), reinterpret_cast<uint8_t const *> (val_a.mv_data) + sizeof (*this), reinterpret_cast<uint8_t *> (this));
}
rai::account_info::account_info (rai::block_hash const & head_a, rai::block_hash const & rep_block_a, rai::block_hash const & open_block_a, rai::amount const & balance_a, uint64_t modified_a, uint64_t block_count_a) :
rai::account_info::account_info (rai::block_hash const & head_a, rai::block_hash const & rep_block_a, rai::block_hash const & open_block_a, rai::amount const & balance_a, uint64_t modified_a, uint64_t block_count_a, uint8_t version_a) :
head (head_a),
rep_block (rep_block_a),
open_block (open_block_a),
balance (balance_a),
modified (modified_a),
block_count (block_count_a)
block_count (block_count_a),
version (version_a)
{
}
@ -224,6 +226,7 @@ void rai::account_info::serialize (rai::stream & stream_a) const
write (stream_a, balance.bytes);
write (stream_a, modified);
write (stream_a, block_count);
write (stream_a, version);
}
bool rai::account_info::deserialize (rai::stream & stream_a)
@ -244,6 +247,10 @@ bool rai::account_info::deserialize (rai::stream & stream_a)
if (!error)
{
error = read (stream_a, block_count);
if (!error)
{
error = read (stream_a, version);
}
}
}
}
@ -254,7 +261,7 @@ bool rai::account_info::deserialize (rai::stream & stream_a)
bool rai::account_info::operator== (rai::account_info const & other_a) const
{
return head == other_a.head && rep_block == other_a.rep_block && open_block == other_a.open_block && balance == other_a.balance && modified == other_a.modified && block_count == other_a.block_count;
return head == other_a.head && rep_block == other_a.rep_block && open_block == other_a.open_block && balance == other_a.balance && modified == other_a.modified && block_count == other_a.block_count && version == other_a.version;
}
bool rai::account_info::operator!= (rai::account_info const & other_a) const
@ -283,20 +290,22 @@ size_t rai::block_counts::sum ()
rai::pending_info::pending_info () :
source (0),
amount (0)
amount (0),
min_version (0)
{
}
rai::pending_info::pending_info (MDB_val const & val_a)
{
assert (val_a.mv_size == sizeof (*this));
static_assert (sizeof (source) + sizeof (amount) == sizeof (*this), "Packed class");
static_assert (sizeof (source) + sizeof (amount) + sizeof (min_version) == sizeof (*this), "Packed class");
std::copy (reinterpret_cast<uint8_t const *> (val_a.mv_data), reinterpret_cast<uint8_t const *> (val_a.mv_data) + sizeof (*this), reinterpret_cast<uint8_t *> (this));
}
rai::pending_info::pending_info (rai::account const & source_a, rai::amount const & amount_a) :
rai::pending_info::pending_info (rai::account const & source_a, rai::amount const & amount_a, uint8_t min_version_a) :
source (source_a),
amount (amount_a)
amount (amount_a),
min_version (min_version_a)
{
}
@ -304,6 +313,7 @@ void rai::pending_info::serialize (rai::stream & stream_a) const
{
rai::write (stream_a, source.bytes);
rai::write (stream_a, amount.bytes);
rai::write (stream_a, min_version);
}
bool rai::pending_info::deserialize (rai::stream & stream_a)
@ -312,13 +322,17 @@ bool rai::pending_info::deserialize (rai::stream & stream_a)
if (!result)
{
result = rai::read (stream_a, amount.bytes);
if (!result)
{
result = rai::read (stream_a, min_version);
}
}
return result;
}
bool rai::pending_info::operator== (rai::pending_info const & other_a) const
{
return source == other_a.source && amount == other_a.amount;
return source == other_a.source && amount == other_a.amount && min_version == other_a.min_version;
}
rai::mdb_val rai::pending_info::val () const
@ -780,7 +794,7 @@ void rai::genesis::initialize (MDB_txn * transaction_a, rai::block_store & store
auto hash_l (hash ());
assert (store_a.latest_begin (transaction_a) == store_a.latest_end ());
store_a.block_put (transaction_a, hash_l, *open);
store_a.account_put (transaction_a, genesis_account, { hash_l, open->hash (), open->hash (), std::numeric_limits<rai::uint128_t>::max (), rai::seconds_since_epoch (), 1 });
store_a.account_put (transaction_a, genesis_account, { hash_l, open->hash (), open->hash (), std::numeric_limits<rai::uint128_t>::max (), rai::seconds_since_epoch (), 1, 0 });
store_a.representation_put (transaction_a, genesis_account, std::numeric_limits<rai::uint128_t>::max ());
store_a.checksum_put (transaction_a, 0, 0, hash_l);
store_a.frontier_put (transaction_a, hash_l, genesis_account);

View file

@ -110,13 +110,14 @@ std::unique_ptr<rai::block> deserialize_block (MDB_val const &);
/**
* Latest information about an account
*/
#pragma pack(push, 1)
class account_info
{
public:
account_info ();
account_info (MDB_val const &);
account_info (rai::account_info const &) = default;
account_info (rai::block_hash const &, rai::block_hash const &, rai::block_hash const &, rai::amount const &, uint64_t, uint64_t);
account_info (rai::block_hash const &, rai::block_hash const &, rai::block_hash const &, rai::amount const &, uint64_t, uint64_t, uint8_t);
void serialize (rai::stream &) const;
bool deserialize (rai::stream &);
bool operator== (rai::account_info const &) const;
@ -129,24 +130,29 @@ public:
/** Seconds since posix epoch */
uint64_t modified;
uint64_t block_count;
uint8_t version;
};
#pragma pack(pop)
/**
* Information on an uncollected send
*/
#pragma pack(push, 1)
class pending_info
{
public:
pending_info ();
pending_info (MDB_val const &);
pending_info (rai::account const &, rai::amount const &);
pending_info (rai::account const &, rai::amount const &, uint8_t);
void serialize (rai::stream &) const;
bool deserialize (rai::stream &);
bool operator== (rai::pending_info const &) const;
rai::mdb_val val () const;
rai::account source;
rai::amount amount;
uint8_t min_version;
};
#pragma pack(pop)
class pending_key
{
public:
@ -222,11 +228,12 @@ enum class process_result
old, // Already seen and was valid
negative_spend, // Malicious attempt to spend a negative amount
fork, // Malicious fork based on previous
unreceivable, // Source block doesn't exist or has already been received
unreceivable, // Source block doesn't exist, has already been received, or requires an account upgrade (epoch blocks)
gap_previous, // Block marked as previous is unknown
gap_source, // Block marked as source is unknown
opened_burn_account, // The impossible happened, someone found the private key associated with the public key '0'.
balance_mismatch, // Balance and amount delta don't match
representative_mismatch, // Representative is changed when it is not allowed
block_position // This block cannot follow the previous block
};
class process_return

View file

@ -128,7 +128,7 @@ TEST (block_store, pending_iterator)
ASSERT_TRUE (!init);
rai::transaction transaction (store.environment, nullptr, true);
ASSERT_EQ (store.pending_end (), store.pending_begin (transaction));
store.pending_put (transaction, rai::pending_key (1, 2), { 2, 3 });
store.pending_put (transaction, rai::pending_key (1, 2), { 2, 3, 4 });
auto current (store.pending_begin (transaction));
ASSERT_NE (store.pending_end (), current);
rai::pending_key key1 (current->first);
@ -137,6 +137,7 @@ TEST (block_store, pending_iterator)
rai::pending_info pending (current->second);
ASSERT_EQ (rai::account (2), pending.source);
ASSERT_EQ (rai::amount (3), pending.amount);
ASSERT_EQ (4, pending.min_version);
}
TEST (block_store, genesis)
@ -313,7 +314,7 @@ TEST (block_store, frontier_retrieval)
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::account account1 (0);
rai::account_info info1 (0, 0, 0, 0, 0, 0);
rai::account_info info1 (0, 0, 0, 0, 0, 0, 0);
rai::transaction transaction (store.environment, nullptr, true);
store.account_put (transaction, account1, info1);
rai::account_info info2;
@ -329,7 +330,7 @@ TEST (block_store, one_account)
rai::account account (0);
rai::block_hash hash (0);
rai::transaction transaction (store.environment, nullptr, true);
store.account_put (transaction, account, { hash, account, hash, 42, 100, 200 });
store.account_put (transaction, account, { hash, account, hash, 42, 100, 200, 0 });
auto begin (store.latest_begin (transaction));
auto end (store.latest_end ());
ASSERT_NE (end, begin);
@ -374,8 +375,8 @@ TEST (block_store, two_account)
rai::account account2 (3);
rai::block_hash hash2 (4);
rai::transaction transaction (store.environment, nullptr, true);
store.account_put (transaction, account1, { hash1, account1, hash1, 42, 100, 300 });
store.account_put (transaction, account2, { hash2, account2, hash2, 84, 200, 400 });
store.account_put (transaction, account1, { hash1, account1, hash1, 42, 100, 300, 0 });
store.account_put (transaction, account2, { hash2, account2, hash2, 84, 200, 400, 0 });
auto begin (store.latest_begin (transaction));
auto end (store.latest_end ());
ASSERT_NE (end, begin);
@ -407,8 +408,8 @@ TEST (block_store, latest_find)
rai::account account2 (3);
rai::block_hash hash2 (4);
rai::transaction transaction (store.environment, nullptr, true);
store.account_put (transaction, account1, { hash1, account1, hash1, 100, 0, 300 });
store.account_put (transaction, account2, { hash2, account2, hash2, 200, 0, 400 });
store.account_put (transaction, account1, { hash1, account1, hash1, 100, 0, 300, 0 });
store.account_put (transaction, account2, { hash2, account2, hash2, 200, 0, 400, 0 });
auto first (store.latest_begin (transaction));
auto second (store.latest_begin (transaction));
++second;

View file

@ -2265,3 +2265,89 @@ TEST (ledger, state_receive_change_rollback)
ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account));
ASSERT_EQ (0, ledger.weight (transaction, rep.pub));
}
TEST (ledger, epoch_blocks_general)
{
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::stat stats;
rai::keypair epoch_key;
rai::ledger ledger (store, stats, 123, epoch_key.pub);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
rai::keypair destination;
rai::state_block epoch1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount, 123, epoch_key.prv, epoch_key.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, epoch1).code);
rai::state_block epoch2 (rai::genesis_account, epoch1.hash (), rai::genesis_account, rai::genesis_amount, 123, epoch_key.prv, epoch_key.pub, 0);
ASSERT_EQ (rai::process_result::block_position, ledger.process (transaction, epoch2).code);
rai::account_info genesis_info;
ASSERT_FALSE (ledger.store.account_get (transaction, rai::genesis_account, genesis_info));
ASSERT_EQ (genesis_info.version, 1);
ledger.rollback (transaction, epoch1.hash ());
ASSERT_FALSE (ledger.store.account_get (transaction, rai::genesis_account, genesis_info));
ASSERT_EQ (genesis_info.version, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, epoch1).code);
ASSERT_FALSE (ledger.store.account_get (transaction, rai::genesis_account, genesis_info));
ASSERT_EQ (genesis_info.version, 1);
rai::change_block change1 (epoch1.hash (), rai::genesis_account, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
ASSERT_EQ (rai::process_result::block_position, ledger.process (transaction, change1).code);
rai::state_block send1 (rai::genesis_account, epoch1.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code);
rai::open_block open1 (send1.hash (), rai::genesis_account, destination.pub, destination.prv, destination.pub, 0);
ASSERT_EQ (rai::process_result::unreceivable, ledger.process (transaction, open1).code);
rai::state_block epoch3 (destination.pub, 0, rai::genesis_account, 0, 123, epoch_key.prv, epoch_key.pub, 0);
ASSERT_EQ (rai::process_result::representative_mismatch, ledger.process (transaction, epoch3).code);
rai::state_block epoch4 (destination.pub, 0, 0, 0, 123, epoch_key.prv, epoch_key.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, epoch4).code);
rai::receive_block receive1 (epoch4.hash (), send1.hash (), destination.prv, destination.pub, 0);
ASSERT_EQ (rai::process_result::block_position, ledger.process (transaction, receive1).code);
rai::state_block receive2 (destination.pub, epoch4.hash (), destination.pub, rai::Gxrb_ratio, send1.hash (), destination.prv, destination.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive2).code);
ASSERT_EQ (0, ledger.balance (transaction, epoch4.hash ()));
ASSERT_EQ (rai::Gxrb_ratio, ledger.balance (transaction, receive2.hash ()));
ASSERT_EQ (rai::Gxrb_ratio, ledger.amount (transaction, receive2.hash ()));
ASSERT_EQ (rai::genesis_amount - rai::Gxrb_ratio, ledger.weight (transaction, rai::genesis_account));
ASSERT_EQ (rai::Gxrb_ratio, ledger.weight (transaction, destination.pub));
}
TEST (ledger, epoch_blocks_receive_upgrade)
{
bool init (false);
rai::block_store store (init, rai::unique_path ());
ASSERT_TRUE (!init);
rai::stat stats;
rai::keypair epoch_key;
rai::ledger ledger (store, stats, 123, epoch_key.pub);
rai::genesis genesis;
rai::transaction transaction (store.environment, nullptr, true);
genesis.initialize (transaction, store);
rai::keypair destination;
rai::state_block send1 (rai::genesis_account, genesis.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send1).code);
rai::state_block epoch1 (rai::genesis_account, send1.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio, 123, epoch_key.prv, epoch_key.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, epoch1).code);
rai::state_block send2 (rai::genesis_account, epoch1.hash (), rai::genesis_account, rai::genesis_amount - rai::Gxrb_ratio * 2, destination.pub, rai::test_genesis_key.prv, rai::test_genesis_key.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send2).code);
rai::open_block open1 (send1.hash (), destination.pub, destination.pub, destination.prv, destination.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, open1).code);
rai::receive_block receive1 (open1.hash (), send2.hash (), destination.prv, destination.pub, 0);
ASSERT_EQ (rai::process_result::unreceivable, ledger.process (transaction, receive1).code);
rai::state_block receive2 (destination.pub, open1.hash (), destination.pub, rai::Gxrb_ratio * 2, send2.hash (), destination.prv, destination.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive2).code);
rai::account_info destination_info;
ASSERT_FALSE (ledger.store.account_get (transaction, destination.pub, destination_info));
ASSERT_EQ (destination_info.version, 1);
ledger.rollback (transaction, receive2.hash ());
ASSERT_FALSE (ledger.store.account_get (transaction, destination.pub, destination_info));
ASSERT_EQ (destination_info.version, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, receive2).code);
ASSERT_FALSE (ledger.store.account_get (transaction, destination.pub, destination_info));
ASSERT_EQ (destination_info.version, 1);
rai::keypair destination2;
rai::state_block send3 (destination.pub, receive2.hash (), destination.pub, rai::Gxrb_ratio, destination2.pub, destination.prv, destination.pub, 0);
ASSERT_EQ (rai::process_result::progress, ledger.process (transaction, send3).code);
rai::open_block open2 (send3.hash (), destination2.pub, destination2.pub, destination2.prv, destination2.pub, 0);
ASSERT_EQ (rai::process_result::unreceivable, ledger.process (transaction, open2).code);
}

View file

@ -513,14 +513,12 @@ TEST (node_config, serialization)
config1.receive_minimum = 10;
config1.online_weight_minimum = 10;
config1.online_weight_quorum = 10;
config1.password_fanout = 10;
config1.password_fanout = 20;
config1.enable_voting = false;
config1.callback_address = "test";
config1.callback_port = 10;
config1.callback_target = "test";
config1.lmdb_max_dbs = 256;
config1.state_block_parse_canary = 10;
config1.state_block_generate_canary = 10;
boost::property_tree::ptree tree;
config1.serialize_json (tree);
rai::logging logging2;
@ -538,11 +536,12 @@ TEST (node_config, serialization)
ASSERT_NE (config2.callback_port, config1.callback_port);
ASSERT_NE (config2.callback_target, config1.callback_target);
ASSERT_NE (config2.lmdb_max_dbs, config1.lmdb_max_dbs);
ASSERT_NE (config2.state_block_parse_canary, config1.state_block_parse_canary);
ASSERT_NE (config2.state_block_generate_canary, config1.state_block_generate_canary);
ASSERT_FALSE (tree.get_optional<std::string> ("epoch_block_link"));
ASSERT_FALSE (tree.get_optional<std::string> ("epoch_block_signer"));
bool upgraded (false);
config2.deserialize_json (upgraded, tree);
ASSERT_FALSE (config2.deserialize_json (upgraded, tree));
ASSERT_FALSE (upgraded);
ASSERT_EQ (config2.bootstrap_fraction_numerator, config1.bootstrap_fraction_numerator);
ASSERT_EQ (config2.peering_port, config1.peering_port);
@ -555,8 +554,6 @@ TEST (node_config, serialization)
ASSERT_EQ (config2.callback_port, config1.callback_port);
ASSERT_EQ (config2.callback_target, config1.callback_target);
ASSERT_EQ (config2.lmdb_max_dbs, config1.lmdb_max_dbs);
ASSERT_EQ (config2.state_block_parse_canary, config1.state_block_parse_canary);
ASSERT_EQ (config2.state_block_generate_canary, config1.state_block_generate_canary);
}
TEST (node_config, v1_v2_upgrade)

View file

@ -819,7 +819,7 @@ TEST (rpc, frontier)
{
rai::keypair key;
source[key.pub] = key.prv.data;
system.nodes[0]->store.account_put (transaction, key.pub, rai::account_info (key.prv.data, 0, 0, 0, 0, 0));
system.nodes[0]->store.account_put (transaction, key.pub, rai::account_info (key.prv.data, 0, 0, 0, 0, 0, 0));
}
}
rai::keypair key;
@ -859,7 +859,7 @@ TEST (rpc, frontier_limited)
{
rai::keypair key;
source[key.pub] = key.prv.data;
system.nodes[0]->store.account_put (transaction, key.pub, rai::account_info (key.prv.data, 0, 0, 0, 0, 0));
system.nodes[0]->store.account_put (transaction, key.pub, rai::account_info (key.prv.data, 0, 0, 0, 0, 0, 0));
}
}
rai::keypair key;
@ -889,7 +889,7 @@ TEST (rpc, frontier_startpoint)
{
rai::keypair key;
source[key.pub] = key.prv.data;
system.nodes[0]->store.account_put (transaction, key.pub, rai::account_info (key.prv.data, 0, 0, 0, 0, 0));
system.nodes[0]->store.account_put (transaction, key.pub, rai::account_info (key.prv.data, 0, 0, 0, 0, 0, 0));
}
}
rai::keypair key;
@ -1419,6 +1419,8 @@ TEST (rpc, pending)
blocks[hash] = amount;
boost::optional<std::string> source (i->second.get_optional<std::string> ("source"));
ASSERT_FALSE (source.is_initialized ());
boost::optional<uint8_t> min_version (i->second.get_optional<uint8_t> ("min_version"));
ASSERT_FALSE (min_version.is_initialized ());
}
ASSERT_EQ (blocks[block1->hash ()], 100);
request.put ("threshold", "101");
@ -1432,6 +1434,7 @@ TEST (rpc, pending)
ASSERT_EQ (0, blocks_node.size ());
request.put ("threshold", "0");
request.put ("source", "true");
request.put ("min_version", "true");
test_response response2 (request, rpc, system.service);
while (response2.status == 0)
{
@ -1448,6 +1451,7 @@ TEST (rpc, pending)
hash.decode_hex (i->first);
amounts[hash].decode_dec (i->second.get<std::string> ("amount"));
sources[hash].decode_account (i->second.get<std::string> ("source"));
ASSERT_EQ (i->second.get<uint8_t> ("min_version"), 0);
}
ASSERT_EQ (amounts[block1->hash ()], 100);
ASSERT_EQ (sources[block1->hash ()], rai::test_genesis_key.pub);
@ -2574,6 +2578,8 @@ TEST (rpc, wallet_pending)
blocks[hash] = amount;
boost::optional<std::string> source (i->second.get_optional<std::string> ("source"));
ASSERT_FALSE (source.is_initialized ());
boost::optional<uint8_t> min_version (i->second.get_optional<uint8_t> ("min_version"));
ASSERT_FALSE (min_version.is_initialized ());
}
}
ASSERT_EQ (blocks[block1->hash ()], 100);
@ -2588,6 +2594,7 @@ TEST (rpc, wallet_pending)
ASSERT_EQ (0, pending1.size ());
request.put ("threshold", "0");
request.put ("source", "true");
request.put ("min_version", "true");
test_response response2 (request, rpc, system0.service);
while (response2.status == 0)
{
@ -2606,6 +2613,7 @@ TEST (rpc, wallet_pending)
hash.decode_hex (i->first);
amounts[hash].decode_dec (i->second.get<std::string> ("amount"));
sources[hash].decode_account (i->second.get<std::string> ("source"));
ASSERT_EQ (i->second.get<uint8_t> ("min_version"), 0);
}
}
ASSERT_EQ (amounts[block1->hash ()], 100);
@ -2889,6 +2897,7 @@ TEST (rpc, account_info)
ASSERT_LT (std::abs ((long)time - stol (modified_timestamp)), 5);
std::string block_count (response.json.get<std::string> ("block_count"));
ASSERT_EQ ("2", block_count);
ASSERT_EQ (0, response.json.get<uint8_t> ("account_version"));
boost::optional<std::string> weight (response.json.get_optional<std::string> ("weight"));
ASSERT_FALSE (weight.is_initialized ());
boost::optional<std::string> pending (response.json.get_optional<std::string> ("pending"));

View file

@ -55,7 +55,7 @@ public:
ledger.store.representation_add (transaction, ledger.representative (transaction, hash), 0 - amount);
ledger.change_latest (transaction, destination_account, block_a.hashables.previous, representative, ledger.balance (transaction, block_a.hashables.previous), info.block_count - 1);
ledger.store.block_del (transaction, hash);
ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), { source_account, amount });
ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), { source_account, amount, 0 });
ledger.store.frontier_del (transaction, hash);
ledger.store.frontier_put (transaction, block_a.hashables.previous, destination_account);
ledger.store.block_successor_clear (transaction, block_a.hashables.previous);
@ -74,7 +74,7 @@ public:
ledger.store.representation_add (transaction, ledger.representative (transaction, hash), 0 - amount);
ledger.change_latest (transaction, destination_account, 0, 0, 0, 0);
ledger.store.block_del (transaction, hash);
ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), { source_account, amount });
ledger.store.pending_put (transaction, rai::pending_key (destination_account, block_a.hashables.source), { source_account, amount, 0 });
ledger.store.frontier_del (transaction, hash);
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::open);
}
@ -118,6 +118,9 @@ public:
ledger.store.representation_add (transaction, representative, balance);
}
rai::account_info info;
auto error (ledger.store.account_get (transaction, block_a.hashables.account, info));
if (is_send)
{
rai::pending_key key (block_a.hashables.link, hash);
@ -128,17 +131,17 @@ public:
ledger.store.pending_del (transaction, key);
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::send);
}
else if (!block_a.hashables.link.is_zero ())
else if (!block_a.hashables.link.is_zero () && block_a.hashables.link != ledger.epoch_link)
{
rai::pending_info info (ledger.account (transaction, block_a.hashables.link), block_a.hashables.balance.number () - balance);
ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link), info);
auto source_version (ledger.store.block_version (transaction, block_a.hashables.link));
rai::pending_info pending_info (ledger.account (transaction, block_a.hashables.link), block_a.hashables.balance.number () - balance, source_version);
ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link), pending_info);
ledger.stats.inc (rai::stat::type::rollback, rai::stat::detail::receive);
}
rai::account_info info;
auto error (ledger.store.account_get (transaction, block_a.hashables.account, info));
assert (!error);
ledger.change_latest (transaction, block_a.hashables.account, block_a.hashables.previous, representative, balance, info.block_count - 1);
auto previous_version (ledger.store.block_version (transaction, block_a.hashables.previous));
ledger.change_latest (transaction, block_a.hashables.account, block_a.hashables.previous, representative, balance, info.block_count - 1, false, previous_version);
auto previous (ledger.store.block_get (transaction, block_a.hashables.previous));
if (previous != nullptr)
@ -170,6 +173,7 @@ public:
void change_block (rai::change_block const &) override;
void state_block (rai::state_block const &) override;
void state_block_impl (rai::state_block const &);
void epoch_block_impl (rai::state_block const &);
rai::ledger & ledger;
MDB_txn * transaction;
rai::process_return result;
@ -177,7 +181,17 @@ public:
void ledger_processor::state_block (rai::state_block const & block_a)
{
state_block_impl (block_a);
// Check if this is an epoch block
rai::account_info info;
ledger.store.account_get (transaction, block_a.hashables.account, info);
if (block_a.hashables.balance == info.balance && !ledger.epoch_link.is_zero () && block_a.hashables.link == ledger.epoch_link)
{
epoch_block_impl (block_a);
}
else
{
state_block_impl (block_a);
}
}
void ledger_processor::state_block_impl (rai::state_block const & block_a)
@ -193,12 +207,14 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a)
result.code = block_a.hashables.account.is_zero () ? rai::process_result::opened_burn_account : rai::process_result::progress; // Is this for the burn account? (Unambiguous)
if (result.code == rai::process_result::progress)
{
uint8_t account_version (0);
rai::account_info info;
result.amount = block_a.hashables.balance;
auto is_send (false);
auto account_error (ledger.store.account_get (transaction, block_a.hashables.account, info));
if (!account_error)
{
account_version = info.version;
// Account already exists
result.code = block_a.hashables.previous.is_zero () ? rai::process_result::fork : rai::process_result::progress; // Has this account already been opened? (Ambigious)
if (result.code == rai::process_result::progress)
@ -236,6 +252,7 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a)
if (result.code == rai::process_result::progress)
{
result.code = result.amount == pending.amount ? rai::process_result::progress : rai::process_result::balance_mismatch;
account_version = std::max (account_version, pending.min_version);
}
}
}
@ -250,7 +267,7 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a)
{
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::state_block);
result.state_is_send = is_send;
ledger.store.block_put (transaction, hash, block_a);
ledger.store.block_put (transaction, hash, block_a, 0, account_version);
if (!info.rep_block.is_zero ())
{
@ -263,7 +280,7 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a)
if (is_send)
{
rai::pending_key key (block_a.hashables.link, hash);
rai::pending_info info (block_a.hashables.account, result.amount.number ());
rai::pending_info info (block_a.hashables.account, result.amount.number (), account_version);
ledger.store.pending_put (transaction, key, info);
}
else if (!block_a.hashables.link.is_zero ())
@ -271,7 +288,7 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a)
ledger.store.pending_del (transaction, rai::pending_key (block_a.hashables.account, block_a.hashables.link));
}
ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1, true);
ledger.change_latest (transaction, block_a.hashables.account, hash, hash, block_a.hashables.balance, info.block_count + 1, true, account_version);
if (!ledger.store.frontier_get (transaction, info.head).is_zero ())
{
ledger.store.frontier_del (transaction, info.head);
@ -284,6 +301,69 @@ void ledger_processor::state_block_impl (rai::state_block const & block_a)
}
}
void ledger_processor::epoch_block_impl (rai::state_block const & block_a)
{
auto hash (block_a.hash ());
auto existing (ledger.store.block_exists (transaction, hash));
result.code = existing ? rai::process_result::old : rai::process_result::progress; // Have we seen this block before? (Unambiguous)
if (result.code == rai::process_result::progress)
{
result.code = validate_message (ledger.epoch_signer, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Unambiguous)
if (result.code == rai::process_result::progress)
{
result.code = block_a.hashables.account.is_zero () ? rai::process_result::opened_burn_account : rai::process_result::progress; // Is this for the burn account? (Unambiguous)
if (result.code == rai::process_result::progress)
{
rai::account_info info;
auto account_error (ledger.store.account_get (transaction, block_a.hashables.account, info));
if (!account_error)
{
// Account already exists
result.code = block_a.hashables.previous.is_zero () ? rai::process_result::fork : rai::process_result::progress; // Has this account already been opened? (Ambigious)
if (result.code == rai::process_result::progress)
{
result.code = ledger.store.block_exists (transaction, block_a.hashables.previous) ? rai::process_result::progress : rai::process_result::gap_previous; // Does the previous block exist in the ledger? (Unambigious)
if (result.code == rai::process_result::progress)
{
result.code = block_a.hashables.previous == info.head ? rai::process_result::progress : rai::process_result::fork; // Is the previous block the account's head block? (Ambigious)
if (result.code == rai::process_result::progress)
{
auto last_rep_block (ledger.store.block_get (transaction, info.rep_block));
assert (last_rep_block != nullptr);
result.code = block_a.hashables.representative == last_rep_block->representative () ? rai::process_result::progress : rai::process_result::representative_mismatch;
}
}
}
}
else
{
result.code = block_a.hashables.representative.is_zero () ? rai::process_result::progress : rai::process_result::representative_mismatch;
}
if (result.code == rai::process_result::progress)
{
result.code = info.version == 0 ? rai::process_result::progress : rai::process_result::block_position;
if (result.code == rai::process_result::progress)
{
result.code = block_a.hashables.balance == info.balance ? rai::process_result::progress : rai::process_result::balance_mismatch;
if (result.code == rai::process_result::progress)
{
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::epoch_block);
result.account = block_a.hashables.account;
result.amount = 0;
ledger.store.block_put (transaction, hash, block_a, 0, 1);
ledger.change_latest (transaction, block_a.hashables.account, hash, hash, info.balance, info.block_count + 1, true, 1);
if (!ledger.store.frontier_get (transaction, info.head).is_zero ())
{
ledger.store.frontier_del (transaction, info.head);
}
}
}
}
}
}
}
}
void ledger_processor::change_block (rai::change_block const & block_a)
{
auto hash (block_a.hash ());
@ -358,7 +438,7 @@ void ledger_processor::send_block (rai::send_block const & block_a)
ledger.store.representation_add (transaction, info.rep_block, 0 - amount);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, account, hash, info.rep_block, block_a.hashables.balance, info.block_count + 1);
ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.destination, hash), { account, amount });
ledger.store.pending_put (transaction, rai::pending_key (block_a.hashables.destination, hash), { account, amount, 0 });
ledger.store.frontier_del (transaction, block_a.hashables.previous);
ledger.store.frontier_put (transaction, hash, account);
result.account = account;
@ -407,19 +487,23 @@ void ledger_processor::receive_block (rai::receive_block const & block_a)
result.code = ledger.store.pending_get (transaction, key, pending) ? rai::process_result::unreceivable : rai::process_result::progress; // Has this source already been received (Malformed)
if (result.code == rai::process_result::progress)
{
auto new_balance (info.balance.number () + pending.amount.number ());
rai::account_info source_info;
auto error (ledger.store.account_get (transaction, pending.source, source_info));
assert (!error);
ledger.store.pending_del (transaction, key);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, account, hash, info.rep_block, new_balance, info.block_count + 1);
ledger.store.representation_add (transaction, info.rep_block, pending.amount.number ());
ledger.store.frontier_del (transaction, block_a.hashables.previous);
ledger.store.frontier_put (transaction, hash, account);
result.account = account;
result.amount = pending.amount;
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::receive);
result.code = pending.min_version == 0 ? rai::process_result::progress : rai::process_result::unreceivable; // Are we receiving a state-only send? (Malformed)
if (result.code == rai::process_result::progress)
{
auto new_balance (info.balance.number () + pending.amount.number ());
rai::account_info source_info;
auto error (ledger.store.account_get (transaction, pending.source, source_info));
assert (!error);
ledger.store.pending_del (transaction, key);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, account, hash, info.rep_block, new_balance, info.block_count + 1);
ledger.store.representation_add (transaction, info.rep_block, pending.amount.number ());
ledger.store.frontier_del (transaction, block_a.hashables.previous);
ledger.store.frontier_put (transaction, hash, account);
result.account = account;
result.amount = pending.amount;
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::receive);
}
}
}
}
@ -460,17 +544,21 @@ void ledger_processor::open_block (rai::open_block const & block_a)
result.code = block_a.hashables.account == rai::burn_account ? rai::process_result::opened_burn_account : rai::process_result::progress; // Is it burning 0 account? (Malicious)
if (result.code == rai::process_result::progress)
{
rai::account_info source_info;
auto error (ledger.store.account_get (transaction, pending.source, source_info));
assert (!error);
ledger.store.pending_del (transaction, key);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, block_a.hashables.account, hash, hash, pending.amount.number (), info.block_count + 1);
ledger.store.representation_add (transaction, hash, pending.amount.number ());
ledger.store.frontier_put (transaction, hash, block_a.hashables.account);
result.account = block_a.hashables.account;
result.amount = pending.amount;
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::open);
result.code = pending.min_version == 0 ? rai::process_result::progress : rai::process_result::unreceivable; // Are we receiving a state-only send? (Malformed)
if (result.code == rai::process_result::progress)
{
rai::account_info source_info;
auto error (ledger.store.account_get (transaction, pending.source, source_info));
assert (!error);
ledger.store.pending_del (transaction, key);
ledger.store.block_put (transaction, hash, block_a);
ledger.change_latest (transaction, block_a.hashables.account, hash, hash, pending.amount.number (), info.block_count + 1);
ledger.store.representation_add (transaction, hash, pending.amount.number ());
ledger.store.frontier_put (transaction, hash, block_a.hashables.account);
result.account = block_a.hashables.account;
result.amount = pending.amount;
ledger.stats.inc (rai::stat::type::ledger, rai::stat::detail::open);
}
}
}
}
@ -498,10 +586,12 @@ bool rai::shared_ptr_block_hash::operator() (std::shared_ptr<rai::block> const &
return lhs->hash () == rhs->hash ();
}
rai::ledger::ledger (rai::block_store & store_a, rai::stat & stat_a) :
rai::ledger::ledger (rai::block_store & store_a, rai::stat & stat_a, rai::uint256_union const & epoch_link_a, rai::account const & epoch_signer_a) :
store (store_a),
stats (stat_a),
check_bootstrap_weights (true)
check_bootstrap_weights (true),
epoch_link (epoch_link_a),
epoch_signer (epoch_signer_a)
{
}
@ -794,7 +884,7 @@ void rai::ledger::checksum_update (MDB_txn * transaction_a, rai::block_hash cons
store.checksum_put (transaction_a, 0, 0, value);
}
void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & account_a, rai::block_hash const & hash_a, rai::block_hash const & rep_block_a, rai::amount const & balance_a, uint64_t block_count_a, bool is_state)
void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & account_a, rai::block_hash const & hash_a, rai::block_hash const & rep_block_a, rai::amount const & balance_a, uint64_t block_count_a, bool is_state, uint8_t version_a)
{
rai::account_info info;
auto exists (!store.account_get (transaction_a, account_a, info));
@ -814,6 +904,7 @@ void rai::ledger::change_latest (MDB_txn * transaction_a, rai::account const & a
info.balance = balance_a;
info.modified = rai::seconds_since_epoch ();
info.block_count = block_count_a;
info.version = version_a;
store.account_put (transaction_a, account_a, info);
if (!(block_count_a % store.block_info_max) && !is_state)
{

View file

@ -17,7 +17,7 @@ using tally_t = std::map<rai::uint128_t, std::shared_ptr<rai::block>, std::great
class ledger
{
public:
ledger (rai::block_store &, rai::stat &);
ledger (rai::block_store &, rai::stat &, rai::uint256_union const & = 1, rai::account const & = 0);
std::pair<rai::uint128_t, std::shared_ptr<rai::block>> winner (MDB_txn *, rai::votes const & votes_a);
// Map of weight -> associated block, ordered greatest to least
rai::tally_t tally (MDB_txn *, rai::votes const &);
@ -41,7 +41,7 @@ public:
rai::block_hash block_source (MDB_txn *, rai::block const &);
rai::process_return process (MDB_txn *, rai::block const &);
void rollback (MDB_txn *, rai::block_hash const &);
void change_latest (MDB_txn *, rai::account const &, rai::block_hash const &, rai::account const &, rai::uint128_union const &, uint64_t, bool = false);
void change_latest (MDB_txn *, rai::account const &, rai::block_hash const &, rai::account const &, rai::uint128_union const &, uint64_t, bool = false, uint8_t = 0);
void checksum_update (MDB_txn *, rai::block_hash const &);
rai::checksum checksum (MDB_txn *, rai::account const &, rai::account const &);
void dump_account_chain (rai::account const &);
@ -51,5 +51,7 @@ public:
std::unordered_map<rai::account, rai::uint128_t> bootstrap_weights;
uint64_t bootstrap_weight_max_blocks;
std::atomic<bool> check_bootstrap_weights;
rai::uint256_union epoch_link;
rai::account epoch_signer;
};
};

View file

@ -1984,7 +1984,7 @@ void rai::bulk_push_server::received_block (boost::system::error_code const & ec
rai::frontier_req_server::frontier_req_server (std::shared_ptr<rai::bootstrap_server> const & connection_a, std::unique_ptr<rai::frontier_req> request_a) :
connection (connection_a),
current (request_a->start.number () - 1),
info (0, 0, 0, 0, 0, 0),
info (0, 0, 0, 0, 0, 0, 0),
request (std::move (request_a)),
send_buffer (std::make_shared<std::vector<uint8_t>> ())
{

View file

@ -99,37 +99,44 @@ void rai::message_parser::deserialize_buffer (uint8_t const * buffer_a, size_t s
rai::message_header header (error, stream);
if (!error)
{
switch (header.type)
if (rai::rai_network == rai::rai_networks::rai_beta_network && header.version_using < rai::protocol_version)
{
case rai::message_type::keepalive:
status = parse_status::outdated_version;
}
else
{
switch (header.type)
{
deserialize_keepalive (stream, header);
break;
}
case rai::message_type::publish:
{
deserialize_publish (stream, header);
break;
}
case rai::message_type::confirm_req:
{
deserialize_confirm_req (stream, header);
break;
}
case rai::message_type::confirm_ack:
{
deserialize_confirm_ack (stream, header);
break;
}
case rai::message_type::node_id_handshake:
{
deserialize_node_id_handshake (stream, header);
break;
}
default:
{
status = parse_status::invalid_message_type;
break;
case rai::message_type::keepalive:
{
deserialize_keepalive (stream, header);
break;
}
case rai::message_type::publish:
{
deserialize_publish (stream, header);
break;
}
case rai::message_type::confirm_req:
{
deserialize_confirm_req (stream, header);
break;
}
case rai::message_type::confirm_ack:
{
deserialize_confirm_ack (stream, header);
break;
}
case rai::message_type::node_id_handshake:
{
deserialize_node_id_handshake (stream, header);
break;
}
default:
{
status = parse_status::invalid_message_type;
break;
}
}
}
}

View file

@ -190,7 +190,8 @@ public:
invalid_publish_message,
invalid_confirm_req_message,
invalid_confirm_ack_message,
invalid_node_id_handshake_message
invalid_node_id_handshake_message,
outdated_version
};
message_parser (rai::message_visitor &, rai::work_pool &);
void deserialize_buffer (uint8_t const *, size_t);

View file

@ -899,6 +899,9 @@ bootstrap_connections_max (64),
callback_port (0),
lmdb_max_dbs (128)
{
const char * epoch_message ("epoch v1 block");
strncpy ((char *)epoch_block_link.bytes.data (), epoch_message, epoch_block_link.bytes.size ());
epoch_block_signer = rai::genesis_account;
switch (rai::rai_network)
{
case rai::rai_networks::rai_test_network:
@ -911,8 +914,6 @@ lmdb_max_dbs (128)
preconfigured_representatives.push_back (rai::account ("259A40656144FAA16D2A8516F7BE9C74A63C6CA399960EDB747D144ABB0F7ABD"));
preconfigured_representatives.push_back (rai::account ("259A40A92FA42E2240805DE8618EC4627F0BA41937160B4CFF7F5335FD1933DF"));
preconfigured_representatives.push_back (rai::account ("259A40FF3262E273EC451E873C4CDF8513330425B38860D882A16BCC74DA9B73"));
state_block_parse_canary = rai::block_hash ("5005F5283DE8D2DAB0DAC41DE9BD23640F962B4F0EA7D3128C2EA3D78D578E27");
state_block_generate_canary = rai::block_hash ("FC18E2265FB835E8CF60E63531053A768CEDF5194263B01A5C95574944E4660D");
break;
case rai::rai_networks::rai_live_network:
preconfigured_peers.push_back ("rai.raiblocks.net");
@ -924,8 +925,6 @@ lmdb_max_dbs (128)
preconfigured_representatives.push_back (rai::account ("2399A083C600AA0572F5E36247D978FCFC840405F8D4B6D33161C0066A55F431"));
preconfigured_representatives.push_back (rai::account ("2298FAB7C61058E77EA554CB93EDEEDA0692CBFCC540AB213B2836B29029E23A"));
preconfigured_representatives.push_back (rai::account ("3FE80B4BC842E82C1C18ABFEEC47EA989E63953BC82AC411F304D13833D52A56"));
state_block_parse_canary = rai::block_hash ("89F1C0AC4C5AD23964AB880571E3EA67FDC41BD11AB20E67F0A29CF94CD4E24A");
state_block_generate_canary = rai::block_hash ("B6DC4D64801BEC7D81DAA086A5733D251E8CBA0E9226FD6173D97C0569EC2998");
break;
default:
assert (false);
@ -935,7 +934,7 @@ lmdb_max_dbs (128)
void rai::node_config::serialize_json (boost::property_tree::ptree & tree_a) const
{
tree_a.put ("version", "12");
tree_a.put ("version", "13");
tree_a.put ("peering_port", std::to_string (peering_port));
tree_a.put ("bootstrap_fraction_numerator", std::to_string (bootstrap_fraction_numerator));
tree_a.put ("receive_minimum", receive_minimum.to_string_dec ());
@ -978,8 +977,6 @@ void rai::node_config::serialize_json (boost::property_tree::ptree & tree_a) con
tree_a.put ("callback_port", std::to_string (callback_port));
tree_a.put ("callback_target", callback_target);
tree_a.put ("lmdb_max_dbs", lmdb_max_dbs);
tree_a.put ("state_block_parse_canary", state_block_parse_canary.to_string ());
tree_a.put ("state_block_generate_canary", state_block_generate_canary.to_string ());
}
bool rai::node_config::upgrade_json (unsigned version, boost::property_tree::ptree & tree_a)
@ -1054,8 +1051,8 @@ bool rai::node_config::upgrade_json (unsigned version, boost::property_tree::ptr
tree_a.put ("version", "9");
result = true;
case 9:
tree_a.put ("state_block_parse_canary", state_block_parse_canary.to_string ());
tree_a.put ("state_block_generate_canary", state_block_generate_canary.to_string ());
tree_a.put ("state_block_parse_canary", rai::block_hash (0).to_string ());
tree_a.put ("state_block_generate_canary", rai::block_hash (0).to_string ());
tree_a.erase ("version");
tree_a.put ("version", "10");
result = true;
@ -1076,6 +1073,12 @@ bool rai::node_config::upgrade_json (unsigned version, boost::property_tree::ptr
result = true;
}
case 12:
tree_a.erase ("state_block_parse_canary");
tree_a.erase ("state_block_generate_canary");
tree_a.erase ("version");
tree_a.put ("version", "13");
result = true;
case 13:
break;
default:
throw std::runtime_error ("Unknown node_config version");
@ -1161,8 +1164,6 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree
callback_target = tree_a.get<std::string> ("callback_target");
auto lmdb_max_dbs_l = tree_a.get<std::string> ("lmdb_max_dbs");
result |= parse_port (callback_port_l, callback_port);
auto state_block_parse_canary_l = tree_a.get<std::string> ("state_block_parse_canary");
auto state_block_generate_canary_l = tree_a.get<std::string> ("state_block_generate_canary");
try
{
peering_port = std::stoul (peering_port_l);
@ -1182,8 +1183,6 @@ bool rai::node_config::deserialize_json (bool & upgraded_a, boost::property_tree
result |= password_fanout < 16;
result |= password_fanout > 1024 * 1024;
result |= io_threads == 0;
result |= state_block_parse_canary.decode_hex (state_block_parse_canary_l);
result |= state_block_generate_canary.decode_hex (state_block_generate_canary_l);
}
catch (std::logic_error const &)
{
@ -1532,6 +1531,14 @@ rai::process_return rai::block_processor::process_receive_one (MDB_txn * transac
}
break;
}
case rai::process_result::representative_mismatch:
{
if (node.config.logging.ledger_logging ())
{
BOOST_LOG (node.log) << boost::str (boost::format ("Representative mismatch for: %1%") % hash.to_string ());
}
break;
}
case rai::process_result::block_position:
{
if (node.config.logging.ledger_logging ())
@ -1568,7 +1575,7 @@ alarm (alarm_a),
work (work_a),
store (init_a.block_store_init, application_path_a / "data.ldb", config_a.lmdb_max_dbs),
gap_cache (*this),
ledger (store, stats),
ledger (store, stats, config.epoch_block_link, config.epoch_block_signer),
active (*this),
network (*this, config.peering_port),
bootstrap_initiator (*this),

View file

@ -483,8 +483,8 @@ public:
std::string callback_target;
int lmdb_max_dbs;
rai::stat_config stat_config;
rai::block_hash state_block_parse_canary;
rai::block_hash state_block_generate_canary;
rai::uint256_union epoch_block_link;
rai::account epoch_block_signer;
static std::chrono::seconds constexpr keepalive_period = std::chrono::seconds (60);
static std::chrono::seconds constexpr keepalive_cutoff = keepalive_period * 5;
static std::chrono::minutes constexpr wallet_backup_interval = std::chrono::minutes (5);

View file

@ -352,6 +352,7 @@ void rai::rpc_handler::account_info ()
response_l.put ("balance", balance);
response_l.put ("modified_timestamp", std::to_string (info.modified));
response_l.put ("block_count", std::to_string (info.block_count));
response_l.put ("account_version", std::to_string (info.version));
if (representative)
{
auto block (node.store.block_get (transaction, info.rep_block));
@ -1795,6 +1796,14 @@ public:
tree.put ("subtype", "change");
}
}
else if (balance == previous_balance && !handler.node.ledger.epoch_link.is_zero () && block_a.hashables.link == handler.node.ledger.epoch_link)
{
if (raw)
{
tree.put ("subtype", "epoch");
tree.put ("account", handler.node.ledger.epoch_signer.to_account ());
}
}
else
{
if (raw)
@ -2323,6 +2332,7 @@ void rai::rpc_handler::pending ()
}
}
const bool source = request.get<bool> ("source", false);
const bool min_version = request.get<bool> ("min_version", false);
boost::property_tree::ptree response_l;
boost::property_tree::ptree peers_l;
{
@ -2331,7 +2341,7 @@ void rai::rpc_handler::pending ()
for (auto i (node.store.pending_begin (transaction, rai::pending_key (account, 0))), n (node.store.pending_begin (transaction, rai::pending_key (end, 0))); i != n && peers_l.size () < count; ++i)
{
rai::pending_key key (i->first);
if (threshold.is_zero () && !source)
if (threshold.is_zero () && !source && !min_version)
{
boost::property_tree::ptree entry;
entry.put ("", key.hash.to_string ());
@ -2342,11 +2352,18 @@ void rai::rpc_handler::pending ()
rai::pending_info info (i->second);
if (info.amount.number () >= threshold.number ())
{
if (source)
if (source || min_version)
{
boost::property_tree::ptree pending_tree;
pending_tree.put ("amount", info.amount.number ().convert_to<std::string> ());
pending_tree.put ("source", info.source.to_account ());
if (source)
{
pending_tree.put ("source", info.source.to_account ());
}
if (min_version)
{
pending_tree.put ("min_version", std::to_string (info.min_version));
}
peers_l.add_child (key.hash.to_string (), pending_tree);
}
else
@ -3992,6 +4009,7 @@ void rai::rpc_handler::wallet_pending ()
}
}
const bool source = request.get<bool> ("source", false);
const bool min_version = request.get<bool> ("min_version", false);
boost::property_tree::ptree response_l;
boost::property_tree::ptree pending;
rai::transaction transaction (node.store.environment, nullptr, false);
@ -4014,11 +4032,18 @@ void rai::rpc_handler::wallet_pending ()
rai::pending_info info (ii->second);
if (info.amount.number () >= threshold.number ())
{
if (source)
if (source || min_version)
{
boost::property_tree::ptree pending_tree;
pending_tree.put ("amount", info.amount.number ().convert_to<std::string> ());
pending_tree.put ("source", info.source.to_account ());
if (source)
{
pending_tree.put ("source", info.source.to_account ());
}
if (min_version)
{
pending_tree.put ("min_version", std::to_string (info.min_version));
}
peers_l.add_child (key.hash.to_string (), pending_tree);
}
else

View file

@ -411,6 +411,9 @@ std::string rai::stat::detail_to_string (uint32_t key)
case rai::stat::detail::state_block:
res = "state_block";
break;
case rai::stat::detail::epoch_block:
res = "epoch_block";
break;
case rai::stat::detail::vote_valid:
res = "vote_valid";
break;

View file

@ -202,6 +202,7 @@ public:
open,
change,
state_block,
epoch_block,
// message specific
keepalive,

View file

@ -547,6 +547,11 @@ public:
type = "Change";
account = block_a.hashables.representative;
}
else if (balance == previous_balance && !ledger.epoch_link.is_zero () && block_a.hashables.link == ledger.epoch_link)
{
type = "Epoch";
account = ledger.epoch_signer;
}
else
{
type = "Receive";