Refactoring: Split secure.*pp into common, ledger and blockstore, and move working_path to utility, where it was declared anyway (#662)
This commit is contained in:
parent
bb544ee0de
commit
702da39639
18 changed files with 3227 additions and 3141 deletions
|
@ -266,8 +266,12 @@ add_library (secure
|
|||
${PLATFORM_SECURE_SOURCE}
|
||||
${CMAKE_BINARY_DIR}/bootstrap_weights.cpp
|
||||
rai/config.hpp
|
||||
rai/secure.cpp
|
||||
rai/secure.hpp
|
||||
rai/common.cpp
|
||||
rai/common.hpp
|
||||
rai/blockstore.cpp
|
||||
rai/blockstore.hpp
|
||||
rai/ledger.cpp
|
||||
rai/ledger.hpp
|
||||
rai/node/utility.cpp
|
||||
rai/node/utility.hpp
|
||||
rai/versioning.hpp
|
||||
|
|
1280
rai/blockstore.cpp
Normal file
1280
rai/blockstore.cpp
Normal file
File diff suppressed because it is too large
Load diff
183
rai/blockstore.hpp
Normal file
183
rai/blockstore.hpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
#pragma once
|
||||
|
||||
#include <rai/common.hpp>
|
||||
|
||||
namespace rai
|
||||
{
|
||||
/**
|
||||
* The value produced when iterating with \ref store_iterator
|
||||
*/
|
||||
class store_entry
|
||||
{
|
||||
public:
|
||||
store_entry ();
|
||||
void clear ();
|
||||
store_entry * operator-> ();
|
||||
rai::mdb_val first;
|
||||
rai::mdb_val second;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates the key/value pairs of a transaction
|
||||
*/
|
||||
class store_iterator
|
||||
{
|
||||
public:
|
||||
store_iterator (MDB_txn *, MDB_dbi);
|
||||
store_iterator (std::nullptr_t);
|
||||
store_iterator (MDB_txn *, MDB_dbi, MDB_val const &);
|
||||
store_iterator (rai::store_iterator &&);
|
||||
store_iterator (rai::store_iterator const &) = delete;
|
||||
~store_iterator ();
|
||||
rai::store_iterator & operator++ ();
|
||||
void next_dup ();
|
||||
rai::store_iterator & operator= (rai::store_iterator &&);
|
||||
rai::store_iterator & operator= (rai::store_iterator const &) = delete;
|
||||
rai::store_entry & operator-> ();
|
||||
bool operator== (rai::store_iterator const &) const;
|
||||
bool operator!= (rai::store_iterator const &) const;
|
||||
MDB_cursor * cursor;
|
||||
rai::store_entry current;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manages block storage and iteration
|
||||
*/
|
||||
class block_store
|
||||
{
|
||||
public:
|
||||
block_store (bool &, boost::filesystem::path const &, int lmdb_max_dbs = 128);
|
||||
|
||||
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));
|
||||
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 &);
|
||||
std::unique_ptr<rai::block> block_get (MDB_txn *, rai::block_hash const &);
|
||||
std::unique_ptr<rai::block> block_random (MDB_txn *);
|
||||
std::unique_ptr<rai::block> block_random (MDB_txn *, MDB_dbi);
|
||||
void block_del (MDB_txn *, rai::block_hash const &);
|
||||
bool block_exists (MDB_txn *, rai::block_hash const &);
|
||||
rai::block_counts block_count (MDB_txn *);
|
||||
std::unordered_multimap<rai::block_hash, rai::block_hash> block_dependencies (MDB_txn *);
|
||||
|
||||
void frontier_put (MDB_txn *, rai::block_hash const &, rai::account const &);
|
||||
rai::account frontier_get (MDB_txn *, rai::block_hash const &);
|
||||
void frontier_del (MDB_txn *, rai::block_hash const &);
|
||||
size_t frontier_count (MDB_txn *);
|
||||
|
||||
void account_put (MDB_txn *, rai::account const &, rai::account_info const &);
|
||||
bool account_get (MDB_txn *, rai::account const &, rai::account_info &);
|
||||
void account_del (MDB_txn *, rai::account const &);
|
||||
bool account_exists (MDB_txn *, rai::account const &);
|
||||
rai::store_iterator latest_begin (MDB_txn *, rai::account const &);
|
||||
rai::store_iterator latest_begin (MDB_txn *);
|
||||
rai::store_iterator latest_end ();
|
||||
|
||||
void pending_put (MDB_txn *, rai::pending_key const &, rai::pending_info const &);
|
||||
void pending_del (MDB_txn *, rai::pending_key const &);
|
||||
bool pending_get (MDB_txn *, rai::pending_key const &, rai::pending_info &);
|
||||
bool pending_exists (MDB_txn *, rai::pending_key const &);
|
||||
rai::store_iterator pending_begin (MDB_txn *, rai::pending_key const &);
|
||||
rai::store_iterator pending_begin (MDB_txn *);
|
||||
rai::store_iterator pending_end ();
|
||||
|
||||
void block_info_put (MDB_txn *, rai::block_hash const &, rai::block_info const &);
|
||||
void block_info_del (MDB_txn *, rai::block_hash const &);
|
||||
bool block_info_get (MDB_txn *, rai::block_hash const &, rai::block_info &);
|
||||
bool block_info_exists (MDB_txn *, rai::block_hash const &);
|
||||
rai::store_iterator block_info_begin (MDB_txn *, rai::block_hash const &);
|
||||
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 &);
|
||||
static size_t const block_info_max = 32;
|
||||
|
||||
rai::uint128_t representation_get (MDB_txn *, rai::account const &);
|
||||
void representation_put (MDB_txn *, rai::account const &, rai::uint128_t const &);
|
||||
void representation_add (MDB_txn *, rai::account const &, rai::uint128_t const &);
|
||||
rai::store_iterator representation_begin (MDB_txn *);
|
||||
rai::store_iterator representation_end ();
|
||||
|
||||
void unchecked_clear (MDB_txn *);
|
||||
void unchecked_put (MDB_txn *, rai::block_hash const &, std::shared_ptr<rai::block> const &);
|
||||
std::vector<std::shared_ptr<rai::block>> unchecked_get (MDB_txn *, rai::block_hash const &);
|
||||
void unchecked_del (MDB_txn *, rai::block_hash const &, rai::block const &);
|
||||
rai::store_iterator unchecked_begin (MDB_txn *);
|
||||
rai::store_iterator unchecked_begin (MDB_txn *, rai::block_hash const &);
|
||||
rai::store_iterator unchecked_end ();
|
||||
size_t unchecked_count (MDB_txn *);
|
||||
std::unordered_multimap<rai::block_hash, std::shared_ptr<rai::block>> unchecked_cache;
|
||||
|
||||
void unsynced_put (MDB_txn *, rai::block_hash const &);
|
||||
void unsynced_del (MDB_txn *, rai::block_hash const &);
|
||||
bool unsynced_exists (MDB_txn *, rai::block_hash const &);
|
||||
rai::store_iterator unsynced_begin (MDB_txn *, rai::block_hash const &);
|
||||
rai::store_iterator unsynced_begin (MDB_txn *);
|
||||
rai::store_iterator unsynced_end ();
|
||||
|
||||
void checksum_put (MDB_txn *, uint64_t, uint8_t, rai::checksum const &);
|
||||
bool checksum_get (MDB_txn *, uint64_t, uint8_t, rai::checksum &);
|
||||
void checksum_del (MDB_txn *, uint64_t, uint8_t);
|
||||
|
||||
rai::vote_result vote_validate (MDB_txn *, std::shared_ptr<rai::vote>);
|
||||
// Return latest vote for an account from store
|
||||
std::shared_ptr<rai::vote> vote_get (MDB_txn *, rai::account const &);
|
||||
// Populate vote with the next sequence number
|
||||
std::shared_ptr<rai::vote> vote_generate (MDB_txn *, rai::account const &, rai::raw_key const &, std::shared_ptr<rai::block>);
|
||||
// Return either vote or the stored vote with a higher sequence number
|
||||
std::shared_ptr<rai::vote> vote_max (MDB_txn *, std::shared_ptr<rai::vote>);
|
||||
// Return latest vote for an account considering the vote cache
|
||||
std::shared_ptr<rai::vote> vote_current (MDB_txn *, rai::account const &);
|
||||
void flush (MDB_txn *);
|
||||
rai::store_iterator vote_begin (MDB_txn *);
|
||||
rai::store_iterator vote_end ();
|
||||
std::mutex cache_mutex;
|
||||
std::unordered_map<rai::account, std::shared_ptr<rai::vote>> vote_cache;
|
||||
|
||||
void version_put (MDB_txn *, int);
|
||||
int version_get (MDB_txn *);
|
||||
void do_upgrades (MDB_txn *);
|
||||
void upgrade_v1_to_v2 (MDB_txn *);
|
||||
void upgrade_v2_to_v3 (MDB_txn *);
|
||||
void upgrade_v3_to_v4 (MDB_txn *);
|
||||
void upgrade_v4_to_v5 (MDB_txn *);
|
||||
void upgrade_v5_to_v6 (MDB_txn *);
|
||||
void upgrade_v6_to_v7 (MDB_txn *);
|
||||
void upgrade_v7_to_v8 (MDB_txn *);
|
||||
void upgrade_v8_to_v9 (MDB_txn *);
|
||||
void upgrade_v9_to_v10 (MDB_txn *);
|
||||
|
||||
void clear (MDB_dbi);
|
||||
|
||||
rai::mdb_env environment;
|
||||
// block_hash -> account // Maps head blocks to owning account
|
||||
MDB_dbi frontiers;
|
||||
// account -> block_hash, representative, balance, timestamp // Account to head block, representative, balance, last_change
|
||||
MDB_dbi accounts;
|
||||
// block_hash -> send_block
|
||||
MDB_dbi send_blocks;
|
||||
// block_hash -> receive_block
|
||||
MDB_dbi receive_blocks;
|
||||
// block_hash -> open_block
|
||||
MDB_dbi open_blocks;
|
||||
// block_hash -> change_block
|
||||
MDB_dbi change_blocks;
|
||||
// block_hash -> sender, amount, destination // Pending blocks to sender account, amount, destination account
|
||||
MDB_dbi pending;
|
||||
// block_hash -> account, balance // Blocks info
|
||||
MDB_dbi blocks_info;
|
||||
// account -> weight // Representation
|
||||
MDB_dbi representation;
|
||||
// block_hash -> block // Unchecked bootstrap blocks
|
||||
MDB_dbi unchecked;
|
||||
// block_hash -> // Blocks that haven't been broadcast
|
||||
MDB_dbi unsynced;
|
||||
// (uint56_t, uint8_t) -> block_hash // Mapping of region to checksum
|
||||
MDB_dbi checksum;
|
||||
// account -> uint64_t // Highest vote observed for account
|
||||
MDB_dbi vote;
|
||||
// uint256_union -> ? // Meta information about block store
|
||||
MDB_dbi meta;
|
||||
};
|
||||
}
|
755
rai/common.cpp
Normal file
755
rai/common.cpp
Normal file
|
@ -0,0 +1,755 @@
|
|||
#include <rai/common.hpp>
|
||||
|
||||
#include <rai/blockstore.hpp>
|
||||
#include <rai/lib/interface.h>
|
||||
#include <rai/node/common.hpp>
|
||||
#include <rai/versioning.hpp>
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include <ed25519-donna/ed25519.h>
|
||||
|
||||
// Genesis keys for network variants
|
||||
namespace
|
||||
{
|
||||
char const * test_private_key_data = "34F0A37AAD20F4A260F0A5B3CB3D7FB50673212263E58A380BC10474BB039CE4";
|
||||
char const * test_public_key_data = "B0311EA55708D6A53C75CDBF88300259C6D018522FE3D4D0A242E431F9E8B6D0"; // xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo
|
||||
char const * beta_public_key_data = "9D3A5B66B478670455B241D6BAC3D3FE1CBB7E7B7EAA429FA036C2704C3DC0A4"; // xrb_39btdfmday591jcu6igpqd3x9ziwqfz9pzocacht1fp4g385ui76a87x6phk
|
||||
char const * live_public_key_data = "E89208DD038FBB269987689621D52292AE9C35941A7484756ECCED92A65093BA"; // xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3
|
||||
char const * test_genesis_data = R"%%%({
|
||||
"type": "open",
|
||||
"source": "B0311EA55708D6A53C75CDBF88300259C6D018522FE3D4D0A242E431F9E8B6D0",
|
||||
"representative": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo",
|
||||
"account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpiij4txtdo",
|
||||
"work": "9680625b39d3363d",
|
||||
"signature": "ECDA914373A2F0CA1296475BAEE40500A7F0A7AD72A5A80C81D7FAB7F6C802B2CC7DB50F5DD0FB25B2EF11761FA7344A158DD5A700B21BD47DE5BD0F63153A02"
|
||||
})%%%";
|
||||
|
||||
char const * beta_genesis_data = R"%%%({
|
||||
"type": "open",
|
||||
"source": "9D3A5B66B478670455B241D6BAC3D3FE1CBB7E7B7EAA429FA036C2704C3DC0A4",
|
||||
"representative": "xrb_39btdfmday591jcu6igpqd3x9ziwqfz9pzocacht1fp4g385ui76a87x6phk",
|
||||
"account": "xrb_39btdfmday591jcu6igpqd3x9ziwqfz9pzocacht1fp4g385ui76a87x6phk",
|
||||
"work": "6eb12d4c42dba31e",
|
||||
"signature": "BD0D374FCEB33EAABDF728E9B4DCDBF3B226DA97EEAB8EA5B7EDE286B1282C24D6EB544644FE871235E4F58CD94DF66D9C555309895F67A7D1F922AAC12CE907"
|
||||
})%%%";
|
||||
|
||||
char const * live_genesis_data = R"%%%({
|
||||
"type": "open",
|
||||
"source": "E89208DD038FBB269987689621D52292AE9C35941A7484756ECCED92A65093BA",
|
||||
"representative": "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3",
|
||||
"account": "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3",
|
||||
"work": "62f05417dd3fb691",
|
||||
"signature": "9F0C933C8ADE004D808EA1985FA746A7E95BA2A38F867640F53EC8F180BDFE9E2C1268DEAD7C2664F356E37ABA362BC58E46DBA03E523A7B5A19E4B6EB12BB02"
|
||||
})%%%";
|
||||
|
||||
class ledger_constants
|
||||
{
|
||||
public:
|
||||
ledger_constants () :
|
||||
zero_key ("0"),
|
||||
test_genesis_key (test_private_key_data),
|
||||
rai_test_account (test_public_key_data),
|
||||
rai_beta_account (beta_public_key_data),
|
||||
rai_live_account (live_public_key_data),
|
||||
rai_test_genesis (test_genesis_data),
|
||||
rai_beta_genesis (beta_genesis_data),
|
||||
rai_live_genesis (live_genesis_data),
|
||||
genesis_account (rai::rai_network == rai::rai_networks::rai_test_network ? rai_test_account : rai::rai_network == rai::rai_networks::rai_beta_network ? rai_beta_account : rai_live_account),
|
||||
genesis_block (rai::rai_network == rai::rai_networks::rai_test_network ? rai_test_genesis : rai::rai_network == rai::rai_networks::rai_beta_network ? rai_beta_genesis : rai_live_genesis),
|
||||
genesis_amount (std::numeric_limits<rai::uint128_t>::max ()),
|
||||
burn_account (0)
|
||||
{
|
||||
CryptoPP::AutoSeededRandomPool random_pool;
|
||||
// Randomly generating these mean no two nodes will ever have the same sentinal values which protects against some insecure algorithms
|
||||
random_pool.GenerateBlock (not_a_block.bytes.data (), not_a_block.bytes.size ());
|
||||
random_pool.GenerateBlock (not_an_account.bytes.data (), not_an_account.bytes.size ());
|
||||
}
|
||||
rai::keypair zero_key;
|
||||
rai::keypair test_genesis_key;
|
||||
rai::account rai_test_account;
|
||||
rai::account rai_beta_account;
|
||||
rai::account rai_live_account;
|
||||
std::string rai_test_genesis;
|
||||
std::string rai_beta_genesis;
|
||||
std::string rai_live_genesis;
|
||||
rai::account genesis_account;
|
||||
std::string genesis_block;
|
||||
rai::uint128_t genesis_amount;
|
||||
rai::block_hash not_a_block;
|
||||
rai::account not_an_account;
|
||||
rai::account burn_account;
|
||||
};
|
||||
ledger_constants globals;
|
||||
}
|
||||
|
||||
size_t constexpr rai::send_block::size;
|
||||
size_t constexpr rai::receive_block::size;
|
||||
size_t constexpr rai::open_block::size;
|
||||
size_t constexpr rai::change_block::size;
|
||||
|
||||
rai::keypair const & rai::zero_key (globals.zero_key);
|
||||
rai::keypair const & rai::test_genesis_key (globals.test_genesis_key);
|
||||
rai::account const & rai::rai_test_account (globals.rai_test_account);
|
||||
rai::account const & rai::rai_beta_account (globals.rai_beta_account);
|
||||
rai::account const & rai::rai_live_account (globals.rai_live_account);
|
||||
std::string const & rai::rai_test_genesis (globals.rai_test_genesis);
|
||||
std::string const & rai::rai_beta_genesis (globals.rai_beta_genesis);
|
||||
std::string const & rai::rai_live_genesis (globals.rai_live_genesis);
|
||||
|
||||
rai::account const & rai::genesis_account (globals.genesis_account);
|
||||
std::string const & rai::genesis_block (globals.genesis_block);
|
||||
rai::uint128_t const & rai::genesis_amount (globals.genesis_amount);
|
||||
rai::block_hash const & rai::not_a_block (globals.not_a_block);
|
||||
rai::block_hash const & rai::not_an_account (globals.not_an_account);
|
||||
rai::account const & rai::burn_account (globals.burn_account);
|
||||
|
||||
rai::votes::votes (std::shared_ptr<rai::block> block_a) :
|
||||
id (block_a->root ())
|
||||
{
|
||||
rep_votes.insert (std::make_pair (rai::not_an_account, block_a));
|
||||
}
|
||||
|
||||
rai::tally_result rai::votes::vote (std::shared_ptr<rai::vote> vote_a)
|
||||
{
|
||||
rai::tally_result result;
|
||||
auto existing (rep_votes.find (vote_a->account));
|
||||
if (existing == rep_votes.end ())
|
||||
{
|
||||
// Vote on this block hasn't been seen from rep before
|
||||
result = rai::tally_result::vote;
|
||||
rep_votes.insert (std::make_pair (vote_a->account, vote_a->block));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(*existing->second == *vote_a->block))
|
||||
{
|
||||
// Rep changed their vote
|
||||
result = rai::tally_result::changed;
|
||||
existing->second = vote_a->block;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rep vote remained the same
|
||||
result = rai::tally_result::confirm;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Create a new random keypair
|
||||
rai::keypair::keypair ()
|
||||
{
|
||||
random_pool.GenerateBlock (prv.data.bytes.data (), prv.data.bytes.size ());
|
||||
ed25519_publickey (prv.data.bytes.data (), pub.bytes.data ());
|
||||
}
|
||||
|
||||
// Create a keypair given a hex string of the private key
|
||||
rai::keypair::keypair (std::string const & prv_a)
|
||||
{
|
||||
auto error (prv.data.decode_hex (prv_a));
|
||||
assert (!error);
|
||||
ed25519_publickey (prv.data.bytes.data (), pub.bytes.data ());
|
||||
}
|
||||
|
||||
// Serialize a block prefixed with an 8-bit typecode
|
||||
void rai::serialize_block (rai::stream & stream_a, rai::block const & block_a)
|
||||
{
|
||||
write (stream_a, block_a.type ());
|
||||
block_a.serialize (stream_a);
|
||||
}
|
||||
|
||||
std::unique_ptr<rai::block> rai::deserialize_block (MDB_val const & val_a)
|
||||
{
|
||||
rai::bufferstream stream (reinterpret_cast<uint8_t const *> (val_a.mv_data), val_a.mv_size);
|
||||
return deserialize_block (stream);
|
||||
}
|
||||
|
||||
rai::account_info::account_info () :
|
||||
head (0),
|
||||
rep_block (0),
|
||||
open_block (0),
|
||||
balance (0),
|
||||
modified (0),
|
||||
block_count (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");
|
||||
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) :
|
||||
head (head_a),
|
||||
rep_block (rep_block_a),
|
||||
open_block (open_block_a),
|
||||
balance (balance_a),
|
||||
modified (modified_a),
|
||||
block_count (block_count_a)
|
||||
{
|
||||
}
|
||||
|
||||
void rai::account_info::serialize (rai::stream & stream_a) const
|
||||
{
|
||||
write (stream_a, head.bytes);
|
||||
write (stream_a, rep_block.bytes);
|
||||
write (stream_a, open_block.bytes);
|
||||
write (stream_a, balance.bytes);
|
||||
write (stream_a, modified);
|
||||
write (stream_a, block_count);
|
||||
}
|
||||
|
||||
bool rai::account_info::deserialize (rai::stream & stream_a)
|
||||
{
|
||||
auto error (read (stream_a, head.bytes));
|
||||
if (!error)
|
||||
{
|
||||
error = read (stream_a, rep_block.bytes);
|
||||
if (!error)
|
||||
{
|
||||
error = read (stream_a, open_block.bytes);
|
||||
if (!error)
|
||||
{
|
||||
error = read (stream_a, balance.bytes);
|
||||
if (!error)
|
||||
{
|
||||
error = read (stream_a, modified);
|
||||
if (!error)
|
||||
{
|
||||
error = read (stream_a, block_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool rai::account_info::operator!= (rai::account_info const & other_a) const
|
||||
{
|
||||
return !(*this == other_a);
|
||||
}
|
||||
|
||||
rai::mdb_val rai::account_info::val () const
|
||||
{
|
||||
return rai::mdb_val (sizeof (*this), const_cast<rai::account_info *> (this));
|
||||
}
|
||||
|
||||
rai::block_counts::block_counts () :
|
||||
send (0),
|
||||
receive (0),
|
||||
open (0),
|
||||
change (0)
|
||||
{
|
||||
}
|
||||
|
||||
size_t rai::block_counts::sum ()
|
||||
{
|
||||
return send + receive + open + change;
|
||||
}
|
||||
|
||||
rai::pending_info::pending_info () :
|
||||
source (0),
|
||||
amount (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");
|
||||
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) :
|
||||
source (source_a),
|
||||
amount (amount_a)
|
||||
{
|
||||
}
|
||||
|
||||
void rai::pending_info::serialize (rai::stream & stream_a) const
|
||||
{
|
||||
rai::write (stream_a, source.bytes);
|
||||
rai::write (stream_a, amount.bytes);
|
||||
}
|
||||
|
||||
bool rai::pending_info::deserialize (rai::stream & stream_a)
|
||||
{
|
||||
auto result (rai::read (stream_a, source.bytes));
|
||||
if (!result)
|
||||
{
|
||||
result = rai::read (stream_a, amount.bytes);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool rai::pending_info::operator== (rai::pending_info const & other_a) const
|
||||
{
|
||||
return source == other_a.source && amount == other_a.amount;
|
||||
}
|
||||
|
||||
rai::mdb_val rai::pending_info::val () const
|
||||
{
|
||||
return rai::mdb_val (sizeof (*this), const_cast<rai::pending_info *> (this));
|
||||
}
|
||||
|
||||
rai::pending_key::pending_key (rai::account const & account_a, rai::block_hash const & hash_a) :
|
||||
account (account_a),
|
||||
hash (hash_a)
|
||||
{
|
||||
}
|
||||
|
||||
rai::pending_key::pending_key (MDB_val const & val_a)
|
||||
{
|
||||
assert (val_a.mv_size == sizeof (*this));
|
||||
static_assert (sizeof (account) + sizeof (hash) == 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));
|
||||
}
|
||||
|
||||
void rai::pending_key::serialize (rai::stream & stream_a) const
|
||||
{
|
||||
rai::write (stream_a, account.bytes);
|
||||
rai::write (stream_a, hash.bytes);
|
||||
}
|
||||
|
||||
bool rai::pending_key::deserialize (rai::stream & stream_a)
|
||||
{
|
||||
auto error (rai::read (stream_a, account.bytes));
|
||||
if (!error)
|
||||
{
|
||||
error = rai::read (stream_a, hash.bytes);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
bool rai::pending_key::operator== (rai::pending_key const & other_a) const
|
||||
{
|
||||
return account == other_a.account && hash == other_a.hash;
|
||||
}
|
||||
|
||||
rai::mdb_val rai::pending_key::val () const
|
||||
{
|
||||
return rai::mdb_val (sizeof (*this), const_cast<rai::pending_key *> (this));
|
||||
}
|
||||
|
||||
rai::block_info::block_info () :
|
||||
account (0),
|
||||
balance (0)
|
||||
{
|
||||
}
|
||||
|
||||
rai::block_info::block_info (MDB_val const & val_a)
|
||||
{
|
||||
assert (val_a.mv_size == sizeof (*this));
|
||||
static_assert (sizeof (account) + sizeof (balance) == 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::block_info::block_info (rai::account const & account_a, rai::amount const & balance_a) :
|
||||
account (account_a),
|
||||
balance (balance_a)
|
||||
{
|
||||
}
|
||||
|
||||
void rai::block_info::serialize (rai::stream & stream_a) const
|
||||
{
|
||||
rai::write (stream_a, account.bytes);
|
||||
rai::write (stream_a, balance.bytes);
|
||||
}
|
||||
|
||||
bool rai::block_info::deserialize (rai::stream & stream_a)
|
||||
{
|
||||
auto error (rai::read (stream_a, account.bytes));
|
||||
if (!error)
|
||||
{
|
||||
error = rai::read (stream_a, balance.bytes);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
bool rai::block_info::operator== (rai::block_info const & other_a) const
|
||||
{
|
||||
return account == other_a.account && balance == other_a.balance;
|
||||
}
|
||||
|
||||
rai::mdb_val rai::block_info::val () const
|
||||
{
|
||||
return rai::mdb_val (sizeof (*this), const_cast<rai::block_info *> (this));
|
||||
}
|
||||
|
||||
bool rai::vote::operator== (rai::vote const & other_a) const
|
||||
{
|
||||
return sequence == other_a.sequence && *block == *other_a.block && account == other_a.account && signature == other_a.signature;
|
||||
}
|
||||
|
||||
bool rai::vote::operator!= (rai::vote const & other_a) const
|
||||
{
|
||||
return !(*this == other_a);
|
||||
}
|
||||
|
||||
std::string rai::vote::to_json () const
|
||||
{
|
||||
std::stringstream stream;
|
||||
boost::property_tree::ptree tree;
|
||||
tree.put ("account", account.to_account ());
|
||||
tree.put ("signature", signature.number ());
|
||||
tree.put ("sequence", std::to_string (sequence));
|
||||
tree.put ("block", block->to_json ());
|
||||
boost::property_tree::write_json (stream, tree);
|
||||
return stream.str ();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class root_visitor : public rai::block_visitor
|
||||
{
|
||||
public:
|
||||
root_visitor (rai::block_store & store_a) :
|
||||
store (store_a)
|
||||
{
|
||||
}
|
||||
virtual ~root_visitor () = default;
|
||||
void send_block (rai::send_block const & block_a) override
|
||||
{
|
||||
result = block_a.previous ();
|
||||
}
|
||||
void receive_block (rai::receive_block const & block_a) override
|
||||
{
|
||||
result = block_a.previous ();
|
||||
}
|
||||
// Open blocks have no previous () so we use the account number
|
||||
void open_block (rai::open_block const & block_a) override
|
||||
{
|
||||
rai::transaction transaction (store.environment, nullptr, false);
|
||||
auto hash (block_a.source ());
|
||||
auto source (store.block_get (transaction, hash));
|
||||
if (source != nullptr)
|
||||
{
|
||||
auto send (dynamic_cast<rai::send_block *> (source.get ()));
|
||||
if (send != nullptr)
|
||||
{
|
||||
result = send->hashables.destination;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.clear ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.clear ();
|
||||
}
|
||||
}
|
||||
void change_block (rai::change_block const & block_a) override
|
||||
{
|
||||
result = block_a.previous ();
|
||||
}
|
||||
rai::block_store & store;
|
||||
rai::block_hash result;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
rai::amount_visitor::amount_visitor (MDB_txn * transaction_a, rai::block_store & store_a) :
|
||||
transaction (transaction_a),
|
||||
store (store_a)
|
||||
{
|
||||
}
|
||||
|
||||
void rai::amount_visitor::send_block (rai::send_block const & block_a)
|
||||
{
|
||||
balance_visitor prev (transaction, store);
|
||||
prev.compute (block_a.hashables.previous);
|
||||
result = prev.result - block_a.hashables.balance.number ();
|
||||
}
|
||||
|
||||
void rai::amount_visitor::receive_block (rai::receive_block const & block_a)
|
||||
{
|
||||
from_send (block_a.hashables.source);
|
||||
}
|
||||
|
||||
void rai::amount_visitor::open_block (rai::open_block const & block_a)
|
||||
{
|
||||
if (block_a.hashables.source != rai::genesis_account)
|
||||
{
|
||||
from_send (block_a.hashables.source);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = rai::genesis_amount;
|
||||
}
|
||||
}
|
||||
|
||||
void rai::amount_visitor::change_block (rai::change_block const & block_a)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
|
||||
void rai::amount_visitor::from_send (rai::block_hash const & hash_a)
|
||||
{
|
||||
auto source_block (store.block_get (transaction, hash_a));
|
||||
assert (source_block != nullptr);
|
||||
source_block->visit (*this);
|
||||
}
|
||||
|
||||
void rai::amount_visitor::compute (rai::block_hash const & block_hash)
|
||||
{
|
||||
auto block (store.block_get (transaction, block_hash));
|
||||
if (block != nullptr)
|
||||
{
|
||||
block->visit (*this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (block_hash == rai::genesis_account)
|
||||
{
|
||||
result = std::numeric_limits<rai::uint128_t>::max ();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (false);
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rai::balance_visitor::balance_visitor (MDB_txn * transaction_a, rai::block_store & store_a) :
|
||||
transaction (transaction_a),
|
||||
store (store_a),
|
||||
current (0),
|
||||
result (0)
|
||||
{
|
||||
}
|
||||
|
||||
void rai::balance_visitor::send_block (rai::send_block const & block_a)
|
||||
{
|
||||
result += block_a.hashables.balance.number ();
|
||||
current = 0;
|
||||
}
|
||||
|
||||
void rai::balance_visitor::receive_block (rai::receive_block const & block_a)
|
||||
{
|
||||
amount_visitor source (transaction, store);
|
||||
source.compute (block_a.hashables.source);
|
||||
rai::block_info block_info;
|
||||
if (!store.block_info_get (transaction, block_a.hash (), block_info))
|
||||
{
|
||||
result += block_info.balance.number ();
|
||||
current = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += source.result;
|
||||
current = block_a.hashables.previous;
|
||||
}
|
||||
}
|
||||
|
||||
void rai::balance_visitor::open_block (rai::open_block const & block_a)
|
||||
{
|
||||
amount_visitor source (transaction, store);
|
||||
source.compute (block_a.hashables.source);
|
||||
result += source.result;
|
||||
current = 0;
|
||||
}
|
||||
|
||||
void rai::balance_visitor::change_block (rai::change_block const & block_a)
|
||||
{
|
||||
rai::block_info block_info;
|
||||
if (!store.block_info_get (transaction, block_a.hash (), block_info))
|
||||
{
|
||||
result += block_info.balance.number ();
|
||||
current = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = block_a.hashables.previous;
|
||||
}
|
||||
}
|
||||
|
||||
void rai::balance_visitor::compute (rai::block_hash const & block_hash)
|
||||
{
|
||||
current = block_hash;
|
||||
while (!current.is_zero ())
|
||||
{
|
||||
auto block (store.block_get (transaction, current));
|
||||
assert (block != nullptr);
|
||||
block->visit (*this);
|
||||
}
|
||||
}
|
||||
|
||||
rai::representative_visitor::representative_visitor (MDB_txn * transaction_a, rai::block_store & store_a) :
|
||||
transaction (transaction_a),
|
||||
store (store_a),
|
||||
result (0)
|
||||
{
|
||||
}
|
||||
|
||||
void rai::representative_visitor::compute (rai::block_hash const & hash_a)
|
||||
{
|
||||
current = hash_a;
|
||||
while (result.is_zero ())
|
||||
{
|
||||
auto block (store.block_get (transaction, current));
|
||||
assert (block != nullptr);
|
||||
block->visit (*this);
|
||||
}
|
||||
}
|
||||
|
||||
void rai::representative_visitor::send_block (rai::send_block const & block_a)
|
||||
{
|
||||
current = block_a.previous ();
|
||||
}
|
||||
|
||||
void rai::representative_visitor::receive_block (rai::receive_block const & block_a)
|
||||
{
|
||||
current = block_a.previous ();
|
||||
}
|
||||
|
||||
void rai::representative_visitor::open_block (rai::open_block const & block_a)
|
||||
{
|
||||
result = block_a.hash ();
|
||||
}
|
||||
|
||||
void rai::representative_visitor::change_block (rai::change_block const & block_a)
|
||||
{
|
||||
result = block_a.hash ();
|
||||
}
|
||||
|
||||
rai::vote::vote (rai::vote const & other_a) :
|
||||
sequence (other_a.sequence),
|
||||
block (other_a.block),
|
||||
account (other_a.account),
|
||||
signature (other_a.signature)
|
||||
{
|
||||
}
|
||||
|
||||
rai::vote::vote (bool & error_a, rai::stream & stream_a)
|
||||
{
|
||||
if (!error_a)
|
||||
{
|
||||
error_a = rai::read (stream_a, account.bytes);
|
||||
if (!error_a)
|
||||
{
|
||||
error_a = rai::read (stream_a, signature.bytes);
|
||||
if (!error_a)
|
||||
{
|
||||
error_a = rai::read (stream_a, sequence);
|
||||
if (!error_a)
|
||||
{
|
||||
block = rai::deserialize_block (stream_a);
|
||||
error_a = block == nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rai::vote::vote (bool & error_a, rai::stream & stream_a, rai::block_type type_a)
|
||||
{
|
||||
if (!error_a)
|
||||
{
|
||||
error_a = rai::read (stream_a, account.bytes);
|
||||
if (!error_a)
|
||||
{
|
||||
error_a = rai::read (stream_a, signature.bytes);
|
||||
if (!error_a)
|
||||
{
|
||||
error_a = rai::read (stream_a, sequence);
|
||||
if (!error_a)
|
||||
{
|
||||
block = rai::deserialize_block (stream_a, type_a);
|
||||
error_a = block == nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rai::vote::vote (rai::account const & account_a, rai::raw_key const & prv_a, uint64_t sequence_a, std::shared_ptr<rai::block> block_a) :
|
||||
sequence (sequence_a),
|
||||
block (block_a),
|
||||
account (account_a),
|
||||
signature (rai::sign_message (prv_a, account_a, hash ()))
|
||||
{
|
||||
}
|
||||
|
||||
rai::vote::vote (MDB_val const & value_a)
|
||||
{
|
||||
rai::bufferstream stream (reinterpret_cast<uint8_t const *> (value_a.mv_data), value_a.mv_size);
|
||||
auto error (rai::read (stream, account.bytes));
|
||||
assert (!error);
|
||||
error = rai::read (stream, signature.bytes);
|
||||
assert (!error);
|
||||
error = rai::read (stream, sequence);
|
||||
assert (!error);
|
||||
block = rai::deserialize_block (stream);
|
||||
assert (block != nullptr);
|
||||
}
|
||||
|
||||
rai::uint256_union rai::vote::hash () const
|
||||
{
|
||||
rai::uint256_union result;
|
||||
blake2b_state hash;
|
||||
blake2b_init (&hash, sizeof (result.bytes));
|
||||
blake2b_update (&hash, block->hash ().bytes.data (), sizeof (result.bytes));
|
||||
union
|
||||
{
|
||||
uint64_t qword;
|
||||
std::array<uint8_t, 8> bytes;
|
||||
};
|
||||
qword = sequence;
|
||||
blake2b_update (&hash, bytes.data (), sizeof (bytes));
|
||||
blake2b_final (&hash, result.bytes.data (), sizeof (result.bytes));
|
||||
return result;
|
||||
}
|
||||
|
||||
void rai::vote::serialize (rai::stream & stream_a, rai::block_type)
|
||||
{
|
||||
write (stream_a, account);
|
||||
write (stream_a, signature);
|
||||
write (stream_a, sequence);
|
||||
block->serialize (stream_a);
|
||||
}
|
||||
|
||||
void rai::vote::serialize (rai::stream & stream_a)
|
||||
{
|
||||
write (stream_a, account);
|
||||
write (stream_a, signature);
|
||||
write (stream_a, sequence);
|
||||
rai::serialize_block (stream_a, *block);
|
||||
}
|
||||
|
||||
rai::genesis::genesis ()
|
||||
{
|
||||
boost::property_tree::ptree tree;
|
||||
std::stringstream istream (rai::genesis_block);
|
||||
boost::property_tree::read_json (istream, tree);
|
||||
auto block (rai::deserialize_block_json (tree));
|
||||
assert (dynamic_cast<rai::open_block *> (block.get ()) != nullptr);
|
||||
open.reset (static_cast<rai::open_block *> (block.release ()));
|
||||
}
|
||||
|
||||
void rai::genesis::initialize (MDB_txn * transaction_a, rai::block_store & store_a) const
|
||||
{
|
||||
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.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);
|
||||
}
|
||||
|
||||
rai::block_hash rai::genesis::hash () const
|
||||
{
|
||||
return open->hash ();
|
||||
}
|
272
rai/common.hpp
Normal file
272
rai/common.hpp
Normal file
|
@ -0,0 +1,272 @@
|
|||
#pragma once
|
||||
|
||||
#include <rai/lib/blocks.hpp>
|
||||
#include <rai/node/utility.hpp>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <blake2/blake2.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <>
|
||||
struct hash<rai::uint256_union>
|
||||
{
|
||||
size_t operator() (rai::uint256_union const & value_a) const
|
||||
{
|
||||
std::hash<rai::uint256_union> hash;
|
||||
return hash (value_a);
|
||||
}
|
||||
};
|
||||
}
|
||||
namespace rai
|
||||
{
|
||||
class block_store;
|
||||
/**
|
||||
* Determine the balance as of this block
|
||||
*/
|
||||
class balance_visitor : public rai::block_visitor
|
||||
{
|
||||
public:
|
||||
balance_visitor (MDB_txn *, rai::block_store &);
|
||||
virtual ~balance_visitor () = default;
|
||||
void compute (rai::block_hash const &);
|
||||
void send_block (rai::send_block const &) override;
|
||||
void receive_block (rai::receive_block const &) override;
|
||||
void open_block (rai::open_block const &) override;
|
||||
void change_block (rai::change_block const &) override;
|
||||
MDB_txn * transaction;
|
||||
rai::block_store & store;
|
||||
rai::block_hash current;
|
||||
rai::uint128_t result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine the amount delta resultant from this block
|
||||
*/
|
||||
class amount_visitor : public rai::block_visitor
|
||||
{
|
||||
public:
|
||||
amount_visitor (MDB_txn *, rai::block_store &);
|
||||
virtual ~amount_visitor () = default;
|
||||
void compute (rai::block_hash const &);
|
||||
void send_block (rai::send_block const &) override;
|
||||
void receive_block (rai::receive_block const &) override;
|
||||
void open_block (rai::open_block const &) override;
|
||||
void change_block (rai::change_block const &) override;
|
||||
void from_send (rai::block_hash const &);
|
||||
MDB_txn * transaction;
|
||||
rai::block_store & store;
|
||||
rai::uint128_t result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine the representative for this block
|
||||
*/
|
||||
class representative_visitor : public rai::block_visitor
|
||||
{
|
||||
public:
|
||||
representative_visitor (MDB_txn * transaction_a, rai::block_store & store_a);
|
||||
virtual ~representative_visitor () = default;
|
||||
void compute (rai::block_hash const & hash_a);
|
||||
void send_block (rai::send_block const & block_a) override;
|
||||
void receive_block (rai::receive_block const & block_a) override;
|
||||
void open_block (rai::open_block const & block_a) override;
|
||||
void change_block (rai::change_block const & block_a) override;
|
||||
MDB_txn * transaction;
|
||||
rai::block_store & store;
|
||||
rai::block_hash current;
|
||||
rai::block_hash result;
|
||||
};
|
||||
|
||||
/**
|
||||
* A key pair. The private key is generated from the random pool, or passed in
|
||||
* as a hex string. The public key is derived using ed25519.
|
||||
*/
|
||||
class keypair
|
||||
{
|
||||
public:
|
||||
keypair ();
|
||||
keypair (std::string const &);
|
||||
rai::public_key pub;
|
||||
rai::raw_key prv;
|
||||
};
|
||||
|
||||
std::unique_ptr<rai::block> deserialize_block (MDB_val const &);
|
||||
|
||||
/**
|
||||
* Latest information about an account
|
||||
*/
|
||||
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);
|
||||
void serialize (rai::stream &) const;
|
||||
bool deserialize (rai::stream &);
|
||||
bool operator== (rai::account_info const &) const;
|
||||
bool operator!= (rai::account_info const &) const;
|
||||
rai::mdb_val val () const;
|
||||
rai::block_hash head;
|
||||
rai::block_hash rep_block;
|
||||
rai::block_hash open_block;
|
||||
rai::amount balance;
|
||||
/** Seconds since posix epoch */
|
||||
uint64_t modified;
|
||||
uint64_t block_count;
|
||||
};
|
||||
|
||||
/**
|
||||
* Information on an uncollected send, source account, amount, target account.
|
||||
*/
|
||||
class pending_info
|
||||
{
|
||||
public:
|
||||
pending_info ();
|
||||
pending_info (MDB_val const &);
|
||||
pending_info (rai::account const &, rai::amount const &);
|
||||
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;
|
||||
};
|
||||
class pending_key
|
||||
{
|
||||
public:
|
||||
pending_key (rai::account const &, rai::block_hash const &);
|
||||
pending_key (MDB_val const &);
|
||||
void serialize (rai::stream &) const;
|
||||
bool deserialize (rai::stream &);
|
||||
bool operator== (rai::pending_key const &) const;
|
||||
rai::mdb_val val () const;
|
||||
rai::account account;
|
||||
rai::block_hash hash;
|
||||
};
|
||||
class block_info
|
||||
{
|
||||
public:
|
||||
block_info ();
|
||||
block_info (MDB_val const &);
|
||||
block_info (rai::account const &, rai::amount const &);
|
||||
void serialize (rai::stream &) const;
|
||||
bool deserialize (rai::stream &);
|
||||
bool operator== (rai::block_info const &) const;
|
||||
rai::mdb_val val () const;
|
||||
rai::account account;
|
||||
rai::amount balance;
|
||||
};
|
||||
class block_counts
|
||||
{
|
||||
public:
|
||||
block_counts ();
|
||||
size_t sum ();
|
||||
size_t send;
|
||||
size_t receive;
|
||||
size_t open;
|
||||
size_t change;
|
||||
};
|
||||
class vote
|
||||
{
|
||||
public:
|
||||
vote () = default;
|
||||
vote (rai::vote const &);
|
||||
vote (bool &, rai::stream &);
|
||||
vote (bool &, rai::stream &, rai::block_type);
|
||||
vote (rai::account const &, rai::raw_key const &, uint64_t, std::shared_ptr<rai::block>);
|
||||
vote (MDB_val const &);
|
||||
rai::uint256_union hash () const;
|
||||
bool operator== (rai::vote const &) const;
|
||||
bool operator!= (rai::vote const &) const;
|
||||
void serialize (rai::stream &, rai::block_type);
|
||||
void serialize (rai::stream &);
|
||||
std::string to_json () const;
|
||||
// Vote round sequence number
|
||||
uint64_t sequence;
|
||||
std::shared_ptr<rai::block> block;
|
||||
// Account that's voting
|
||||
rai::account account;
|
||||
// Signature of sequence + block hash
|
||||
rai::signature signature;
|
||||
};
|
||||
enum class vote_code
|
||||
{
|
||||
invalid, // Vote is not signed correctly
|
||||
replay, // Vote does not have the highest sequence number, it's a replay
|
||||
vote // Vote has the highest sequence number
|
||||
};
|
||||
class vote_result
|
||||
{
|
||||
public:
|
||||
rai::vote_code code;
|
||||
std::shared_ptr<rai::vote> vote;
|
||||
};
|
||||
|
||||
enum class process_result
|
||||
{
|
||||
progress, // Hasn't been seen before, signed correctly
|
||||
bad_signature, // Signature was bad, forged or transmission error
|
||||
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
|
||||
gap_previous, // Block marked as previous is unknown
|
||||
gap_source, // Block marked as source is unknown
|
||||
not_receive_from_send, // Receive does not have a send source
|
||||
account_mismatch, // Account number in open block doesn't match send destination
|
||||
opened_burn_account // The impossible happened, someone found the private key associated with the public key '0'.
|
||||
};
|
||||
class process_return
|
||||
{
|
||||
public:
|
||||
rai::process_result code;
|
||||
rai::account account;
|
||||
rai::amount amount;
|
||||
rai::account pending_account;
|
||||
};
|
||||
enum class tally_result
|
||||
{
|
||||
vote,
|
||||
changed,
|
||||
confirm
|
||||
};
|
||||
class votes
|
||||
{
|
||||
public:
|
||||
votes (std::shared_ptr<rai::block>);
|
||||
rai::tally_result vote (std::shared_ptr<rai::vote>);
|
||||
// Root block of fork
|
||||
rai::block_hash id;
|
||||
// All votes received by account
|
||||
std::unordered_map<rai::account, std::shared_ptr<rai::block>> rep_votes;
|
||||
};
|
||||
extern rai::keypair const & zero_key;
|
||||
extern rai::keypair const & test_genesis_key;
|
||||
extern rai::account const & rai_test_account;
|
||||
extern rai::account const & rai_beta_account;
|
||||
extern rai::account const & rai_live_account;
|
||||
extern std::string const & rai_test_genesis;
|
||||
extern std::string const & rai_beta_genesis;
|
||||
extern std::string const & rai_live_genesis;
|
||||
extern std::string const & genesis_block;
|
||||
extern rai::account const & genesis_account;
|
||||
extern rai::account const & burn_account;
|
||||
extern rai::uint128_t const & genesis_amount;
|
||||
// A block hash that compares inequal to any real block hash
|
||||
extern rai::block_hash const & not_a_block;
|
||||
// An account number that compares inequal to any real account number
|
||||
extern rai::block_hash const & not_an_account;
|
||||
class genesis
|
||||
{
|
||||
public:
|
||||
explicit genesis ();
|
||||
void initialize (MDB_txn *, rai::block_store &) const;
|
||||
rai::block_hash hash () const;
|
||||
std::unique_ptr<rai::open_block> open;
|
||||
};
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rai/common.hpp>
|
||||
#include <rai/lib/interface.h>
|
||||
#include <rai/secure.hpp>
|
||||
|
||||
#include <ed25519-donna/ed25519.h>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <rai/secure.hpp>
|
||||
#include <rai/blockstore.hpp>
|
||||
#include <rai/versioning.hpp>
|
||||
|
||||
TEST (versioning, account_info_v1)
|
||||
|
|
637
rai/ledger.cpp
Normal file
637
rai/ledger.cpp
Normal file
|
@ -0,0 +1,637 @@
|
|||
#include <rai/blockstore.hpp>
|
||||
#include <rai/ledger.hpp>
|
||||
#include <rai/node/common.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* Roll back the visited block
|
||||
*/
|
||||
class rollback_visitor : public rai::block_visitor
|
||||
{
|
||||
public:
|
||||
rollback_visitor (MDB_txn * transaction_a, rai::ledger & ledger_a) :
|
||||
transaction (transaction_a),
|
||||
ledger (ledger_a)
|
||||
{
|
||||
}
|
||||
virtual ~rollback_visitor () = default;
|
||||
void send_block (rai::send_block const & block_a) override
|
||||
{
|
||||
auto hash (block_a.hash ());
|
||||
rai::pending_info pending;
|
||||
rai::pending_key key (block_a.hashables.destination, hash);
|
||||
while (ledger.store.pending_get (transaction, key, pending))
|
||||
{
|
||||
ledger.rollback (transaction, ledger.latest (transaction, block_a.hashables.destination));
|
||||
}
|
||||
rai::account_info info;
|
||||
auto error (ledger.store.account_get (transaction, pending.source, info));
|
||||
assert (!error);
|
||||
ledger.store.pending_del (transaction, key);
|
||||
ledger.store.representation_add (transaction, ledger.representative (transaction, hash), pending.amount.number ());
|
||||
ledger.change_latest (transaction, pending.source, block_a.hashables.previous, info.rep_block, ledger.balance (transaction, block_a.hashables.previous), info.block_count - 1);
|
||||
ledger.store.block_del (transaction, hash);
|
||||
ledger.store.frontier_del (transaction, hash);
|
||||
ledger.store.frontier_put (transaction, block_a.hashables.previous, pending.source);
|
||||
ledger.store.block_successor_clear (transaction, block_a.hashables.previous);
|
||||
if (!(info.block_count % ledger.store.block_info_max))
|
||||
{
|
||||
ledger.store.block_info_del (transaction, hash);
|
||||
}
|
||||
}
|
||||
void receive_block (rai::receive_block const & block_a) override
|
||||
{
|
||||
auto hash (block_a.hash ());
|
||||
auto representative (ledger.representative (transaction, block_a.hashables.previous));
|
||||
auto amount (ledger.amount (transaction, block_a.hashables.source));
|
||||
auto destination_account (ledger.account (transaction, hash));
|
||||
rai::account_info info;
|
||||
auto error (ledger.store.account_get (transaction, destination_account, info));
|
||||
assert (!error);
|
||||
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), { ledger.account (transaction, block_a.hashables.source), amount });
|
||||
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);
|
||||
if (!(info.block_count % ledger.store.block_info_max))
|
||||
{
|
||||
ledger.store.block_info_del (transaction, hash);
|
||||
}
|
||||
}
|
||||
void open_block (rai::open_block const & block_a) override
|
||||
{
|
||||
auto hash (block_a.hash ());
|
||||
auto amount (ledger.amount (transaction, block_a.hashables.source));
|
||||
auto destination_account (ledger.account (transaction, hash));
|
||||
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), { ledger.account (transaction, block_a.hashables.source), amount });
|
||||
ledger.store.frontier_del (transaction, hash);
|
||||
}
|
||||
void change_block (rai::change_block const & block_a) override
|
||||
{
|
||||
auto hash (block_a.hash ());
|
||||
auto representative (ledger.representative (transaction, block_a.hashables.previous));
|
||||
auto account (ledger.account (transaction, block_a.hashables.previous));
|
||||
rai::account_info info;
|
||||
auto error (ledger.store.account_get (transaction, account, info));
|
||||
assert (!error);
|
||||
auto balance (ledger.balance (transaction, block_a.hashables.previous));
|
||||
ledger.store.representation_add (transaction, representative, balance);
|
||||
ledger.store.representation_add (transaction, hash, 0 - balance);
|
||||
ledger.store.block_del (transaction, hash);
|
||||
ledger.change_latest (transaction, account, block_a.hashables.previous, representative, info.balance, info.block_count - 1);
|
||||
ledger.store.frontier_del (transaction, hash);
|
||||
ledger.store.frontier_put (transaction, block_a.hashables.previous, account);
|
||||
ledger.store.block_successor_clear (transaction, block_a.hashables.previous);
|
||||
if (!(info.block_count % ledger.store.block_info_max))
|
||||
{
|
||||
ledger.store.block_info_del (transaction, hash);
|
||||
}
|
||||
}
|
||||
MDB_txn * transaction;
|
||||
rai::ledger & ledger;
|
||||
};
|
||||
|
||||
class ledger_processor : public rai::block_visitor
|
||||
{
|
||||
public:
|
||||
ledger_processor (rai::ledger &, MDB_txn *);
|
||||
virtual ~ledger_processor () = default;
|
||||
void send_block (rai::send_block const &) override;
|
||||
void receive_block (rai::receive_block const &) override;
|
||||
void open_block (rai::open_block const &) override;
|
||||
void change_block (rai::change_block const &) override;
|
||||
rai::ledger & ledger;
|
||||
MDB_txn * transaction;
|
||||
rai::process_return result;
|
||||
};
|
||||
|
||||
void ledger_processor::change_block (rai::change_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? (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
auto previous (ledger.store.block_exists (transaction, block_a.hashables.previous));
|
||||
result.code = previous ? rai::process_result::progress : rai::process_result::gap_previous; // Have we seen the previous block already? (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
auto account (ledger.store.frontier_get (transaction, block_a.hashables.previous));
|
||||
result.code = account.is_zero () ? rai::process_result::fork : rai::process_result::progress;
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
rai::account_info info;
|
||||
auto latest_error (ledger.store.account_get (transaction, account, info));
|
||||
assert (!latest_error);
|
||||
assert (info.head == block_a.hashables.previous);
|
||||
result.code = validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Malformed)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
ledger.store.block_put (transaction, hash, block_a);
|
||||
auto balance (ledger.balance (transaction, block_a.hashables.previous));
|
||||
ledger.store.representation_add (transaction, hash, balance);
|
||||
ledger.store.representation_add (transaction, info.rep_block, 0 - balance);
|
||||
ledger.change_latest (transaction, account, hash, hash, info.balance, info.block_count + 1);
|
||||
ledger.store.frontier_del (transaction, block_a.hashables.previous);
|
||||
ledger.store.frontier_put (transaction, hash, account);
|
||||
result.account = account;
|
||||
result.amount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ledger_processor::send_block (rai::send_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? (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
auto previous (ledger.store.block_exists (transaction, block_a.hashables.previous));
|
||||
result.code = previous ? rai::process_result::progress : rai::process_result::gap_previous; // Have we seen the previous block already? (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
auto account (ledger.store.frontier_get (transaction, block_a.hashables.previous));
|
||||
result.code = account.is_zero () ? rai::process_result::fork : rai::process_result::progress;
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
result.code = validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is this block signed correctly (Malformed)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
rai::account_info info;
|
||||
auto latest_error (ledger.store.account_get (transaction, account, info));
|
||||
assert (!latest_error);
|
||||
assert (info.head == block_a.hashables.previous);
|
||||
result.code = info.balance.number () >= block_a.hashables.balance.number () ? rai::process_result::progress : rai::process_result::negative_spend; // Is this trying to spend a negative amount (Malicious)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
auto amount (info.balance.number () - block_a.hashables.balance.number ());
|
||||
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.frontier_del (transaction, block_a.hashables.previous);
|
||||
ledger.store.frontier_put (transaction, hash, account);
|
||||
result.account = account;
|
||||
result.amount = amount;
|
||||
result.pending_account = block_a.hashables.destination;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ledger_processor::receive_block (rai::receive_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 already? (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
result.code = ledger.store.block_exists (transaction, block_a.hashables.source) ? rai::process_result::progress : rai::process_result::gap_source; // Have we seen the source block already? (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
auto account (ledger.store.frontier_get (transaction, block_a.hashables.previous));
|
||||
result.code = account.is_zero () ? rai::process_result::gap_previous : rai::process_result::progress; //Have we seen the previous block? No entries for account at all (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
result.code = rai::validate_message (account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is the signature valid (Malformed)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
rai::account_info info;
|
||||
ledger.store.account_get (transaction, account, info);
|
||||
result.code = info.head == block_a.hashables.previous ? rai::process_result::progress : rai::process_result::gap_previous; // Block doesn't immediately follow latest block (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
rai::pending_key key (account, block_a.hashables.source);
|
||||
rai::pending_info pending;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.code = ledger.store.block_exists (transaction, block_a.hashables.previous) ? rai::process_result::fork : rai::process_result::gap_previous; // If we have the block but it's not the latest we have a signed fork (Malicious)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ledger_processor::open_block (rai::open_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 already? (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
auto source_missing (!ledger.store.block_exists (transaction, block_a.hashables.source));
|
||||
result.code = source_missing ? rai::process_result::gap_source : rai::process_result::progress; // Have we seen the source block? (Harmless)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
result.code = rai::validate_message (block_a.hashables.account, hash, block_a.signature) ? rai::process_result::bad_signature : rai::process_result::progress; // Is the signature valid (Malformed)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
rai::account_info info;
|
||||
result.code = ledger.store.account_get (transaction, block_a.hashables.account, info) ? rai::process_result::progress : rai::process_result::fork; // Has this account already been opened? (Malicious)
|
||||
if (result.code == rai::process_result::progress)
|
||||
{
|
||||
rai::pending_key key (block_a.hashables.account, block_a.hashables.source);
|
||||
rai::pending_info pending;
|
||||
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)
|
||||
{
|
||||
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_processor::ledger_processor (rai::ledger & ledger_a, MDB_txn * transaction_a) :
|
||||
ledger (ledger_a),
|
||||
transaction (transaction_a)
|
||||
{
|
||||
}
|
||||
} // namespace
|
||||
|
||||
size_t rai::shared_ptr_block_hash::operator() (std::shared_ptr<rai::block> const & block_a) const
|
||||
{
|
||||
auto hash (block_a->hash ());
|
||||
auto result (static_cast<size_t> (hash.qwords[0]));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool rai::shared_ptr_block_hash::operator() (std::shared_ptr<rai::block> const & lhs, std::shared_ptr<rai::block> const & rhs) const
|
||||
{
|
||||
return *lhs == *rhs;
|
||||
}
|
||||
|
||||
rai::ledger::ledger (rai::block_store & store_a, rai::uint128_t const & inactive_supply_a) :
|
||||
store (store_a),
|
||||
inactive_supply (inactive_supply_a),
|
||||
check_bootstrap_weights (true)
|
||||
{
|
||||
}
|
||||
|
||||
// Sum the weights for each vote and return the winning block with its vote tally
|
||||
std::pair<rai::uint128_t, std::shared_ptr<rai::block>> rai::ledger::winner (MDB_txn * transaction_a, rai::votes const & votes_a)
|
||||
{
|
||||
auto tally_l (tally (transaction_a, votes_a));
|
||||
auto existing (tally_l.begin ());
|
||||
return std::make_pair (existing->first, existing->second);
|
||||
}
|
||||
|
||||
std::map<rai::uint128_t, std::shared_ptr<rai::block>, std::greater<rai::uint128_t>> rai::ledger::tally (MDB_txn * transaction_a, rai::votes const & votes_a)
|
||||
{
|
||||
std::unordered_map<std::shared_ptr<block>, rai::uint128_t, rai::shared_ptr_block_hash, rai::shared_ptr_block_hash> totals;
|
||||
// Construct a map of blocks -> vote total.
|
||||
for (auto & i : votes_a.rep_votes)
|
||||
{
|
||||
auto existing (totals.find (i.second));
|
||||
if (existing == totals.end ())
|
||||
{
|
||||
totals.insert (std::make_pair (i.second, 0));
|
||||
existing = totals.find (i.second);
|
||||
assert (existing != totals.end ());
|
||||
}
|
||||
auto weight_l (weight (transaction_a, i.first));
|
||||
existing->second += weight_l;
|
||||
}
|
||||
// Construction a map of vote total -> block in decreasing order.
|
||||
std::map<rai::uint128_t, std::shared_ptr<rai::block>, std::greater<rai::uint128_t>> result;
|
||||
for (auto & i : totals)
|
||||
{
|
||||
result[i.second] = i.first;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Balance for account containing hash
|
||||
rai::uint128_t rai::ledger::balance (MDB_txn * transaction_a, rai::block_hash const & hash_a)
|
||||
{
|
||||
balance_visitor visitor (transaction_a, store);
|
||||
visitor.compute (hash_a);
|
||||
return visitor.result;
|
||||
}
|
||||
|
||||
// Balance for an account by account number
|
||||
rai::uint128_t rai::ledger::account_balance (MDB_txn * transaction_a, rai::account const & account_a)
|
||||
{
|
||||
rai::uint128_t result (0);
|
||||
rai::account_info info;
|
||||
auto none (store.account_get (transaction_a, account_a, info));
|
||||
if (!none)
|
||||
{
|
||||
result = info.balance.number ();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
rai::uint128_t rai::ledger::account_pending (MDB_txn * transaction_a, rai::account const & account_a)
|
||||
{
|
||||
rai::uint128_t result (0);
|
||||
rai::account end (account_a.number () + 1);
|
||||
for (auto i (store.pending_begin (transaction_a, rai::pending_key (account_a, 0))), n (store.pending_begin (transaction_a, rai::pending_key (end, 0))); i != n; ++i)
|
||||
{
|
||||
rai::pending_info info (i->second);
|
||||
result += info.amount.number ();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
rai::process_return rai::ledger::process (MDB_txn * transaction_a, rai::block const & block_a)
|
||||
{
|
||||
ledger_processor processor (*this, transaction_a);
|
||||
block_a.visit (processor);
|
||||
return processor.result;
|
||||
}
|
||||
|
||||
// Money supply for heuristically calculating vote percentages
|
||||
rai::uint128_t rai::ledger::supply (MDB_txn * transaction_a)
|
||||
{
|
||||
auto unallocated (account_balance (transaction_a, rai::genesis_account));
|
||||
auto burned (account_pending (transaction_a, 0));
|
||||
auto absolute_supply (rai::genesis_amount - unallocated - burned);
|
||||
auto adjusted_supply (absolute_supply - inactive_supply);
|
||||
return adjusted_supply <= absolute_supply ? adjusted_supply : 0;
|
||||
}
|
||||
|
||||
rai::block_hash rai::ledger::representative (MDB_txn * transaction_a, rai::block_hash const & hash_a)
|
||||
{
|
||||
auto result (representative_calculated (transaction_a, hash_a));
|
||||
assert (result.is_zero () || store.block_exists (transaction_a, result));
|
||||
return result;
|
||||
}
|
||||
|
||||
rai::block_hash rai::ledger::representative_calculated (MDB_txn * transaction_a, rai::block_hash const & hash_a)
|
||||
{
|
||||
representative_visitor visitor (transaction_a, store);
|
||||
visitor.compute (hash_a);
|
||||
return visitor.result;
|
||||
}
|
||||
|
||||
bool rai::ledger::block_exists (rai::block_hash const & hash_a)
|
||||
{
|
||||
rai::transaction transaction (store.environment, nullptr, false);
|
||||
auto result (store.block_exists (transaction, hash_a));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string rai::ledger::block_text (char const * hash_a)
|
||||
{
|
||||
return block_text (rai::block_hash (hash_a));
|
||||
}
|
||||
|
||||
std::string rai::ledger::block_text (rai::block_hash const & hash_a)
|
||||
{
|
||||
std::string result;
|
||||
rai::transaction transaction (store.environment, nullptr, false);
|
||||
auto block (store.block_get (transaction, hash_a));
|
||||
if (block != nullptr)
|
||||
{
|
||||
block->serialize_json (result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Vote weight of an account
|
||||
rai::uint128_t rai::ledger::weight (MDB_txn * transaction_a, rai::account const & account_a)
|
||||
{
|
||||
if (check_bootstrap_weights.load ())
|
||||
{
|
||||
auto blocks = store.block_count (transaction_a);
|
||||
if (blocks.sum () < bootstrap_weight_max_blocks)
|
||||
{
|
||||
auto weight = bootstrap_weights.find (account_a);
|
||||
if (weight != bootstrap_weights.end ())
|
||||
{
|
||||
return weight->second;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
check_bootstrap_weights = false;
|
||||
}
|
||||
}
|
||||
return store.representation_get (transaction_a, account_a);
|
||||
}
|
||||
|
||||
// Rollback blocks until `block_a' doesn't exist
|
||||
void rai::ledger::rollback (MDB_txn * transaction_a, rai::block_hash const & block_a)
|
||||
{
|
||||
assert (store.block_exists (transaction_a, block_a));
|
||||
auto account_l (account (transaction_a, block_a));
|
||||
rollback_visitor rollback (transaction_a, *this);
|
||||
rai::account_info info;
|
||||
while (store.block_exists (transaction_a, block_a))
|
||||
{
|
||||
auto latest_error (store.account_get (transaction_a, account_l, info));
|
||||
assert (!latest_error);
|
||||
auto block (store.block_get (transaction_a, info.head));
|
||||
block->visit (rollback);
|
||||
}
|
||||
}
|
||||
|
||||
// Return account containing hash
|
||||
rai::account rai::ledger::account (MDB_txn * transaction_a, rai::block_hash const & hash_a)
|
||||
{
|
||||
assert (store.block_exists (transaction_a, hash_a));
|
||||
auto hash (hash_a);
|
||||
rai::block_hash successor (1);
|
||||
rai::block_info block_info;
|
||||
while (!successor.is_zero () && store.block_info_get (transaction_a, successor, block_info))
|
||||
{
|
||||
successor = store.block_successor (transaction_a, hash);
|
||||
if (!successor.is_zero ())
|
||||
{
|
||||
hash = successor;
|
||||
}
|
||||
}
|
||||
rai::account result;
|
||||
if (successor.is_zero ())
|
||||
{
|
||||
result = store.frontier_get (transaction_a, hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = block_info.account;
|
||||
}
|
||||
assert (!result.is_zero ());
|
||||
return result;
|
||||
}
|
||||
|
||||
// Return amount decrease or increase for block
|
||||
rai::uint128_t rai::ledger::amount (MDB_txn * transaction_a, rai::block_hash const & hash_a)
|
||||
{
|
||||
amount_visitor amount (transaction_a, store);
|
||||
amount.compute (hash_a);
|
||||
return amount.result;
|
||||
}
|
||||
|
||||
// Return latest block for account
|
||||
rai::block_hash rai::ledger::latest (MDB_txn * transaction_a, rai::account const & account_a)
|
||||
{
|
||||
rai::account_info info;
|
||||
auto latest_error (store.account_get (transaction_a, account_a, info));
|
||||
return latest_error ? 0 : info.head;
|
||||
}
|
||||
|
||||
// Return latest root for account, account number of there are no blocks for this account.
|
||||
rai::block_hash rai::ledger::latest_root (MDB_txn * transaction_a, rai::account const & account_a)
|
||||
{
|
||||
rai::account_info info;
|
||||
auto latest_error (store.account_get (transaction_a, account_a, info));
|
||||
rai::block_hash result;
|
||||
if (latest_error)
|
||||
{
|
||||
result = account_a;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = info.head;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
rai::checksum rai::ledger::checksum (MDB_txn * transaction_a, rai::account const & begin_a, rai::account const & end_a)
|
||||
{
|
||||
rai::checksum result;
|
||||
auto error (store.checksum_get (transaction_a, 0, 0, result));
|
||||
assert (!error);
|
||||
return result;
|
||||
}
|
||||
|
||||
void rai::ledger::dump_account_chain (rai::account const & account_a)
|
||||
{
|
||||
rai::transaction transaction (store.environment, nullptr, false);
|
||||
auto hash (latest (transaction, account_a));
|
||||
while (!hash.is_zero ())
|
||||
{
|
||||
auto block (store.block_get (transaction, hash));
|
||||
assert (block != nullptr);
|
||||
std::cerr << hash.to_string () << std::endl;
|
||||
hash = block->previous ();
|
||||
}
|
||||
}
|
||||
|
||||
void rai::ledger::checksum_update (MDB_txn * transaction_a, rai::block_hash const & hash_a)
|
||||
{
|
||||
rai::checksum value;
|
||||
auto error (store.checksum_get (transaction_a, 0, 0, value));
|
||||
assert (!error);
|
||||
value ^= hash_a;
|
||||
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)
|
||||
{
|
||||
rai::account_info info;
|
||||
auto exists (!store.account_get (transaction_a, account_a, info));
|
||||
if (exists)
|
||||
{
|
||||
checksum_update (transaction_a, info.head);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (dynamic_cast<rai::open_block *> (store.block_get (transaction_a, hash_a).get ()) != nullptr);
|
||||
info.open_block = hash_a;
|
||||
}
|
||||
if (!hash_a.is_zero ())
|
||||
{
|
||||
info.head = hash_a;
|
||||
info.rep_block = rep_block_a;
|
||||
info.balance = balance_a;
|
||||
info.modified = rai::seconds_since_epoch ();
|
||||
info.block_count = block_count_a;
|
||||
store.account_put (transaction_a, account_a, info);
|
||||
if (!(block_count_a % store.block_info_max))
|
||||
{
|
||||
rai::block_info block_info;
|
||||
block_info.account = account_a;
|
||||
block_info.balance = balance_a;
|
||||
store.block_info_put (transaction_a, hash_a, block_info);
|
||||
}
|
||||
checksum_update (transaction_a, hash_a);
|
||||
}
|
||||
else
|
||||
{
|
||||
store.account_del (transaction_a, account_a);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<rai::block> rai::ledger::successor (MDB_txn * transaction_a, rai::block_hash const & block_a)
|
||||
{
|
||||
assert (store.account_exists (transaction_a, block_a) || store.block_exists (transaction_a, block_a));
|
||||
assert (store.account_exists (transaction_a, block_a) || latest (transaction_a, account (transaction_a, block_a)) != block_a);
|
||||
rai::block_hash successor;
|
||||
if (store.account_exists (transaction_a, block_a))
|
||||
{
|
||||
rai::account_info info;
|
||||
auto error (store.account_get (transaction_a, block_a, info));
|
||||
assert (!error);
|
||||
successor = info.open_block;
|
||||
}
|
||||
else
|
||||
{
|
||||
successor = store.block_successor (transaction_a, block_a);
|
||||
}
|
||||
assert (!successor.is_zero ());
|
||||
auto result (store.block_get (transaction_a, successor));
|
||||
assert (result != nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<rai::block> rai::ledger::forked_block (MDB_txn * transaction_a, rai::block const & block_a)
|
||||
{
|
||||
assert (!store.block_exists (transaction_a, block_a.hash ()));
|
||||
auto root (block_a.root ());
|
||||
assert (store.block_exists (transaction_a, root) || store.account_exists (transaction_a, root));
|
||||
std::unique_ptr<rai::block> result (store.block_get (transaction_a, store.block_successor (transaction_a, root)));
|
||||
if (result == nullptr)
|
||||
{
|
||||
rai::account_info info;
|
||||
auto error (store.account_get (transaction_a, root, info));
|
||||
assert (!error);
|
||||
result = store.block_get (transaction_a, info.open_block);
|
||||
assert (result != nullptr);
|
||||
}
|
||||
return result;
|
||||
}
|
52
rai/ledger.hpp
Normal file
52
rai/ledger.hpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
|
||||
#include <rai/common.hpp>
|
||||
|
||||
namespace rai
|
||||
{
|
||||
class block_store;
|
||||
|
||||
class shared_ptr_block_hash
|
||||
{
|
||||
public:
|
||||
size_t operator() (std::shared_ptr<rai::block> const &) const;
|
||||
bool operator() (std::shared_ptr<rai::block> const &, std::shared_ptr<rai::block> const &) const;
|
||||
};
|
||||
|
||||
class ledger
|
||||
{
|
||||
public:
|
||||
ledger (rai::block_store &, rai::uint128_t 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
|
||||
std::map<rai::uint128_t, std::shared_ptr<rai::block>, std::greater<rai::uint128_t>> tally (MDB_txn *, rai::votes const &);
|
||||
rai::account account (MDB_txn *, rai::block_hash const &);
|
||||
rai::uint128_t amount (MDB_txn *, rai::block_hash const &);
|
||||
rai::uint128_t balance (MDB_txn *, rai::block_hash const &);
|
||||
rai::uint128_t account_balance (MDB_txn *, rai::account const &);
|
||||
rai::uint128_t account_pending (MDB_txn *, rai::account const &);
|
||||
rai::uint128_t weight (MDB_txn *, rai::account const &);
|
||||
std::unique_ptr<rai::block> successor (MDB_txn *, rai::block_hash const &);
|
||||
std::unique_ptr<rai::block> forked_block (MDB_txn *, rai::block const &);
|
||||
rai::block_hash latest (MDB_txn *, rai::account const &);
|
||||
rai::block_hash latest_root (MDB_txn *, rai::account const &);
|
||||
rai::block_hash representative (MDB_txn *, rai::block_hash const &);
|
||||
rai::block_hash representative_calculated (MDB_txn *, rai::block_hash const &);
|
||||
bool block_exists (rai::block_hash const &);
|
||||
std::string block_text (char const *);
|
||||
std::string block_text (rai::block_hash const &);
|
||||
rai::uint128_t supply (MDB_txn *);
|
||||
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);
|
||||
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 &);
|
||||
static rai::uint128_t const unit;
|
||||
rai::block_store & store;
|
||||
rai::uint128_t inactive_supply;
|
||||
std::unordered_map<rai::account, rai::uint128_t> bootstrap_weights;
|
||||
uint64_t bootstrap_weight_max_blocks;
|
||||
std::atomic<bool> check_bootstrap_weights;
|
||||
};
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <rai/blockstore.hpp>
|
||||
#include <rai/ledger.hpp>
|
||||
#include <rai/node/common.hpp>
|
||||
#include <rai/secure.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <rai/common.hpp>
|
||||
#include <rai/lib/interface.h>
|
||||
#include <rai/secure.hpp>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <rai/ledger.hpp>
|
||||
#include <rai/lib/work.hpp>
|
||||
#include <rai/node/bootstrap.hpp>
|
||||
#include <rai/node/wallet.hpp>
|
||||
|
|
|
@ -1,11 +1,29 @@
|
|||
#include <rai/node/utility.hpp>
|
||||
|
||||
#include <rai/lib/interface.h>
|
||||
#include <rai/node/utility.hpp>
|
||||
#include <rai/node/working.hpp>
|
||||
|
||||
#include <lmdb/libraries/liblmdb/lmdb.h>
|
||||
|
||||
#include <ed25519-donna/ed25519.h>
|
||||
|
||||
boost::filesystem::path rai::working_path ()
|
||||
{
|
||||
auto result (rai::app_path ());
|
||||
switch (rai::rai_network)
|
||||
{
|
||||
case rai::rai_networks::rai_test_network:
|
||||
result /= "RaiBlocksTest";
|
||||
break;
|
||||
case rai::rai_networks::rai_beta_network:
|
||||
result /= "RaiBlocksBeta";
|
||||
break;
|
||||
case rai::rai_networks::rai_live_network:
|
||||
result /= "RaiBlocks";
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
boost::filesystem::path rai::unique_path ()
|
||||
{
|
||||
auto result (working_path () / boost::filesystem::unique_path ());
|
||||
|
|
|
@ -98,6 +98,9 @@ bool fetch_object (T & object, boost::filesystem::path const & path_a, std::fstr
|
|||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* RAII wrapper for MDB_env
|
||||
*/
|
||||
class mdb_env
|
||||
{
|
||||
public:
|
||||
|
@ -106,6 +109,10 @@ public:
|
|||
operator MDB_env * () const;
|
||||
MDB_env * environment;
|
||||
};
|
||||
|
||||
/**
|
||||
* Encapsulates MDB_val and provides uint256_union conversion of the data.
|
||||
*/
|
||||
class mdb_val
|
||||
{
|
||||
public:
|
||||
|
@ -121,6 +128,11 @@ public:
|
|||
operator MDB_val const & () const;
|
||||
MDB_val value;
|
||||
};
|
||||
|
||||
/**
|
||||
* RAII wrapper of MDB_txn where the constructor starts the transaction
|
||||
* and the destructor commits it.
|
||||
*/
|
||||
class transaction
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <rai/blockstore.hpp>
|
||||
#include <rai/common.hpp>
|
||||
#include <rai/node/common.hpp>
|
||||
#include <rai/node/openclwork.hpp>
|
||||
#include <rai/secure.hpp>
|
||||
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <rai/secure.hpp>
|
||||
#include <rai/common.hpp>
|
||||
|
||||
namespace rai
|
||||
{
|
||||
boost::filesystem::path app_path ();
|
||||
}
|
||||
}
|
||||
|
|
2720
rai/secure.cpp
2720
rai/secure.cpp
File diff suppressed because it is too large
Load diff
410
rai/secure.hpp
410
rai/secure.hpp
|
@ -1,410 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <rai/lib/blocks.hpp>
|
||||
#include <rai/node/utility.hpp>
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <blake2/blake2.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <>
|
||||
struct hash<rai::uint256_union>
|
||||
{
|
||||
size_t operator() (rai::uint256_union const & value_a) const
|
||||
{
|
||||
std::hash<rai::uint256_union> hash;
|
||||
return hash (value_a);
|
||||
}
|
||||
};
|
||||
}
|
||||
namespace rai
|
||||
{
|
||||
class keypair
|
||||
{
|
||||
public:
|
||||
keypair ();
|
||||
keypair (std::string const &);
|
||||
rai::public_key pub;
|
||||
rai::raw_key prv;
|
||||
};
|
||||
class shared_ptr_block_hash
|
||||
{
|
||||
public:
|
||||
size_t operator() (std::shared_ptr<rai::block> const &) const;
|
||||
bool operator() (std::shared_ptr<rai::block> const &, std::shared_ptr<rai::block> const &) const;
|
||||
};
|
||||
std::unique_ptr<rai::block> deserialize_block (MDB_val const &);
|
||||
// Latest information about an account
|
||||
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);
|
||||
void serialize (rai::stream &) const;
|
||||
bool deserialize (rai::stream &);
|
||||
bool operator== (rai::account_info const &) const;
|
||||
bool operator!= (rai::account_info const &) const;
|
||||
rai::mdb_val val () const;
|
||||
rai::block_hash head;
|
||||
rai::block_hash rep_block;
|
||||
rai::block_hash open_block;
|
||||
rai::amount balance;
|
||||
/** Seconds since posix epoch */
|
||||
uint64_t modified;
|
||||
uint64_t block_count;
|
||||
};
|
||||
class store_entry
|
||||
{
|
||||
public:
|
||||
store_entry ();
|
||||
void clear ();
|
||||
store_entry * operator-> ();
|
||||
rai::mdb_val first;
|
||||
rai::mdb_val second;
|
||||
};
|
||||
class store_iterator
|
||||
{
|
||||
public:
|
||||
store_iterator (MDB_txn *, MDB_dbi);
|
||||
store_iterator (std::nullptr_t);
|
||||
store_iterator (MDB_txn *, MDB_dbi, MDB_val const &);
|
||||
store_iterator (rai::store_iterator &&);
|
||||
store_iterator (rai::store_iterator const &) = delete;
|
||||
~store_iterator ();
|
||||
rai::store_iterator & operator++ ();
|
||||
void next_dup ();
|
||||
rai::store_iterator & operator= (rai::store_iterator &&);
|
||||
rai::store_iterator & operator= (rai::store_iterator const &) = delete;
|
||||
rai::store_entry & operator-> ();
|
||||
bool operator== (rai::store_iterator const &) const;
|
||||
bool operator!= (rai::store_iterator const &) const;
|
||||
MDB_cursor * cursor;
|
||||
rai::store_entry current;
|
||||
};
|
||||
// Information on an uncollected send, source account, amount, target account.
|
||||
class pending_info
|
||||
{
|
||||
public:
|
||||
pending_info ();
|
||||
pending_info (MDB_val const &);
|
||||
pending_info (rai::account const &, rai::amount const &);
|
||||
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;
|
||||
};
|
||||
class pending_key
|
||||
{
|
||||
public:
|
||||
pending_key (rai::account const &, rai::block_hash const &);
|
||||
pending_key (MDB_val const &);
|
||||
void serialize (rai::stream &) const;
|
||||
bool deserialize (rai::stream &);
|
||||
bool operator== (rai::pending_key const &) const;
|
||||
rai::mdb_val val () const;
|
||||
rai::account account;
|
||||
rai::block_hash hash;
|
||||
};
|
||||
class block_info
|
||||
{
|
||||
public:
|
||||
block_info ();
|
||||
block_info (MDB_val const &);
|
||||
block_info (rai::account const &, rai::amount const &);
|
||||
void serialize (rai::stream &) const;
|
||||
bool deserialize (rai::stream &);
|
||||
bool operator== (rai::block_info const &) const;
|
||||
rai::mdb_val val () const;
|
||||
rai::account account;
|
||||
rai::amount balance;
|
||||
};
|
||||
class block_counts
|
||||
{
|
||||
public:
|
||||
block_counts ();
|
||||
size_t sum ();
|
||||
size_t send;
|
||||
size_t receive;
|
||||
size_t open;
|
||||
size_t change;
|
||||
};
|
||||
class vote
|
||||
{
|
||||
public:
|
||||
vote () = default;
|
||||
vote (rai::vote const &);
|
||||
vote (bool &, rai::stream &);
|
||||
vote (bool &, rai::stream &, rai::block_type);
|
||||
vote (rai::account const &, rai::raw_key const &, uint64_t, std::shared_ptr<rai::block>);
|
||||
vote (MDB_val const &);
|
||||
rai::uint256_union hash () const;
|
||||
bool operator== (rai::vote const &) const;
|
||||
bool operator!= (rai::vote const &) const;
|
||||
void serialize (rai::stream &, rai::block_type);
|
||||
void serialize (rai::stream &);
|
||||
std::string to_json () const;
|
||||
// Vote round sequence number
|
||||
uint64_t sequence;
|
||||
std::shared_ptr<rai::block> block;
|
||||
// Account that's voting
|
||||
rai::account account;
|
||||
// Signature of sequence + block hash
|
||||
rai::signature signature;
|
||||
};
|
||||
enum class vote_code
|
||||
{
|
||||
invalid, // Vote is not signed correctly
|
||||
replay, // Vote does not have the highest sequence number, it's a replay
|
||||
vote // Vote has the highest sequence number
|
||||
};
|
||||
class vote_result
|
||||
{
|
||||
public:
|
||||
rai::vote_code code;
|
||||
std::shared_ptr<rai::vote> vote;
|
||||
};
|
||||
class block_store
|
||||
{
|
||||
public:
|
||||
block_store (bool &, boost::filesystem::path const &, int lmdb_max_dbs = 128);
|
||||
|
||||
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));
|
||||
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 &);
|
||||
std::unique_ptr<rai::block> block_get (MDB_txn *, rai::block_hash const &);
|
||||
std::unique_ptr<rai::block> block_random (MDB_txn *);
|
||||
std::unique_ptr<rai::block> block_random (MDB_txn *, MDB_dbi);
|
||||
void block_del (MDB_txn *, rai::block_hash const &);
|
||||
bool block_exists (MDB_txn *, rai::block_hash const &);
|
||||
rai::block_counts block_count (MDB_txn *);
|
||||
std::unordered_multimap<rai::block_hash, rai::block_hash> block_dependencies (MDB_txn *);
|
||||
|
||||
void frontier_put (MDB_txn *, rai::block_hash const &, rai::account const &);
|
||||
rai::account frontier_get (MDB_txn *, rai::block_hash const &);
|
||||
void frontier_del (MDB_txn *, rai::block_hash const &);
|
||||
size_t frontier_count (MDB_txn *);
|
||||
|
||||
void account_put (MDB_txn *, rai::account const &, rai::account_info const &);
|
||||
bool account_get (MDB_txn *, rai::account const &, rai::account_info &);
|
||||
void account_del (MDB_txn *, rai::account const &);
|
||||
bool account_exists (MDB_txn *, rai::account const &);
|
||||
rai::store_iterator latest_begin (MDB_txn *, rai::account const &);
|
||||
rai::store_iterator latest_begin (MDB_txn *);
|
||||
rai::store_iterator latest_end ();
|
||||
|
||||
void pending_put (MDB_txn *, rai::pending_key const &, rai::pending_info const &);
|
||||
void pending_del (MDB_txn *, rai::pending_key const &);
|
||||
bool pending_get (MDB_txn *, rai::pending_key const &, rai::pending_info &);
|
||||
bool pending_exists (MDB_txn *, rai::pending_key const &);
|
||||
rai::store_iterator pending_begin (MDB_txn *, rai::pending_key const &);
|
||||
rai::store_iterator pending_begin (MDB_txn *);
|
||||
rai::store_iterator pending_end ();
|
||||
|
||||
void block_info_put (MDB_txn *, rai::block_hash const &, rai::block_info const &);
|
||||
void block_info_del (MDB_txn *, rai::block_hash const &);
|
||||
bool block_info_get (MDB_txn *, rai::block_hash const &, rai::block_info &);
|
||||
bool block_info_exists (MDB_txn *, rai::block_hash const &);
|
||||
rai::store_iterator block_info_begin (MDB_txn *, rai::block_hash const &);
|
||||
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 &);
|
||||
static size_t const block_info_max = 32;
|
||||
|
||||
rai::uint128_t representation_get (MDB_txn *, rai::account const &);
|
||||
void representation_put (MDB_txn *, rai::account const &, rai::uint128_t const &);
|
||||
void representation_add (MDB_txn *, rai::account const &, rai::uint128_t const &);
|
||||
rai::store_iterator representation_begin (MDB_txn *);
|
||||
rai::store_iterator representation_end ();
|
||||
|
||||
void unchecked_clear (MDB_txn *);
|
||||
void unchecked_put (MDB_txn *, rai::block_hash const &, std::shared_ptr<rai::block> const &);
|
||||
std::vector<std::shared_ptr<rai::block>> unchecked_get (MDB_txn *, rai::block_hash const &);
|
||||
void unchecked_del (MDB_txn *, rai::block_hash const &, rai::block const &);
|
||||
rai::store_iterator unchecked_begin (MDB_txn *);
|
||||
rai::store_iterator unchecked_begin (MDB_txn *, rai::block_hash const &);
|
||||
rai::store_iterator unchecked_end ();
|
||||
size_t unchecked_count (MDB_txn *);
|
||||
std::unordered_multimap<rai::block_hash, std::shared_ptr<rai::block>> unchecked_cache;
|
||||
|
||||
void unsynced_put (MDB_txn *, rai::block_hash const &);
|
||||
void unsynced_del (MDB_txn *, rai::block_hash const &);
|
||||
bool unsynced_exists (MDB_txn *, rai::block_hash const &);
|
||||
rai::store_iterator unsynced_begin (MDB_txn *, rai::block_hash const &);
|
||||
rai::store_iterator unsynced_begin (MDB_txn *);
|
||||
rai::store_iterator unsynced_end ();
|
||||
|
||||
void checksum_put (MDB_txn *, uint64_t, uint8_t, rai::checksum const &);
|
||||
bool checksum_get (MDB_txn *, uint64_t, uint8_t, rai::checksum &);
|
||||
void checksum_del (MDB_txn *, uint64_t, uint8_t);
|
||||
|
||||
rai::vote_result vote_validate (MDB_txn *, std::shared_ptr<rai::vote>);
|
||||
// Return latest vote for an account from store
|
||||
std::shared_ptr<rai::vote> vote_get (MDB_txn *, rai::account const &);
|
||||
// Populate vote with the next sequence number
|
||||
std::shared_ptr<rai::vote> vote_generate (MDB_txn *, rai::account const &, rai::raw_key const &, std::shared_ptr<rai::block>);
|
||||
// Return either vote or the stored vote with a higher sequence number
|
||||
std::shared_ptr<rai::vote> vote_max (MDB_txn *, std::shared_ptr<rai::vote>);
|
||||
// Return latest vote for an account considering the vote cache
|
||||
std::shared_ptr<rai::vote> vote_current (MDB_txn *, rai::account const &);
|
||||
void flush (MDB_txn *);
|
||||
rai::store_iterator vote_begin (MDB_txn *);
|
||||
rai::store_iterator vote_end ();
|
||||
std::mutex cache_mutex;
|
||||
std::unordered_map<rai::account, std::shared_ptr<rai::vote>> vote_cache;
|
||||
|
||||
void version_put (MDB_txn *, int);
|
||||
int version_get (MDB_txn *);
|
||||
void do_upgrades (MDB_txn *);
|
||||
void upgrade_v1_to_v2 (MDB_txn *);
|
||||
void upgrade_v2_to_v3 (MDB_txn *);
|
||||
void upgrade_v3_to_v4 (MDB_txn *);
|
||||
void upgrade_v4_to_v5 (MDB_txn *);
|
||||
void upgrade_v5_to_v6 (MDB_txn *);
|
||||
void upgrade_v6_to_v7 (MDB_txn *);
|
||||
void upgrade_v7_to_v8 (MDB_txn *);
|
||||
void upgrade_v8_to_v9 (MDB_txn *);
|
||||
void upgrade_v9_to_v10 (MDB_txn *);
|
||||
|
||||
void clear (MDB_dbi);
|
||||
|
||||
rai::mdb_env environment;
|
||||
// block_hash -> account // Maps head blocks to owning account
|
||||
MDB_dbi frontiers;
|
||||
// account -> block_hash, representative, balance, timestamp // Account to head block, representative, balance, last_change
|
||||
MDB_dbi accounts;
|
||||
// block_hash -> send_block
|
||||
MDB_dbi send_blocks;
|
||||
// block_hash -> receive_block
|
||||
MDB_dbi receive_blocks;
|
||||
// block_hash -> open_block
|
||||
MDB_dbi open_blocks;
|
||||
// block_hash -> change_block
|
||||
MDB_dbi change_blocks;
|
||||
// block_hash -> sender, amount, destination // Pending blocks to sender account, amount, destination account
|
||||
MDB_dbi pending;
|
||||
// block_hash -> account, balance // Blocks info
|
||||
MDB_dbi blocks_info;
|
||||
// account -> weight // Representation
|
||||
MDB_dbi representation;
|
||||
// block_hash -> block // Unchecked bootstrap blocks
|
||||
MDB_dbi unchecked;
|
||||
// block_hash -> // Blocks that haven't been broadcast
|
||||
MDB_dbi unsynced;
|
||||
// (uint56_t, uint8_t) -> block_hash // Mapping of region to checksum
|
||||
MDB_dbi checksum;
|
||||
// account -> uint64_t // Highest vote observed for account
|
||||
MDB_dbi vote;
|
||||
// uint256_union -> ? // Meta information about block store
|
||||
MDB_dbi meta;
|
||||
};
|
||||
enum class process_result
|
||||
{
|
||||
progress, // Hasn't been seen before, signed correctly
|
||||
bad_signature, // Signature was bad, forged or transmission error
|
||||
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
|
||||
gap_previous, // Block marked as previous is unknown
|
||||
gap_source, // Block marked as source is unknown
|
||||
not_receive_from_send, // Receive does not have a send source
|
||||
account_mismatch, // Account number in open block doesn't match send destination
|
||||
opened_burn_account // The impossible happened, someone found the private key associated with the public key '0'.
|
||||
};
|
||||
class process_return
|
||||
{
|
||||
public:
|
||||
rai::process_result code;
|
||||
rai::account account;
|
||||
rai::amount amount;
|
||||
rai::account pending_account;
|
||||
};
|
||||
enum class tally_result
|
||||
{
|
||||
vote,
|
||||
changed,
|
||||
confirm
|
||||
};
|
||||
class votes
|
||||
{
|
||||
public:
|
||||
votes (std::shared_ptr<rai::block>);
|
||||
rai::tally_result vote (std::shared_ptr<rai::vote>);
|
||||
// Root block of fork
|
||||
rai::block_hash id;
|
||||
// All votes received by account
|
||||
std::unordered_map<rai::account, std::shared_ptr<rai::block>> rep_votes;
|
||||
};
|
||||
class ledger
|
||||
{
|
||||
public:
|
||||
ledger (rai::block_store &, rai::uint128_t 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
|
||||
std::map<rai::uint128_t, std::shared_ptr<rai::block>, std::greater<rai::uint128_t>> tally (MDB_txn *, rai::votes const &);
|
||||
rai::account account (MDB_txn *, rai::block_hash const &);
|
||||
rai::uint128_t amount (MDB_txn *, rai::block_hash const &);
|
||||
rai::uint128_t balance (MDB_txn *, rai::block_hash const &);
|
||||
rai::uint128_t account_balance (MDB_txn *, rai::account const &);
|
||||
rai::uint128_t account_pending (MDB_txn *, rai::account const &);
|
||||
rai::uint128_t weight (MDB_txn *, rai::account const &);
|
||||
std::unique_ptr<rai::block> successor (MDB_txn *, rai::block_hash const &);
|
||||
std::unique_ptr<rai::block> forked_block (MDB_txn *, rai::block const &);
|
||||
rai::block_hash latest (MDB_txn *, rai::account const &);
|
||||
rai::block_hash latest_root (MDB_txn *, rai::account const &);
|
||||
rai::block_hash representative (MDB_txn *, rai::block_hash const &);
|
||||
rai::block_hash representative_calculated (MDB_txn *, rai::block_hash const &);
|
||||
bool block_exists (rai::block_hash const &);
|
||||
std::string block_text (char const *);
|
||||
std::string block_text (rai::block_hash const &);
|
||||
rai::uint128_t supply (MDB_txn *);
|
||||
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);
|
||||
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 &);
|
||||
static rai::uint128_t const unit;
|
||||
rai::block_store & store;
|
||||
rai::uint128_t inactive_supply;
|
||||
std::unordered_map<rai::account, rai::uint128_t> bootstrap_weights;
|
||||
uint64_t bootstrap_weight_max_blocks;
|
||||
std::atomic<bool> check_bootstrap_weights;
|
||||
};
|
||||
extern rai::keypair const & zero_key;
|
||||
extern rai::keypair const & test_genesis_key;
|
||||
extern rai::account const & rai_test_account;
|
||||
extern rai::account const & rai_beta_account;
|
||||
extern rai::account const & rai_live_account;
|
||||
extern std::string const & rai_test_genesis;
|
||||
extern std::string const & rai_beta_genesis;
|
||||
extern std::string const & rai_live_genesis;
|
||||
extern std::string const & genesis_block;
|
||||
extern rai::account const & genesis_account;
|
||||
extern rai::account const & burn_account;
|
||||
extern rai::uint128_t const & genesis_amount;
|
||||
// A block hash that compares inequal to any real block hash
|
||||
extern rai::block_hash const & not_a_block;
|
||||
// An account number that compares inequal to any real account number
|
||||
extern rai::block_hash const & not_an_account;
|
||||
class genesis
|
||||
{
|
||||
public:
|
||||
explicit genesis ();
|
||||
void initialize (MDB_txn *, rai::block_store &) const;
|
||||
rai::block_hash hash () const;
|
||||
std::unique_ptr<rai::open_block> open;
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue