Electroneum
Loading...
Searching...
No Matches
cryptonote::Blockchain Class Reference

#include <blockchain.h>

Classes

struct  transaction_chain_entry
 Now-defunct (TODO: remove) struct from in-memory blockchain. More...
struct  block_extended_info
 container for passing a block and metadata about it on the blockchain More...

Public Member Functions

 Blockchain (tx_memory_pool &tx_pool)
 Blockchain constructor.
 ~Blockchain ()
 Blockchain destructor.
bool init (BlockchainDB *db, const network_type nettype=MAINNET, bool offline=false, const cryptonote::test_options *test_options=NULL, difficulty_type fixed_difficulty=0, const GetCheckpointsCallback &get_checkpoints=nullptr, bool ignore_bsig=false, bool fallback_to_pow=false)
 Initialize the Blockchain state.
bool init (BlockchainDB *db, HardFork *&hf, const network_type nettype=MAINNET, bool offline=false)
 Initialize the Blockchain state.
bool deinit ()
 Uninitializes the blockchain state.
void set_checkpoints (checkpoints &&chk_pts)
 assign a set of blockchain checkpoint hashes
bool get_blocks (uint64_t start_offset, size_t count, std::vector< std::pair< cryptonote::blobdata, block > > &blocks, std::vector< cryptonote::blobdata > &txs) const
 get blocks and transactions from blocks based on start height and count
bool get_blocks (uint64_t start_offset, size_t count, std::vector< std::pair< cryptonote::blobdata, block > > &blocks) const
 get blocks from blocks based on start height and count
bool get_alternative_blocks (std::vector< block > &blocks) const
 compiles a list of all blocks stored as alternative chains
size_t get_alternative_blocks_count () const
 returns the number of alternative blocks stored
crypto::hash get_block_id_by_height (uint64_t height) const
 gets a block's hash given a height
bool get_block_by_hash (const crypto::hash &h, block &blk, bool *orphan=NULL) const
 gets the block with a given hash
bool prepare_handle_incoming_blocks (const std::vector< block_complete_entry > &blocks_entry, std::vector< block > &blocks)
 performs some preprocessing on a group of incoming blocks to speed up verification
bool cleanup_handle_incoming_blocks (bool force_sync=false)
 incoming blocks post-processing, cleanup, and disk sync
bool have_tx (const crypto::hash &id) const
 search the blockchain for a transaction by hash
bool key_images_already_spent (const transaction &tx) const
 check if any key image in a transaction has already been spent
bool utxo_nonexistence_from_output (const txin_to_key_public &public_output) const
 check if a single utxo in a transaction has already been spent using the hash and out index (v3 tx onwards)
bool utxo_nonexistent (const transaction &tx) const
 check if any utxo in a transaction has already been spent using the tx (v3 tx onwards)
bool have_tx_keyimg_as_spent (const crypto::key_image &key_im) const
 check if a key image is already spent on the blockchain
uint64_t get_current_blockchain_height () const
 get the current height of the blockchain
crypto::hash get_tail_id () const
 get the hash of the most recent block on the blockchain
crypto::hash get_tail_id (uint64_t &height) const
 get the height and hash of the most recent block on the blockchain
difficulty_type get_difficulty_for_next_block ()
 returns the difficulty target the next block to be added must meet
void normalize_v7_difficulties ()
 Normalize the cumulative difficulty for V7 blocks, fixing the differing difficulty among nodes.
bool add_new_block (const block &bl_, block_verification_context &bvc)
 adds a block to the blockchain
bool reset_and_set_genesis_block (const block &b)
 clears the blockchain and starts a new one
bool create_block_template (block &b, const account_public_address &miner_address, difficulty_type &di, uint64_t &height, uint64_t &expected_reward, const blobdata &ex_nonce)
 creates a new block to mine against
bool create_block_template (block &b, const crypto::hash *from_block, const account_public_address &miner_address, difficulty_type &di, uint64_t &height, uint64_t &expected_reward, const blobdata &ex_nonce)
bool have_block (const crypto::hash &id) const
 checks if a block is known about with a given hash
size_t get_total_transactions () const
 gets the total number of transactions on the main chain
bool get_short_chain_history (std::list< crypto::hash > &ids) const
 gets the hashes for a subset of the blockchain
bool find_blockchain_supplement (const std::list< crypto::hash > &qblock_ids, std::vector< crypto::hash > &hashes, uint64_t &start_height, uint64_t &current_height, bool clip_pruned) const
 get recent block hashes for a foreign chain
bool find_blockchain_supplement (const std::list< crypto::hash > &qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request &resp) const
 get recent block hashes for a foreign chain
bool find_blockchain_supplement (const std::list< crypto::hash > &qblock_ids, uint64_t &starter_offset) const
 find the most recent common point between ours and a foreign chain
bool find_blockchain_supplement (const uint64_t req_start_block, const std::list< crypto::hash > &qblock_ids, std::vector< std::pair< std::pair< cryptonote::blobdata, crypto::hash >, std::vector< std::pair< crypto::hash, cryptonote::blobdata > > > > &blocks, uint64_t &total_height, uint64_t &start_height, bool pruned, bool get_miner_tx_hash, size_t max_count) const
 get recent blocks for a foreign chain
bool handle_get_objects (NOTIFY_REQUEST_GET_OBJECTS::request &arg, NOTIFY_RESPONSE_GET_OBJECTS::request &rsp)
 retrieves a set of blocks and their transactions, and possibly other transactions
uint64_t get_num_mature_outputs (uint64_t amount) const
 get number of outputs of an amount past the minimum spendable age
crypto::public_key get_output_key (uint64_t amount, uint64_t global_index) const
 get the public key for an output
bool get_outs (const COMMAND_RPC_GET_OUTPUTS_BIN::request &req, COMMAND_RPC_GET_OUTPUTS_BIN::response &res) const
 gets specific outputs to mix with
void get_output_key_mask_unlocked (const uint64_t &amount, const uint64_t &index, crypto::public_key &key, rct::key &mask, bool &unlocked) const
 gets an output's key and unlocked state
bool get_output_distribution (uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector< uint64_t > &distribution, uint64_t &base) const
 gets per block distribution of outputs of a given amount
bool get_tx_outputs_gindexs (const crypto::hash &tx_id, std::vector< uint64_t > &indexs) const
 gets the global indices for outputs from a given transaction
bool get_tx_outputs_gindexs (const crypto::hash &tx_id, size_t n_txes, std::vector< std::vector< uint64_t > > &indexs) const
bool store_blockchain ()
 stores the blockchain
bool check_tx_inputs (transaction &tx, uint64_t &pmax_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block=false)
 validates a transaction's inputs
uint64_t get_dynamic_base_fee_estimate (uint64_t grace_blocks) const
 get dynamic per kB or byte fee estimate for the next few blocks
bool check_fee (size_t tx_weight, uint64_t fee) const
 validate a transaction's fee
bool check_tx_outputs (const transaction &tx, tx_verification_context &tvc)
 check that a transaction's outputs conform to current standards
uint64_t get_current_cumulative_block_weight_limit () const
 gets the block weight limit based on recent blocks
uint64_t get_next_long_term_block_weight (uint64_t block_weight) const
 gets the long term block weight for a new block
uint64_t get_current_cumulative_block_weight_median () const
 gets the block weight median based on recent blocks (same window as for the limit)
difficulty_type block_difficulty (uint64_t i) const
 gets the difficulty of the block with a given height
template<class t_ids_container, class t_blocks_container, class t_missed_container>
bool get_blocks (const t_ids_container &block_ids, t_blocks_container &blocks, t_missed_container &missed_bs) const
 gets blocks based on a list of block hashes
template<class t_ids_container, class t_tx_container, class t_missed_container>
bool get_transactions_blobs (const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs, bool pruned=false) const
 gets transactions based on a list of transaction hashes
template<class t_ids_container, class t_tx_container, class t_missed_container>
bool get_split_transactions_blobs (const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs) const
template<class t_ids_container, class t_tx_container, class t_missed_container>
bool get_transactions (const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs) const
void check_against_checkpoints (const checkpoints &points, bool enforce)
 check the blockchain against a set of checkpoints
void set_enforce_dns_checkpoints (bool enforce)
 configure whether or not to enforce DNS-based checkpoints
bool update_checkpoints (const std::string &file_path, bool check_dns)
 loads new checkpoints from a file and optionally from DNS
void set_user_options (uint64_t maxthreads, bool sync_on_blocks, uint64_t sync_threshold, blockchain_db_sync_mode sync_mode, bool fast_sync, std::string validator_key)
 Update the validators public key by fetching data from electroneum's endpoint.
void set_block_notify (const std::shared_ptr< tools::Notify > &notify)
 sets a block notify object to call for every new block
void set_reorg_notify (const std::shared_ptr< tools::Notify > &notify)
 sets a reorg notify object to call for every reorg
void safesyncmode (const bool onoff)
 Put DB in safe sync mode.
void set_show_time_stats (bool stats)
 set whether or not to show/print time statistics
HardFork::State get_hard_fork_state () const
 gets the hardfork voting state object
uint8_t get_current_hard_fork_version () const
 gets the current hardfork version in use/voted for
uint8_t get_ideal_hard_fork_version () const
 returns the newest hardfork version known to the blockchain
uint8_t get_next_hard_fork_version () const
 returns the next hardfork version
uint8_t get_ideal_hard_fork_version (uint64_t height) const
 returns the newest hardfork version voted to be enabled as of a certain height
uint8_t get_hard_fork_version (uint64_t height) const
 returns the actual hardfork version for a given block height
uint64_t get_earliest_ideal_height_for_version (uint8_t version) const
 returns the earliest block a given version may activate
bool get_hard_fork_voting_info (uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
 get information about hardfork voting for a version
uint64_t get_difficulty_target () const
 get difficulty target based on chain and hardfork version
bool flush_txes_from_pool (const std::vector< crypto::hash > &txids)
 remove transactions from the transaction pool (if present)
std::map< uint64_t, std::tuple< uint64_t, uint64_t, uint64_t > > get_output_histogram (const std::vector< uint64_t > &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count=0) const
 return a histogram of outputs on the blockchain
bool for_all_key_images (std::function< bool(const crypto::key_image &)>) const
 perform a check on all key images in the blockchain
bool for_blocks_range (const uint64_t &h1, const uint64_t &h2, std::function< bool(uint64_t, const crypto::hash &, const block &)>) const
 perform a check on all blocks in the blockchain in the given range
bool for_all_transactions (std::function< bool(const crypto::hash &, const cryptonote::transaction &)>, bool pruned) const
 perform a check on all transactions in the blockchain
bool for_all_outputs (std::function< bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)>) const
 perform a check on all outputs in the blockchain
bool for_all_outputs (uint64_t amount, std::function< bool(uint64_t height)>) const
 perform a check on all outputs of a given amount in the blockchain
const BlockchainDBget_db () const
 get a reference to the BlockchainDB in use by Blockchain
BlockchainDBget_db ()
 get a reference to the BlockchainDB in use by Blockchain
void output_scan_worker (const uint64_t amount, const std::vector< uint64_t > &offsets, std::vector< output_data_t > &outputs) const
 get a number of outputs of a specific amount
void block_longhash_worker (uint64_t height, const epee::span< const block > &blocks, std::unordered_map< crypto::hash, crypto::hash > &map) const
 computes the "short" and "long" hashes for a set of blocks
std::list< std::pair< block_extended_info, std::vector< crypto::hash > > > get_alternative_chains () const
 returns a set of known alternate chains
void add_txpool_tx (const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta)
void update_txpool_tx (const crypto::hash &txid, const txpool_tx_meta_t &meta)
void remove_txpool_tx (const crypto::hash &txid)
uint64_t get_txpool_tx_count (bool include_unrelayed_txes=true) const
bool get_txpool_tx_meta (const crypto::hash &txid, txpool_tx_meta_t &meta) const
bool get_txpool_tx_blob (const crypto::hash &txid, cryptonote::blobdata &bd) const
cryptonote::blobdata get_txpool_tx_blob (const crypto::hash &txid) const
bool for_all_txpool_txes (std::function< bool(const crypto::hash &, const txpool_tx_meta_t &, const cryptonote::blobdata *)>, bool include_blob=false, bool include_unrelayed_txes=true) const
uint32_t get_mempool_tx_livetime () const
bool is_within_compiled_block_hash_area (uint64_t height) const
bool is_within_compiled_block_hash_area () const
uint32_t get_blockchain_pruning_seed () const
bool prune_blockchain (uint32_t pruning_seed=0)
bool update_blockchain_pruning ()
bool check_blockchain_pruning ()
void lock ()
void unlock ()
void cancel ()
void on_new_tx_from_block (const cryptonote::transaction &tx)
 called when we see a tx originating from a block
std::vector< time_t > get_last_block_timestamps (unsigned int blocks) const
 returns the timestamps of the last N blocks
void pop_blocks (uint64_t nblocks)
 removes blocks from the top of the blockchain
void sign_block (block &b, std::string privateKey)
 Digitally sign the block.
bool verify_block_signature (const block &b)
 Verify block's digital signature.
void set_validator_key (std::string key)
 set validator key
void set_validators_list_instance (std::unique_ptr< electroneum::basic::Validators > &v)
electroneum::basic::Validator get_validator_by_height (uint64_t height)
network_type get_nettype () const
 get blockchain nettype
template<class t_ids_container, class t_tx_container, class t_missed_container>
bool get_transactions_blobs (const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs, bool pruned) const

Static Public Member Functions

static uint64_t get_fee_quantization_mask ()
 get fee quantization mask
static uint64_t get_dynamic_base_fee (uint64_t block_reward, size_t median_block_weight, uint8_t version)
 get dynamic per kB or byte fee for a given block weight
static const std::vector< HardFork::Params > & get_hard_fork_heights (network_type nettype)
 gets the hardfork heights of given network

Detailed Description

Definition at line 97 of file blockchain.h.

Constructor & Destructor Documentation

◆ Blockchain()

Blockchain::Blockchain ( tx_memory_pool & tx_pool)

Blockchain constructor.

Parameters
tx_poola reference to the transaction pool to be kept by the Blockchain

Definition at line 146 of file blockchain.cpp.

146 :
147 m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_weight_limit(0), m_current_block_cumul_weight_median(0),
148 m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_sync_on_blocks(true), m_db_sync_threshold(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_bytes_to_sync(0), m_cancel(false),
149 m_long_term_block_weights_window(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
150 m_long_term_effective_median_block_weight(0),
151 m_long_term_block_weights_cache_tip_hash(crypto::null_hash),
152 m_long_term_block_weights_cache_rolling_median(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
153 m_difficulty_for_next_block_top_hash(crypto::null_hash),
154 m_difficulty_for_next_block(1),
155 m_btc_valid(false),
156 m_batch_success(true)
157{
158 LOG_PRINT_L3("Blockchain::" << __func__);
159}
#define CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE
#define LOG_PRINT_L3(x)
@ db_async
handle syncing calls instead of the backing db, asynchronously
Definition blockchain.h:81

◆ ~Blockchain()

Blockchain::~Blockchain ( )

Blockchain destructor.

Definition at line 161 of file blockchain.cpp.

162{
163 try { deinit(); }
164 catch (const std::exception &e) { /* ignore */ }
165}
bool deinit()
Uninitializes the blockchain state.
Here is the call graph for this function:

Member Function Documentation

◆ add_new_block()

bool Blockchain::add_new_block ( const block & bl_,
block_verification_context & bvc )

adds a block to the blockchain

Adds a new block to the blockchain. If the block's parent is not the current top of the blockchain, the block may be added to an alternate chain. If the block does not belong, is already in the blockchain or an alternate chain, or is invalid, return false.

Parameters
bl_the block to be added
bvcmetadata about the block addition's success/failure
Returns
true on successful addition to the blockchain, else false

Definition at line 4196 of file blockchain.cpp.

4197{
4198 LOG_PRINT_L3("Blockchain::" << __func__);
4200 CRITICAL_REGION_LOCAL(m_tx_pool);//to avoid deadlock lets lock tx_pool for whole add/reorganize process
4201 CRITICAL_REGION_LOCAL1(m_blockchain_lock);
4202 db_rtxn_guard rtxn_guard(m_db);
4203 if(have_block(id))
4204 {
4205 LOG_PRINT_L3("block with id = " << id << " already exists");
4206 bvc.m_already_exists = true;
4207 m_blocks_txs_check.clear();
4208 return false;
4209 }
4210
4211 //check that block refers to chain tail
4212 if(!(bl.prev_id == get_tail_id()))
4213 {
4214 //chain switching or wrong block
4215 bvc.m_added_to_main_chain = false;
4216 rtxn_guard.stop();
4217 bool r = handle_alternative_block(bl, id, bvc);
4218 m_blocks_txs_check.clear();
4219 return r;
4220 //never relay alternative blocks
4221 }
4222
4223 rtxn_guard.stop();
4224 return handle_block_to_main_chain(bl, id, bvc);
4225}
crypto::hash get_tail_id() const
get the hash of the most recent block on the blockchain
bool have_block(const crypto::hash &id) const
checks if a block is known about with a given hash
POD_CLASS hash
Definition hash.h:50
bool get_block_hash(const block &b, crypto::hash &res)
#define CRITICAL_REGION_LOCAL1(x)
Definition syncobj.h:230
#define CRITICAL_REGION_LOCAL(x)
Definition syncobj.h:228
Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_txpool_tx()

void Blockchain::add_txpool_tx ( const crypto::hash & txid,
const cryptonote::blobdata & blob,
const txpool_tx_meta_t & meta )

Definition at line 4768 of file blockchain.cpp.

4769{
4770 m_db->add_txpool_tx(txid, blob, meta);
4771}

◆ block_difficulty()

difficulty_type Blockchain::block_difficulty ( uint64_t i) const

gets the difficulty of the block with a given height

Parameters
ithe height
Returns
the difficulty

Definition at line 2403 of file blockchain.cpp.

2404{
2405 LOG_PRINT_L3("Blockchain::" << __func__);
2406 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
2407 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
2408 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
2409 // lock if it is otherwise needed.
2410 try
2411 {
2412 return m_db->get_block_difficulty(i);
2413 }
2414 catch (const BLOCK_DNE& e)
2415 {
2416 MERROR("Attempted to get block difficulty for height above blockchain height");
2417 }
2418 return 0;
2419}
#define MERROR(x)
Definition misc_log_ex.h:73

◆ block_longhash_worker()

void Blockchain::block_longhash_worker ( uint64_t height,
const epee::span< const block > & blocks,
std::unordered_map< crypto::hash, crypto::hash > & map ) const

computes the "short" and "long" hashes for a set of blocks

Parameters
heightthe height of the first block
blocksthe blocks to be hashed
mapreturn-by-reference the hashes for each block

Definition at line 4313 of file blockchain.cpp.

4314{
4317
4318 for (const auto & block : blocks)
4319 {
4320 if (m_cancel)
4321 break;
4322 crypto::hash id = get_block_hash(block);
4323 crypto::hash pow = get_block_longhash(block, height++);
4324 map.emplace(id, pow);
4325 }
4326
4329}
uint64_t height
void slow_hash_allocate_state()
void slow_hash_free_state()
bool get_block_longhash(const block &b, crypto::hash &res, uint64_t height)
#define TIME_MEASURE_FINISH(var_name)
#define TIME_MEASURE_START(var_name)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ cancel()

void Blockchain::cancel ( )

Definition at line 4933 of file blockchain.cpp.

4934{
4935 m_cancel = true;
4936}

◆ check_against_checkpoints()

void Blockchain::check_against_checkpoints ( const checkpoints & points,
bool enforce )

check the blockchain against a set of checkpoints

If a block fails a checkpoint and enforce is enabled, the blockchain will be rolled back to two blocks prior to that block. If enforce is disabled, as is currently the default case with DNS-based checkpoints, an error will be printed to the user but no other action will be taken.

Parameters
pointsthe checkpoints to check against
enforcewhether or not to take action on failure

Definition at line 4229 of file blockchain.cpp.

4230{
4231 const auto& pts = points.get_points();
4232 bool stop_batch;
4233
4234 CRITICAL_REGION_LOCAL(m_blockchain_lock);
4235 stop_batch = m_db->batch_start();
4236 const uint64_t blockchain_height = m_db->height();
4237 for (const auto& pt : pts)
4238 {
4239 // if the checkpoint is for a block we don't have yet, move on
4240 if (pt.first >= blockchain_height)
4241 {
4242 continue;
4243 }
4244
4245 if (!points.check_block(pt.first, m_db->get_block_hash_from_height(pt.first)))
4246 {
4247 // if asked to enforce checkpoints, roll back to a couple of blocks before the checkpoint
4248 if (enforce)
4249 {
4250 LOG_ERROR("Local blockchain failed to pass a checkpoint, rolling back!");
4251 std::list<block> empty;
4252 rollback_blockchain_switching(empty, pt.first - 2);
4253
4254 //Flush the txpool if we've just popped blocks due to failed checkpoint.
4255 std::vector<crypto::hash> txs;
4256 m_tx_pool.get_transaction_hashes(txs, true);
4258 }
4259 else
4260 {
4261 LOG_ERROR("WARNING: local blockchain failed to pass a ElectroneumPulse checkpoint, and you could be on a fork. You should either sync up from scratch, OR download a fresh blockchain bootstrap, OR enable checkpoint enforcing with the --enforce-dns-checkpointing command-line option");
4262 }
4263 }
4264 }
4265 if (stop_batch)
4266 m_db->batch_stop();
4267}
bool flush_txes_from_pool(const std::vector< crypto::hash > &txids)
remove transactions from the transaction pool (if present)
bool check_block(uint64_t height, const crypto::hash &h, bool &is_a_checkpoint) const
checks if the given height and hash agree with the checkpoints
const std::map< uint64_t, crypto::hash > & get_points() const
gets the checkpoints container
#define LOG_ERROR(x)
Definition misc_log_ex.h:98
unsigned __int64 uint64_t
Definition stdint.h:136
Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_blockchain_pruning()

bool Blockchain::check_blockchain_pruning ( )

Definition at line 4091 of file blockchain.cpp.

4092{
4093 m_tx_pool.lock();
4095 CRITICAL_REGION_LOCAL(m_blockchain_lock);
4096
4097 return m_db->check_pruning();
4098}
boost::shared_ptr< call_befor_die_base > auto_scope_leave_caller
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
Here is the call graph for this function:

◆ check_fee()

bool Blockchain::check_fee ( size_t tx_weight,
uint64_t fee ) const

validate a transaction's fee

This function validates the fee is enough for the transaction. This is based on the weight of the transaction, and, after a height threshold, on the average weight of transaction in a past window

Parameters
tx_weightthe transaction weight
feethe fee
Returns
true if the fee is enough, false otherwise

Definition at line 3385 of file blockchain.cpp.

3386{
3388 const uint64_t blockchain_height = m_db->height();
3389
3390 uint64_t median = 0;
3391 uint64_t already_generated_coins = 0;
3392 uint64_t base_reward = 0;
3394 {
3395 median = m_current_block_cumul_weight_limit / 2;
3396 const uint64_t blockchain_height = m_db->height();
3397 already_generated_coins = blockchain_height ? m_db->get_block_already_generated_coins(blockchain_height - 1) : 0;
3398 if (!get_block_reward(median, 1, already_generated_coins, base_reward, version, blockchain_height, get_nettype()))
3399 return false;
3400 }
3401
3402 uint64_t needed_fee;
3404 {
3405 const bool use_long_term_median_in_fee = version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT;
3406 uint64_t fee_per_byte = get_dynamic_base_fee(base_reward, use_long_term_median_in_fee ? m_long_term_effective_median_block_weight : median, version);
3407 MDEBUG("Using " << print_etn(fee_per_byte) << "/byte fee");
3408 needed_fee = tx_weight * fee_per_byte;
3409 // quantize fee up to 8 decimals
3410 const uint64_t mask = get_fee_quantization_mask();
3411 needed_fee = (needed_fee + mask - 1) / mask * mask;
3412 }
3413 else
3414 {
3415 uint64_t fee_per_kb;
3417 {
3418 if (version >= 11) {
3419 fee_per_kb = FEE_PER_KB_V11;
3420 } else if (version < 11 && version >= 6) {
3421 fee_per_kb = FEE_PER_KB_V6;
3422 } else {
3423 fee_per_kb = FEE_PER_KB;
3424 }
3425 }
3426 else
3427 {
3428 fee_per_kb = get_dynamic_base_fee(base_reward, median, version);
3429 }
3430 MDEBUG("Using " << print_etn(fee_per_kb) << "/kB fee");
3431
3432 needed_fee = tx_weight / 1024;
3433 needed_fee += (tx_weight % 1024) ? 1 : 0;
3434 needed_fee *= fee_per_kb;
3435 }
3436
3437 if (fee < needed_fee - needed_fee / 50) // keep a little 2% buffer on acceptance - no integer overflow
3438 {
3439 MERROR_VER("transaction fee is not enough: " << print_etn(fee) << ", minimum fee: " << print_etn(needed_fee));
3440 return false;
3441 }
3442 return true;
3443}
uint8_t version
#define MERROR_VER(x)
uint8_t get_current_hard_fork_version() const
gets the current hardfork version in use/voted for
Definition blockchain.h:825
network_type get_nettype() const
get blockchain nettype
static uint64_t get_fee_quantization_mask()
get fee quantization mask
static uint64_t get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version)
get dynamic per kB or byte fee for a given block weight
#define FEE_PER_KB_V11
#define HF_VERSION_DYNAMIC_FEE
#define FEE_PER_KB_V6
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT
#define FEE_PER_KB
#define HF_VERSION_PER_BYTE_FEE
#define MDEBUG(x)
Definition misc_log_ex.h:76
bool get_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint8_t version, uint64_t current_block_height, network_type nettype)
std::string print_etn(uint64_t amount, unsigned int decimal_point)
type_vec_type median(std::vector< type_vec_type > &v)
unsigned char uint8_t
Definition stdint.h:124
Here is the call graph for this function:

◆ check_tx_inputs()

bool cryptonote::Blockchain::check_tx_inputs ( transaction & tx,
uint64_t & pmax_used_block_height,
crypto::hash & max_used_block_id,
tx_verification_context & tvc,
bool kept_by_block = false )

validates a transaction's inputs

validates a transaction's inputs as correctly used and not previously spent. also returns the hash and height of the most recent block which contains an output that was used as an input to the transaction. The transaction's rct signatures, if any, are expanded.

Parameters
txthe transaction to validate
pmax_used_block_heightreturn-by-reference block height of most recent input
max_used_block_idreturn-by-reference block hash of most recent input
tvcreturned information about tx verification
kept_by_blockwhether or not the transaction is from a previously-verified block
Returns
false if any input is invalid, otherwise true

◆ check_tx_outputs()

bool Blockchain::check_tx_outputs ( const transaction & tx,
tx_verification_context & tvc )

check that a transaction's outputs conform to current standards

This function checks, for example at the time of this writing, that each output is of the form a * 10^b (phrased differently, that if written out would have only one non-zero digit in base 10).

Parameters
txthe transaction to check the outputs of
tvcreturned info about tx verification
Returns
false if any outputs do not conform, otherwise true

Definition at line 2901 of file blockchain.cpp.

2902{
2903 LOG_PRINT_L3("Blockchain::" << __func__);
2904 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2905
2906 const uint8_t hf_version = m_hardfork->get_current_version();
2907
2908 // from hard fork 2, we forbid dust and compound outputs
2909 if (hf_version >= HF_VERSION_FORBID_DUST_OUTPUTS) {
2910 for (auto &o: tx.vout) {
2911 if (!is_valid_decomposed_amount(o.amount)) {
2912 tvc.m_invalid_output = true;
2913 return false;
2914 }
2915 }
2916 }
2917
2918 // from v4, forbid invalid pubkeys
2919 if (hf_version >= HF_VERSION_FORBID_INVALID_PUBKEYS) {
2920 for (const auto &o: tx.vout) {
2921 if (hf_version < HF_VERSION_PUBLIC_TX) {
2922 if (o.target.type() == typeid(txout_to_key)) {
2923 const txout_to_key &out_to_key = boost::get<txout_to_key>(o.target);
2924 if (!crypto::check_key(out_to_key.key)) {
2925 tvc.m_invalid_output = true;
2926 return false;
2927 }
2928 }
2929 }
2930 else {
2931 //do a sanity check on output type before checking destination
2932 if (o.target.type() != typeid(txout_to_key_public)) {
2933 return false;
2934 }
2935 const txout_to_key_public &out_to_key_public = boost::get<txout_to_key_public>(o.target);
2936 if (!crypto::check_key(out_to_key_public.address.m_spend_public_key) ||
2937 !crypto::check_key(out_to_key_public.address.m_view_public_key)) {
2938 tvc.m_invalid_output = true;
2939 return false;
2940 }
2941
2943 uint64_t integrated_address_prefix = get_config(m_nettype).CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
2944 uint64_t subaddress_prefix = get_config(m_nettype).CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX;
2945
2946 std::vector<uint64_t> supported_prefixes{address_prefix, integrated_address_prefix, subaddress_prefix};
2947
2948 if(std::find(supported_prefixes.begin(), supported_prefixes.end(), out_to_key_public.m_address_prefix) == supported_prefixes.end()) {
2949 tvc.m_invalid_output = true;
2950 return false;
2951 }
2952 }
2953 }
2954 }
2955 return true;
2956}
#define HF_VERSION_PUBLIC_TX
#define HF_VERSION_FORBID_INVALID_PUBKEYS
#define HF_VERSION_FORBID_DUST_OUTPUTS
bool check_key(const public_key &key)
Definition crypto.h:256
bool is_valid_decomposed_amount(uint64_t amount)
const config_t & get_config(network_type nettype)
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX
cryptonote::account_public_address address
Here is the call graph for this function:

◆ cleanup_handle_incoming_blocks()

bool Blockchain::cleanup_handle_incoming_blocks ( bool force_sync = false)

incoming blocks post-processing, cleanup, and disk sync

Parameters
force_syncif true, and Blockchain is handling syncing to disk, always sync
Returns
true

Definition at line 4332 of file blockchain.cpp.

4333{
4334 bool success = false;
4335
4336 MTRACE("Blockchain::" << __func__);
4337 CRITICAL_REGION_BEGIN(m_blockchain_lock);
4339
4340 try
4341 {
4342 if (m_batch_success)
4343 m_db->batch_stop();
4344 else
4345 m_db->batch_abort();
4346 success = true;
4347 }
4348 catch (const std::exception &e)
4349 {
4350 MERROR("Exception in cleanup_handle_incoming_blocks: " << e.what());
4351 }
4352
4353 if (success && m_sync_counter > 0)
4354 {
4355 if (force_sync)
4356 {
4357 if(m_db_sync_mode != db_nosync)
4359 m_sync_counter = 0;
4360 }
4361 else if (m_db_sync_threshold && ((m_db_sync_on_blocks && m_sync_counter >= m_db_sync_threshold) || (!m_db_sync_on_blocks && m_bytes_to_sync >= m_db_sync_threshold)))
4362 {
4363 MDEBUG("Sync threshold met, syncing");
4364 if(m_db_sync_mode == db_async)
4365 {
4366 m_sync_counter = 0;
4367 m_bytes_to_sync = 0;
4368 m_async_service.dispatch(boost::bind(&Blockchain::store_blockchain, this));
4369 }
4370 else if(m_db_sync_mode == db_sync)
4371 {
4373 }
4374 else // db_nosync
4375 {
4376 // DO NOTHING, not required to call sync.
4377 }
4378 }
4379 }
4380
4382 m_blocks_longhash_table.clear();
4383 m_scan_table.clear();
4384 m_blocks_txs_check.clear();
4385 m_check_txin_table.clear();
4386
4388 m_tx_pool.unlock();
4389
4391
4392 return success;
4393}
bool store_blockchain()
stores the blockchain
#define MTRACE(x)
Definition misc_log_ex.h:77
@ db_nosync
Leave syncing up to the backing db (safest, but slowest because of disk I/O).
Definition blockchain.h:82
@ db_sync
handle syncing calls instead of the backing db, synchronously
Definition blockchain.h:80
t1
Definition pow22523.h:58
#define CRITICAL_REGION_END()
Definition syncobj.h:233
#define CRITICAL_REGION_BEGIN(x)
Definition syncobj.h:229
Here is the call graph for this function:

◆ create_block_template() [1/2]

bool Blockchain::create_block_template ( block & b,
const account_public_address & miner_address,
difficulty_type & di,
uint64_t & height,
uint64_t & expected_reward,
const blobdata & ex_nonce )

creates a new block to mine against

Parameters
breturn-by-reference block to be filled in
from_blockoptional block hash to start mining from (main chain tip if NULL)
miner_addressaddress new coins for the block will go to
direturn-by-reference tells the miner what the difficulty target is
heightreturn-by-reference tells the miner what height it's mining against
expected_rewardreturn-by-reference the total reward awarded to the miner finding this block, including transaction fees
ex_nonceextra data to be added to the miner transaction's extra
Returns
true if block template filled in successfully, else false

Definition at line 1838 of file blockchain.cpp.

1839{
1840 return create_block_template(b, NULL, miner_address, diffic, height, expected_reward, ex_nonce);
1841}
bool create_block_template(block &b, const account_public_address &miner_address, difficulty_type &di, uint64_t &height, uint64_t &expected_reward, const blobdata &ex_nonce)
creates a new block to mine against
Here is the call graph for this function:
Here is the caller graph for this function:

◆ create_block_template() [2/2]

bool Blockchain::create_block_template ( block & b,
const crypto::hash * from_block,
const account_public_address & miner_address,
difficulty_type & di,
uint64_t & height,
uint64_t & expected_reward,
const blobdata & ex_nonce )

Definition at line 1583 of file blockchain.cpp.

1584{
1585 LOG_PRINT_L3("Blockchain::" << __func__);
1586 size_t median_weight;
1587 uint64_t already_generated_coins;
1588 //uint64_t pool_cookie;
1589
1590 m_tx_pool.lock();
1591 const auto unlock_guard = epee::misc_utils::create_scope_leave_handler([&]() { m_tx_pool.unlock(); });
1592 CRITICAL_REGION_LOCAL(m_blockchain_lock);
1593 if (m_btc_valid && !from_block) {
1594 // The pool cookie is atomic. The lack of locking is OK, as if it changes
1595 // just as we compare it, we'll just use a slightly old template, but
1596 // this would be the case anyway if we'd lock, and the change happened
1597 // just after the block template was created
1598 if (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address)) && m_btc_nonce == ex_nonce
1599 && m_btc_pool_cookie == m_tx_pool.cookie() && m_btc.prev_id == get_tail_id()) {
1600 MDEBUG("Using cached template");
1601 m_btc.timestamp = time(NULL); // update timestamp unconditionally
1602 b = m_btc;
1603 diffic = m_btc_difficulty;
1604 height = m_btc_height;
1605 expected_reward = m_btc_expected_reward;
1606 return true;
1607 }
1608 MDEBUG("Not using cached template: address " << (!memcmp(&miner_address, &m_btc_address, sizeof(cryptonote::account_public_address))) << ", nonce " << (m_btc_nonce == ex_nonce) << ", cookie " << (m_btc_pool_cookie == m_tx_pool.cookie()) << ", from_block " << (!!from_block));
1609 invalidate_block_template_cache();
1610 }
1611
1612 if (from_block)
1613 {
1614 //build alternative subchain, front -> mainchain, back -> alternative head
1615 //block is not related with head of main chain
1616 //first of all - look in alternative chains container
1617 auto it_prev = m_alternative_chains.find(*from_block);
1618 bool parent_in_main = m_db->block_exists(*from_block);
1619 if(it_prev == m_alternative_chains.end() && !parent_in_main)
1620 {
1621 MERROR("Unknown from block");
1622 return false;
1623 }
1624
1625 //we have new block in alternative chain
1626 std::list<blocks_ext_by_hash::const_iterator> alt_chain;
1627 block_verification_context bvc = boost::value_initialized<block_verification_context>();
1628 std::vector<uint64_t> timestamps;
1629 if (!build_alt_chain(*from_block, alt_chain, timestamps, bvc))
1630 return false;
1631
1632 if (parent_in_main)
1633 {
1634 cryptonote::block prev_block;
1635 CHECK_AND_ASSERT_MES(get_block_by_hash(*from_block, prev_block), false, "From block not found"); // TODO
1636 uint64_t from_block_height = cryptonote::get_block_height(prev_block);
1637 height = from_block_height + 1;
1638 }
1639 else
1640 {
1641 height = alt_chain.back()->second.height + 1;
1642 }
1643 b.major_version = m_hardfork->get_ideal_version(height);
1644 b.minor_version = m_hardfork->get_ideal_version();
1645 b.prev_id = *from_block;
1646
1647 // cheat and use the weight of the block we start from, virtually certain to be acceptable
1648 // and use 1.9 times rather than 2 times so we're even more sure
1649 if (parent_in_main)
1650 {
1651 median_weight = m_db->get_block_weight(height - 1);
1652 already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
1653 }
1654 else
1655 {
1656 median_weight = it_prev->second.block_cumulative_weight - it_prev->second.block_cumulative_weight / 20;
1657 already_generated_coins = alt_chain.back()->second.already_generated_coins;
1658 }
1659
1660 // FIXME: consider moving away from block_extended_info at some point
1661 block_extended_info bei = boost::value_initialized<block_extended_info>();
1662 bei.bl = b;
1663 bei.height = alt_chain.size() ? it_prev->second.height + 1 : m_db->get_block_height(*from_block) + 1;
1664
1665 diffic = get_next_difficulty_for_alternative_chain(alt_chain, bei);
1666 }
1667 else
1668 {
1669 height = m_db->height();
1670 b.major_version = m_hardfork->get_current_version();
1671 b.minor_version = m_hardfork->get_ideal_version();
1672 b.prev_id = get_tail_id();
1673 median_weight = m_current_block_cumul_weight_limit / 2;
1675 already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
1676 }
1677 b.timestamp = time(NULL);
1678
1679 uint64_t median_ts;
1680 if (!check_block_timestamp(b, median_ts))
1681 {
1682 b.timestamp = median_ts;
1683 }
1684
1685 CHECK_AND_ASSERT_MES(diffic, false, "difficulty overhead.");
1686
1687 size_t txs_weight;
1688 uint64_t fee;
1689 if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, b.major_version))
1690 {
1691 return false;
1692 }
1693 //pool_cookie = m_tx_pool.cookie();
1694#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1695 size_t real_txs_weight = 0;
1696 uint64_t real_fee = 0;
1697 for(crypto::hash &cur_hash: b.tx_hashes)
1698 {
1699 auto cur_res = m_tx_pool.m_transactions.find(cur_hash);
1700 if (cur_res == m_tx_pool.m_transactions.end())
1701 {
1702 LOG_ERROR("Creating block template: error: transaction not found");
1703 continue;
1704 }
1705 tx_memory_pool::tx_details &cur_tx = cur_res->second;
1706 real_txs_weight += cur_tx.weight;
1707 real_fee += cur_tx.fee;
1708 if (cur_tx.weight != get_transaction_weight(cur_tx.tx))
1709 {
1710 LOG_ERROR("Creating block template: error: invalid transaction weight");
1711 }
1712
1713 uint64_t inputs_amount;
1714 if (!get_inputs_etn_amount(cur_tx.tx, inputs_amount))
1715 {
1716 LOG_ERROR("Creating block template: error: cannot get inputs amount");
1717 }
1718 else if (cur_tx.fee != inputs_amount - get_outs_etn_amount(cur_tx.tx))
1719 {
1720 LOG_ERROR("Creating block template: error: invalid fee");
1721 }
1722 }
1723 if (txs_weight != real_txs_weight)
1724 {
1725 LOG_ERROR("Creating block template: error: wrongly calculated transaction weight");
1726 }
1727 if (fee != real_fee)
1728 {
1729 LOG_ERROR("Creating block template: error: wrongly calculated fee");
1730 }
1731 MDEBUG("Creating block template: height " << height <<
1732 ", median weight " << median_weight <<
1733 ", already generated coins " << already_generated_coins <<
1734 ", transaction weight " << txs_weight <<
1735 ", fee " << fee);
1736#endif
1737
1738 /*
1739 two-phase miner transaction generation: we don't know exact block weight until we prepare block, but we don't know reward until we know
1740 block weight, so first miner transaction generated with fake amount of etn, and with phase we know think we know expected block weight
1741 */
1742 //make blocks coin-base tx looks close to real coinbase tx to get truthful blob weight
1743 uint8_t hf_version = b.major_version;
1744 size_t max_outs = hf_version >= 4 ? 1 : 11;
1745 bool r = construct_miner_tx(height, median_weight, already_generated_coins, txs_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype);
1746 CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance");
1747 size_t cumulative_weight = txs_weight + get_transaction_weight(b.miner_tx);
1748#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1749 MDEBUG("Creating block template: miner tx weight " << get_transaction_weight(b.miner_tx) <<
1750 ", cumulative weight " << cumulative_weight);
1751#endif
1752 for (size_t try_count = 0; try_count != 10; ++try_count)
1753 {
1754 r = construct_miner_tx(height, median_weight, already_generated_coins, cumulative_weight, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version, m_nettype);
1755
1756 CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, second chance");
1757 size_t coinbase_weight = get_transaction_weight(b.miner_tx);
1758 if (coinbase_weight > cumulative_weight - txs_weight)
1759 {
1760 cumulative_weight = txs_weight + coinbase_weight;
1761#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1762 MDEBUG("Creating block template: miner tx weight " << coinbase_weight <<
1763 ", cumulative weight " << cumulative_weight << " is greater than before");
1764#endif
1765 continue;
1766 }
1767
1768 if (coinbase_weight < cumulative_weight - txs_weight)
1769 {
1770 size_t delta = cumulative_weight - txs_weight - coinbase_weight;
1771#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1772 MDEBUG("Creating block template: miner tx weight " << coinbase_weight <<
1773 ", cumulative weight " << txs_weight + coinbase_weight <<
1774 " is less than before, adding " << delta << " zero bytes");
1775#endif
1776 b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0);
1777 //here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len.
1778 if (cumulative_weight != txs_weight + get_transaction_weight(b.miner_tx))
1779 {
1780 CHECK_AND_ASSERT_MES(cumulative_weight + 1 == txs_weight + get_transaction_weight(b.miner_tx), false, "unexpected case: cumulative_weight=" << cumulative_weight << " + 1 is not equal txs_cumulative_weight=" << txs_weight << " + get_transaction_weight(b.miner_tx)=" << get_transaction_weight(b.miner_tx));
1781 b.miner_tx.extra.resize(b.miner_tx.extra.size() - 1);
1782 if (cumulative_weight != txs_weight + get_transaction_weight(b.miner_tx))
1783 {
1784 //fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_weight
1785 MDEBUG("Miner tx creation has no luck with delta_extra size = " << delta << " and " << delta - 1);
1786 cumulative_weight += delta - 1;
1787 continue;
1788 }
1789 MDEBUG("Setting extra for block: " << b.miner_tx.extra.size() << ", try_count=" << try_count);
1790 }
1791 }
1792 CHECK_AND_ASSERT_MES(cumulative_weight == txs_weight + get_transaction_weight(b.miner_tx), false, "unexpected case: cumulative_weight=" << cumulative_weight << " is not equal txs_cumulative_weight=" << txs_weight << " + get_transaction_weight(b.miner_tx)=" << get_transaction_weight(b.miner_tx));
1793#if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
1794 MDEBUG("Creating block template: miner tx weight " << coinbase_weight <<
1795 ", cumulative weight " << cumulative_weight << " is now good");
1796#endif
1797
1798 //if (!from_block)
1799 // cache_block_template(b, miner_address, ex_nonce, diffic, height, expected_reward, pool_cookie);
1800
1801 if(!m_fallback_to_pow && hf_version >= 8) {
1802 sign_block(b, m_validator_key);
1803 }
1804
1805 return true;
1806 }
1807 LOG_ERROR("Failed to create_block_template with " << 10 << " tries");
1808 return false;
1809}
time_t time
bool get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan=NULL) const
gets the block with a given hash
difficulty_type get_difficulty_for_next_block()
returns the difficulty target the next block to be added must meet
void sign_block(block &b, std::string privateKey)
Digitally sign the block.
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
uint64_t get_outs_etn_amount(const transaction &tx)
uint64_t get_block_height(const block &b)
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction &tx, const blobdata &extra_nonce, size_t max_outs, uint8_t hard_fork_version, network_type nettype)
bool get_inputs_etn_amount(const transaction &tx, uint64_t &etn)
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)
container for passing a block and metadata about it on the blockchain
Definition blockchain.h:115
std::vector< crypto::hash > tx_hashes
transaction tx
the transaction
Definition tx_pool.h:405
uint64_t fee
the transaction's fee amount
Definition tx_pool.h:408
size_t weight
the transaction's weight
Definition tx_pool.h:407
Here is the call graph for this function:

◆ deinit()

bool Blockchain::deinit ( )

Uninitializes the blockchain state.

Saves to disk any state that needs to be maintained

Returns
true on success, false if any uninitialization steps fail

Definition at line 660 of file blockchain.cpp.

661{
662 LOG_PRINT_L3("Blockchain::" << __func__);
663
664 MTRACE("Stopping blockchain read/write activity");
665
666 // stop async service
667 m_async_work_idle.reset();
668 m_async_pool.join_all();
669 m_async_service.stop();
670
671 // as this should be called if handling a SIGSEGV, need to check
672 // if m_db is a NULL pointer (and thus may have caused the illegal
673 // memory operation), otherwise we may cause a loop.
674 try
675 {
676 if (m_db)
677 {
678 m_db->close();
679 MTRACE("Local blockchain read/write activity stopped successfully");
680 }
681 }
682 catch (const std::exception& e)
683 {
684 LOG_ERROR(std::string("Error closing blockchain db: ") + e.what());
685 }
686 catch (...)
687 {
688 LOG_ERROR("There was an issue closing/storing the blockchain, shutting down now to prevent issues!");
689 }
690
691 delete m_hardfork;
692 m_hardfork = NULL;
693 delete m_db;
694 m_db = NULL;
695 return true;
696}
Here is the caller graph for this function:

◆ find_blockchain_supplement() [1/4]

bool Blockchain::find_blockchain_supplement ( const std::list< crypto::hash > & qblock_ids,
NOTIFY_RESPONSE_CHAIN_ENTRY::request & resp ) const

get recent block hashes for a foreign chain

Find the split point between us and foreign blockchain and return (by reference) the most recent common block hash along with up to BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes.

Parameters
qblock_idsthe foreign chain's "short history" (see get_short_chain_history)
respreturn-by-reference the split height and subsequent blocks' hashes
Returns
true if a block found in common, else false

Definition at line 2598 of file blockchain.cpp.

2599{
2600 LOG_PRINT_L3("Blockchain::" << __func__);
2601 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2602
2603 bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height, true);
2604 if (result)
2605 {
2606 cryptonote::difficulty_type wide_cumulative_difficulty = m_db->get_block_cumulative_difficulty(resp.total_height - 1);
2607 resp.cumulative_difficulty = (wide_cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
2608 resp.cumulative_difficulty_top64 = ((wide_cumulative_difficulty >> 64) & 0xffffffffffffffff).convert_to<uint64_t>();
2609 }
2610
2611 return result;
2612}
bool find_blockchain_supplement(const std::list< crypto::hash > &qblock_ids, std::vector< crypto::hash > &hashes, uint64_t &start_height, uint64_t &current_height, bool clip_pruned) const
get recent block hashes for a foreign chain
boost::multiprecision::uint128_t difficulty_type
Definition difficulty.h:43
Here is the call graph for this function:

◆ find_blockchain_supplement() [2/4]

bool Blockchain::find_blockchain_supplement ( const std::list< crypto::hash > & qblock_ids,
std::vector< crypto::hash > & hashes,
uint64_t & start_height,
uint64_t & current_height,
bool clip_pruned ) const

get recent block hashes for a foreign chain

Find the split point between us and foreign blockchain and return (by reference) the most recent common block hash along with up to BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes.

Parameters
qblock_idsthe foreign chain's "short history" (see get_short_chain_history)
hashesthe hashes to be returned, return-by-reference
start_heightthe start height, return-by-reference
current_heightthe current blockchain height, return-by-reference
clip_prunedwhether to constrain results to unpruned data
Returns
true if a block found in common, else false

Definition at line 2568 of file blockchain.cpp.

2569{
2570 LOG_PRINT_L3("Blockchain::" << __func__);
2571 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2572
2573 // if we can't find the split point, return false
2574 if(!find_blockchain_supplement(qblock_ids, start_height))
2575 {
2576 return false;
2577 }
2578
2579 db_rtxn_guard rtxn_guard(m_db);
2580 current_height = get_current_blockchain_height();
2581 uint64_t stop_height = current_height;
2582 if (clip_pruned)
2583 {
2584 const uint32_t pruning_seed = get_blockchain_pruning_seed();
2585 start_height = tools::get_next_unpruned_block_height(start_height, current_height, pruning_seed);
2586 stop_height = tools::get_next_pruned_block_height(start_height, current_height, pruning_seed);
2587 }
2588 size_t count = 0;
2589 hashes.reserve(std::min((size_t)(stop_height - start_height), (size_t)BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT));
2590 for(size_t i = start_height; i < stop_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++)
2591 {
2592 hashes.push_back(m_db->get_block_hash_from_height(i));
2593 }
2594
2595 return true;
2596}
uint32_t get_blockchain_pruning_seed() const
uint64_t get_current_blockchain_height() const
get the current height of the blockchain
#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT
mdb_size_t count(MDB_cursor *cur)
uint64_t get_next_pruned_block_height(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed)
Definition pruning.cpp:93
uint64_t get_next_unpruned_block_height(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed)
Definition pruning.cpp:69
unsigned int uint32_t
Definition stdint.h:126
struct hash_func hashes[]
Here is the call graph for this function:
Here is the caller graph for this function:

◆ find_blockchain_supplement() [3/4]

bool Blockchain::find_blockchain_supplement ( const std::list< crypto::hash > & qblock_ids,
uint64_t & starter_offset ) const

find the most recent common point between ours and a foreign chain

This function takes a list of block hashes from another node on the network to find where the split point is between us and them. This is used to see what to send another node that needs to sync.

Parameters
qblock_idsthe foreign chain's "short history" (see get_short_chain_history)
starter_offsetreturn-by-reference the most recent common block's height
Returns
true if a block found in common, else false

Definition at line 2348 of file blockchain.cpp.

2349{
2350 LOG_PRINT_L3("Blockchain::" << __func__);
2351 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2352
2353 // make sure the request includes at least the genesis block, otherwise
2354 // how can we expect to sync from the client that the block list came from?
2355 if(qblock_ids.empty())
2356 {
2357 MCERROR("net.p2p", "Client sent wrong NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << qblock_ids.size() << ", dropping connection");
2358 return false;
2359 }
2360
2361 db_rtxn_guard rtxn_guard(m_db);
2362 // make sure that the last block in the request's block list matches
2363 // the genesis block
2364 auto gen_hash = m_db->get_block_hash_from_height(0);
2365 if(qblock_ids.back() != gen_hash)
2366 {
2367 LOG_PRINT_L0("Genesis Block Mismatch");
2368 MCERROR("net.p2p", "Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block mismatch: " << std::endl << "id: " << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash << "," << std::endl << " dropping connection");
2369 return false;
2370 }
2371
2372 // Find the first block the foreign chain has that we also have.
2373 // Assume qblock_ids is in reverse-chronological order.
2374 auto bl_it = qblock_ids.begin();
2375 uint64_t split_height = 0;
2376 for(; bl_it != qblock_ids.end(); bl_it++)
2377 {
2378 try
2379 {
2380 if (m_db->block_exists(*bl_it, &split_height))
2381 break;
2382 }
2383 catch (const std::exception& e)
2384 {
2385 MWARNING("Non-critical error trying to find block by hash in BlockchainDB, hash: " << *bl_it);
2386 return false;
2387 }
2388 }
2389
2390 // this should be impossible, as we checked that we share the genesis block,
2391 // but just in case...
2392 if(bl_it == qblock_ids.end())
2393 {
2394 MERROR("Internal error handling connection, can't find split point");
2395 return false;
2396 }
2397
2398 //we start to put block ids INCLUDING last known id, just to make other side be sure
2399 starter_offset = split_height;
2400 return true;
2401}
#define MCERROR(cat, x)
Definition misc_log_ex.h:51
#define MWARNING(x)
Definition misc_log_ex.h:74
#define LOG_PRINT_L0(x)
Definition misc_log_ex.h:99

◆ find_blockchain_supplement() [4/4]

bool Blockchain::find_blockchain_supplement ( const uint64_t req_start_block,
const std::list< crypto::hash > & qblock_ids,
std::vector< std::pair< std::pair< cryptonote::blobdata, crypto::hash >, std::vector< std::pair< crypto::hash, cryptonote::blobdata > > > > & blocks,
uint64_t & total_height,
uint64_t & start_height,
bool pruned,
bool get_miner_tx_hash,
size_t max_count ) const

get recent blocks for a foreign chain

This function gets recent blocks relative to a foreign chain, starting either at a requested height or whatever height is the most recent ours and the foreign chain have in common.

Parameters
req_start_blockif non-zero, specifies a start point (otherwise find most recent commonality)
qblock_idsthe foreign chain's "short history" (see get_short_chain_history)
blocksreturn-by-reference the blocks and their transactions
total_heightreturn-by-reference our current blockchain height
start_heightreturn-by-reference the height of the first block returned
prunedwhether to return full or pruned tx blobs
max_countthe max number of blocks to get
Returns
true if a block found in common or req_start_block specified, else false

Definition at line 2618 of file blockchain.cpp.

2619{
2620 LOG_PRINT_L3("Blockchain::" << __func__);
2621 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2622
2623 // if a specific start height has been requested
2624 if(req_start_block > 0)
2625 {
2626 // if requested height is higher than our chain, return false -- we can't help
2627 if (req_start_block >= m_db->height())
2628 {
2629 return false;
2630 }
2631 start_height = req_start_block;
2632 }
2633 else
2634 {
2635 if(!find_blockchain_supplement(qblock_ids, start_height))
2636 {
2637 return false;
2638 }
2639 }
2640
2641 db_rtxn_guard rtxn_guard(m_db);
2642 total_height = get_current_blockchain_height();
2643 size_t count = 0, size = 0;
2644 blocks.reserve(std::min(std::min(max_count, (size_t)10000), (size_t)(total_height - start_height)));
2645 for(uint64_t i = start_height; i < total_height && count < max_count && (size < FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE || count < 3); i++, count++)
2646 {
2647 blocks.resize(blocks.size()+1);
2648 blocks.back().first.first = m_db->get_block_blob_from_height(i);
2649 block b;
2650 CHECK_AND_ASSERT_MES(parse_and_validate_block_from_blob(blocks.back().first.first, b), false, "internal error, invalid block");
2651 blocks.back().first.second = get_miner_tx_hash ? cryptonote::get_transaction_hash(b.miner_tx) : crypto::null_hash;
2652 std::vector<crypto::hash> mis;
2653 std::vector<cryptonote::blobdata> txs;
2654 get_transactions_blobs(b.tx_hashes, txs, mis, pruned);
2655 CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, transaction from block not found");
2656 size += blocks.back().first.first.size();
2657 for (const auto &t: txs)
2658 size += t.size();
2659
2660 CHECK_AND_ASSERT_MES(txs.size() == b.tx_hashes.size(), false, "mismatched sizes of b.tx_hashes and txs");
2661 blocks.back().second.reserve(txs.size());
2662 for (size_t i = 0; i < txs.size(); ++i)
2663 {
2664 blocks.back().second.push_back(std::make_pair(b.tx_hashes[i], std::move(txs[i])));
2665 }
2666 }
2667 return true;
2668}
#define FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE
bool get_transactions_blobs(const t_ids_container &txs_ids, t_tx_container &txs, t_missed_container &missed_txs, bool pruned=false) const
gets transactions based on a list of transaction hashes
bool parse_and_validate_block_from_blob(const blobdata &b_blob, block &b, crypto::hash *block_hash)
crypto::hash get_transaction_hash(const transaction &t)
Here is the call graph for this function:

◆ flush_txes_from_pool()

bool Blockchain::flush_txes_from_pool ( const std::vector< crypto::hash > & txids)

remove transactions from the transaction pool (if present)

Parameters
txidsa list of hashes of transactions to be removed
Returns
false if any removals fail, otherwise true

Definition at line 3657 of file blockchain.cpp.

3658{
3659 CRITICAL_REGION_LOCAL(m_tx_pool);
3660
3661 bool res = true;
3662 for (const auto &txid: txids)
3663 {
3664 cryptonote::transaction tx;
3665 cryptonote::blobdata txblob;
3666 size_t tx_weight;
3667 uint64_t fee;
3668 bool relayed, do_not_relay, double_spend_seen, nonexistent_utxo_seen;
3669 MINFO("Removing txid " << txid << " from the pool");
3670 if(m_tx_pool.have_tx(txid) && !m_tx_pool.take_tx(txid, tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, nonexistent_utxo_seen))
3671 {
3672 MERROR("Failed to remove txid " << txid << " from the pool");
3673 res = false;
3674 }
3675 }
3676 return res;
3677}
const char * res
#define MINFO(x)
Definition misc_log_ex.h:75
std::string blobdata
Here is the caller graph for this function:

◆ for_all_key_images()

bool Blockchain::for_all_key_images ( std::function< bool(const crypto::key_image &)> ) const

perform a check on all key images in the blockchain

Parameters
std::functionthe check to perform, pass/fail
Returns
false if any key image fails the check, otherwise true

Definition at line 5041 of file blockchain.cpp.

5042{
5043 return m_db->for_all_key_images(f);
5044}

◆ for_all_outputs() [1/2]

bool cryptonote::Blockchain::for_all_outputs ( std::function< bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> ) const

perform a check on all outputs in the blockchain

Parameters
std::functionthe check to perform, pass/fail
Returns
false if any output fails the check, otherwise true

◆ for_all_outputs() [2/2]

bool cryptonote::Blockchain::for_all_outputs ( uint64_t amount,
std::function< bool(uint64_t height)>  ) const

perform a check on all outputs of a given amount in the blockchain

Parameters
amountthe amount to iterate through
std::functionthe check to perform, pass/fail
Returns
false if any output fails the check, otherwise true

◆ for_all_transactions()

bool Blockchain::for_all_transactions ( std::function< bool(const crypto::hash &, const cryptonote::transaction &)> ,
bool pruned ) const

perform a check on all transactions in the blockchain

Parameters
std::functionthe check to perform, pass/fail
boolpruned whether to return pruned txes only
Returns
false if any transaction fails the check, otherwise true

Definition at line 5051 of file blockchain.cpp.

5052{
5053 return m_db->for_all_transactions(f, pruned);
5054}

◆ for_all_txpool_txes()

bool Blockchain::for_all_txpool_txes ( std::function< bool(const crypto::hash &, const txpool_tx_meta_t &, const cryptonote::blobdata *)> ,
bool include_blob = false,
bool include_unrelayed_txes = true ) const

Definition at line 4803 of file blockchain.cpp.

4804{
4805 return m_db->for_all_txpool_txes(f, include_blob, include_unrelayed_txes);
4806}

◆ for_blocks_range()

bool Blockchain::for_blocks_range ( const uint64_t & h1,
const uint64_t & h2,
std::function< bool(uint64_t, const crypto::hash &, const block &)>  ) const

perform a check on all blocks in the blockchain in the given range

Parameters
h1the start height
h2the end height
std::functionthe check to perform, pass/fail
Returns
false if any block fails the check, otherwise true

Definition at line 5046 of file blockchain.cpp.

5047{
5048 return m_db->for_blocks_range(h1, h2, f);
5049}

◆ get_alternative_blocks()

bool Blockchain::get_alternative_blocks ( std::vector< block > & blocks) const

compiles a list of all blocks stored as alternative chains

Parameters
blocksreturn-by-reference container to put result blocks in
Returns
true

Definition at line 2193 of file blockchain.cpp.

2194{
2195 LOG_PRINT_L3("Blockchain::" << __func__);
2196 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2197
2198 blocks.reserve(m_alternative_chains.size());
2199 for (const auto& alt_bl: m_alternative_chains)
2200 {
2201 blocks.push_back(alt_bl.second.bl);
2202 }
2203 return true;
2204}

◆ get_alternative_blocks_count()

size_t Blockchain::get_alternative_blocks_count ( ) const

returns the number of alternative blocks stored

Returns
the number of alternative blocks stored

Definition at line 2206 of file blockchain.cpp.

2207{
2208 LOG_PRINT_L3("Blockchain::" << __func__);
2209 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2210 return m_alternative_chains.size();
2211}

◆ get_alternative_chains()

std::list< std::pair< Blockchain::block_extended_info, std::vector< crypto::hash > > > Blockchain::get_alternative_chains ( ) const

returns a set of known alternate chains

Returns
a list of chains

Definition at line 4900 of file blockchain.cpp.

4901{
4902 std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains;
4903
4904 for (const auto &i: m_alternative_chains)
4905 {
4906 const crypto::hash &top = i.first;
4907 bool found = false;
4908 for (const auto &j: m_alternative_chains)
4909 {
4910 if (j.second.bl.prev_id == top)
4911 {
4912 found = true;
4913 break;
4914 }
4915 }
4916 if (!found)
4917 {
4918 std::vector<crypto::hash> chain;
4919 auto h = i.second.bl.prev_id;
4920 chain.push_back(top);
4921 blocks_ext_by_hash::const_iterator prev;
4922 while ((prev = m_alternative_chains.find(h)) != m_alternative_chains.end())
4923 {
4924 chain.push_back(h);
4925 h = prev->second.bl.prev_id;
4926 }
4927 chains.push_back(std::make_pair(i.second, chain));
4928 }
4929 }
4930 return chains;
4931}

◆ get_block_by_hash()

bool Blockchain::get_block_by_hash ( const crypto::hash & h,
block & blk,
bool * orphan = NULL ) const

gets the block with a given hash

Parameters
hthe hash to look for
blkreturn-by-reference variable to put result block in
orphanif non-NULL, will be set to true if not in the main chain, false otherwise
Returns
true if the block was found, else false

Definition at line 928 of file blockchain.cpp.

929{
930 LOG_PRINT_L3("Blockchain::" << __func__);
931 CRITICAL_REGION_LOCAL(m_blockchain_lock);
932
933 // try to find block in main chain
934 try
935 {
936 blk = m_db->get_block(h);
937 if (orphan)
938 *orphan = false;
939 return true;
940 }
941 // try to find block in alternative chain
942 catch (const BLOCK_DNE& e)
943 {
944 blocks_ext_by_hash::const_iterator it_alt = m_alternative_chains.find(h);
945 if (m_alternative_chains.end() != it_alt)
946 {
947 blk = it_alt->second.bl;
948 if (orphan)
949 *orphan = true;
950 return true;
951 }
952 }
953 catch (const std::exception& e)
954 {
955 MERROR(std::string("Something went wrong fetching block by hash: ") + e.what());
956 throw;
957 }
958 catch (...)
959 {
960 MERROR(std::string("Something went wrong fetching block hash by hash"));
961 throw;
962 }
963
964 return false;
965}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_block_id_by_height()

crypto::hash Blockchain::get_block_id_by_height ( uint64_t height) const

gets a block's hash given a height

Parameters
heightthe height of the block
Returns
the hash of the block at the requested height, or a zeroed hash if there is no such block

Definition at line 901 of file blockchain.cpp.

902{
903 LOG_PRINT_L3("Blockchain::" << __func__);
904 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
905 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
906 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
907 // lock if it is otherwise needed.
908 try
909 {
910 return m_db->get_block_hash_from_height(height);
911 }
912 catch (const BLOCK_DNE& e)
913 {
914 }
915 catch (const std::exception& e)
916 {
917 MERROR(std::string("Something went wrong fetching block hash by height: ") + e.what());
918 throw;
919 }
920 catch (...)
921 {
922 MERROR(std::string("Something went wrong fetching block hash by height"));
923 throw;
924 }
925 return null_hash;
926}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_blockchain_pruning_seed()

uint32_t cryptonote::Blockchain::get_blockchain_pruning_seed ( ) const
inline

Definition at line 1017 of file blockchain.h.

1017{ return m_db->get_blockchain_pruning_seed(); }
Here is the caller graph for this function:

◆ get_blocks() [1/3]

template<class t_ids_container, class t_blocks_container, class t_missed_container>
bool Blockchain::get_blocks ( const t_ids_container & block_ids,
t_blocks_container & blocks,
t_missed_container & missed_bs ) const

gets blocks based on a list of block hashes

Template Parameters
t_ids_containera standard-iterable container
t_blocks_containera standard-iterable container
t_missed_containera standard-iterable container
Parameters
block_idsa container of block hashes for which to get the corresponding blocks
blocksreturn-by-reference a container to store result blocks in
missed_bsreturn-by-reference a container to store missed blocks in
Returns
false if an unexpected exception occurs, else true

Definition at line 2427 of file blockchain.cpp.

2428{
2429 LOG_PRINT_L3("Blockchain::" << __func__);
2430 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2431
2432 reserve_container(blocks, block_ids.size());
2433 for (const auto& block_hash : block_ids)
2434 {
2435 try
2436 {
2437 uint64_t height = 0;
2438 if (m_db->block_exists(block_hash, &height))
2439 {
2440 blocks.push_back(std::make_pair(m_db->get_block_blob_from_height(height), block()));
2441 if (!parse_and_validate_block_from_blob(blocks.back().first, blocks.back().second))
2442 {
2443 LOG_ERROR("Invalid block: " << block_hash);
2444 blocks.pop_back();
2445 missed_bs.push_back(block_hash);
2446 }
2447 }
2448 else
2449 missed_bs.push_back(block_hash);
2450 }
2451 catch (const std::exception& e)
2452 {
2453 return false;
2454 }
2455 }
2456 return true;
2457}
void reserve_container(std::vector< T > &v, size_t N)
Here is the call graph for this function:

◆ get_blocks() [2/3]

bool Blockchain::get_blocks ( uint64_t start_offset,
size_t count,
std::vector< std::pair< cryptonote::blobdata, block > > & blocks ) const

get blocks from blocks based on start height and count

Parameters
start_offsetthe height on the blockchain to start at
countthe number of blocks to get, if there are as many after start_offset
blocksreturn-by-reference container to put result blocks in
Returns
false if start_offset > blockchain height, else true

Definition at line 2118 of file blockchain.cpp.

2119{
2120 LOG_PRINT_L3("Blockchain::" << __func__);
2121 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2122 const uint64_t height = m_db->height();
2123 if(start_offset >= height)
2124 return false;
2125
2126 blocks.reserve(blocks.size() + height - start_offset);
2127 for(size_t i = start_offset; i < start_offset + count && i < height;i++)
2128 {
2129 blocks.push_back(std::make_pair(m_db->get_block_blob_from_height(i), block()));
2130 if (!parse_and_validate_block_from_blob(blocks.back().first, blocks.back().second))
2131 {
2132 LOG_ERROR("Invalid block");
2133 return false;
2134 }
2135 }
2136 return true;
2137}
Here is the call graph for this function:

◆ get_blocks() [3/3]

bool Blockchain::get_blocks ( uint64_t start_offset,
size_t count,
std::vector< std::pair< cryptonote::blobdata, block > > & blocks,
std::vector< cryptonote::blobdata > & txs ) const

get blocks and transactions from blocks based on start height and count

Parameters
start_offsetthe height on the blockchain to start at
countthe number of blocks to get, if there are as many after start_offset
blocksreturn-by-reference container to put result blocks in
txsreturn-by-reference container to put result transactions in
Returns
false if start_offset > blockchain height, else true

Definition at line 2096 of file blockchain.cpp.

2097{
2098 LOG_PRINT_L3("Blockchain::" << __func__);
2099 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2100 if(start_offset >= m_db->height())
2101 return false;
2102
2103 if (!get_blocks(start_offset, count, blocks))
2104 {
2105 return false;
2106 }
2107
2108 for(const auto& blk : blocks)
2109 {
2110 std::vector<crypto::hash> missed_ids;
2111 get_transactions_blobs(blk.second.tx_hashes, txs, missed_ids);
2112 CHECK_AND_ASSERT_MES(!missed_ids.size(), false, "has missed transactions in own block in main blockchain");
2113 }
2114
2115 return true;
2116}
bool get_blocks(uint64_t start_offset, size_t count, std::vector< std::pair< cryptonote::blobdata, block > > &blocks, std::vector< cryptonote::blobdata > &txs) const
get blocks and transactions from blocks based on start height and count
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_current_blockchain_height()

uint64_t Blockchain::get_current_blockchain_height ( ) const

get the current height of the blockchain

Returns
the height

Definition at line 322 of file blockchain.cpp.

323{
324 LOG_PRINT_L3("Blockchain::" << __func__);
325 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
326 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
327 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
328 // lock if it is otherwise needed.
329 return m_db->height();
330}
Here is the caller graph for this function:

◆ get_current_cumulative_block_weight_limit()

uint64_t Blockchain::get_current_cumulative_block_weight_limit ( ) const

gets the block weight limit based on recent blocks

Returns
the limit

Definition at line 1560 of file blockchain.cpp.

1561{
1562 LOG_PRINT_L3("Blockchain::" << __func__);
1563 return m_current_block_cumul_weight_limit;
1564}

◆ get_current_cumulative_block_weight_median()

uint64_t Blockchain::get_current_cumulative_block_weight_median ( ) const

gets the block weight median based on recent blocks (same window as for the limit)

Returns
the median

Definition at line 1566 of file blockchain.cpp.

1567{
1568 LOG_PRINT_L3("Blockchain::" << __func__);
1569 return m_current_block_cumul_weight_median;
1570}

◆ get_current_hard_fork_version()

uint8_t cryptonote::Blockchain::get_current_hard_fork_version ( ) const
inline

gets the current hardfork version in use/voted for

Returns
the version

Definition at line 825 of file blockchain.h.

825{ return m_hardfork->get_current_version(); }
Here is the caller graph for this function:

◆ get_db() [1/2]

BlockchainDB & cryptonote::Blockchain::get_db ( )
inline

get a reference to the BlockchainDB in use by Blockchain

Returns
a reference to the BlockchainDB instance

Definition at line 973 of file blockchain.h.

974 {
975 return *m_db;
976 }

◆ get_db() [2/2]

const BlockchainDB & cryptonote::Blockchain::get_db ( ) const
inline

get a reference to the BlockchainDB in use by Blockchain

Returns
a reference to the BlockchainDB instance

Definition at line 963 of file blockchain.h.

964 {
965 return *m_db;
966 }
Here is the caller graph for this function:

◆ get_difficulty_for_next_block()

difficulty_type Blockchain::get_difficulty_for_next_block ( )

returns the difficulty target the next block to be added must meet

Returns
the target

Definition at line 971 of file blockchain.cpp.

972{
973 if (m_fixed_difficulty)
974 {
975 return m_db->height() ? m_fixed_difficulty : 1;
976 }
977
978 LOG_PRINT_L3("Blockchain::" << __func__);
979
980 crypto::hash top_hash = get_tail_id();
981 {
982 CRITICAL_REGION_LOCAL(m_difficulty_lock);
983 // we can call this without the blockchain lock, it might just give us
984 // something a bit out of date, but that's fine since anything which
985 // requires the blockchain lock will have acquired it in the first place,
986 // and it will be unlocked only when called from the getinfo RPC
987 if (top_hash == m_difficulty_for_next_block_top_hash)
988 return m_difficulty_for_next_block;
989 }
990
991 CRITICAL_REGION_LOCAL(m_blockchain_lock);
992 std::vector<uint64_t> timestamps;
993 std::vector<difficulty_type> difficulties;
995 top_hash = get_tail_id(height); // get it again now that we have the lock
996 ++height; // top block height to blockchain height
997
998 uint64_t v6height = 0, v7height = 0, v8height = 0;
999 if(m_nettype == MAINNET) {
1000 v6height = mainnet_hard_forks[1].height;
1001 v7height = mainnet_hard_forks[2].height;
1002 v8height = mainnet_hard_forks[3].height;
1003 } else if(m_nettype == TESTNET) {
1004 v6height = testnet_hard_forks[1].height;
1005 v7height = testnet_hard_forks[2].height;
1006 v8height = testnet_hard_forks[3].height;
1007 } else if(m_nettype == STAGENET) {
1008 v6height = stagenet_hard_forks[5].height;
1009 v7height = stagenet_hard_forks[5].height;
1010 v8height = stagenet_hard_forks[5].height;
1011 } else if(m_nettype == UNDEFINED){
1012 MERROR(std::string("Something went wrong defining the network type."));
1013 }
1014
1015
1016 uint32_t difficultyBlocksCount = (height >= v6height && height < v7height) ? DIFFICULTY_BLOCKS_COUNT_V6 : DIFFICULTY_BLOCKS_COUNT;
1017
1018 // After v8 allow the difficulty window to grow linearly (from zero) back to DIFFICULTY_BLOCKS_COUNT.
1019 if((height >= v8height) && (height < v8height + 720))
1020 {
1021 // Initial clear of the caches when we hit v8.
1022 if(height == v8height)
1023 {
1024 m_timestamps.clear();
1025 m_difficulties.clear();
1026 }
1027 difficultyBlocksCount = height - v8height;
1028 }
1029
1030 // ND: Speedup
1031 // 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
1032 // then when the next block difficulty is queried, push the latest height data and
1033 // pop the oldest one from the list. This only requires 1x read per height instead
1034 // of doing 735 (DIFFICULTY_BLOCKS_COUNT).
1035 // Post v8 we will only re-enter this scope after the first DIFFICULTY_BLOCKS_COUNT blocks due to the last condition.
1036 if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1) && m_timestamps.size() >= difficultyBlocksCount)
1037 {
1038 uint64_t index = height - 1;
1039 m_timestamps.push_back(m_db->get_block_timestamp(index));
1040 m_difficulties.push_back(m_db->get_block_cumulative_difficulty(index));
1041
1042 while (m_timestamps.size() > difficultyBlocksCount)
1043 m_timestamps.erase(m_timestamps.begin());
1044 while (m_difficulties.size() > difficultyBlocksCount)
1045 m_difficulties.erase(m_difficulties.begin());
1046
1047 m_timestamps_and_difficulties_height = height;
1048 timestamps = m_timestamps;
1049 difficulties = m_difficulties;
1050 }
1051 else
1052 {
1053 uint64_t offset = height - std::min < uint64_t > (height, static_cast<uint64_t>(difficultyBlocksCount));
1054 if (offset == 0)
1055 ++offset;
1056
1057 timestamps.clear();
1058 difficulties.clear();
1059 if (height > offset)
1060 {
1061 timestamps.reserve(height - offset);
1062 difficulties.reserve(height - offset);
1063 }
1064 for (; offset < height; offset++)
1065 {
1066 timestamps.push_back(m_db->get_block_timestamp(offset));
1067 difficulties.push_back(m_db->get_block_cumulative_difficulty(offset));
1068 }
1069
1070 m_timestamps_and_difficulties_height = height;
1071 m_timestamps = timestamps;
1072 m_difficulties = difficulties;
1073 }
1074 size_t target = get_difficulty_target();
1075 const uint8_t version = (height >= v6height && height < v7height) ? 6 : 1;
1076 difficulty_type diff = next_difficulty(timestamps, difficulties, target, version);
1077
1078 CRITICAL_REGION_LOCAL1(m_difficulty_lock);
1079 m_difficulty_for_next_block_top_hash = top_hash;
1080 m_difficulty_for_next_block = diff;
1081 return diff;
1082}
uint64_t get_difficulty_target() const
get difficulty target based on chain and hardfork version
#define DIFFICULTY_BLOCKS_COUNT_V6
#define DIFFICULTY_BLOCKS_COUNT
difficulty_type next_difficulty(std::vector< uint64_t > timestamps, std::vector< difficulty_type > cumulative_difficulties, size_t target_seconds, uint8_t version)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_difficulty_target()

uint64_t Blockchain::get_difficulty_target ( ) const

get difficulty target based on chain and hardfork version

Returns
difficulty target

Definition at line 4890 of file blockchain.cpp.

4891{
4893}
#define DIFFICULTY_TARGET
#define DIFFICULTY_TARGET_V6
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_dynamic_base_fee()

uint64_t Blockchain::get_dynamic_base_fee ( uint64_t block_reward,
size_t median_block_weight,
uint8_t version )
static

get dynamic per kB or byte fee for a given block weight

The dynamic fee is based on the block weight in a past window, and the current block reward. It is expressed by kB before v8, and per byte from v8.

Parameters
block_rewardthe current block reward
median_block_weightthe median block weight in the past window
versionhard fork version for rules and constants to use
Returns
the fee

Definition at line 3347 of file blockchain.cpp.

3348{
3349 const uint64_t min_block_weight = get_min_block_weight(version);
3350 if (median_block_weight < min_block_weight)
3351 median_block_weight = min_block_weight;
3352 uint64_t hi, lo;
3353
3355 {
3356 lo = mul128(block_reward, DYNAMIC_FEE_REFERENCE_TRANSACTION_WEIGHT, &hi);
3357 div128_32(hi, lo, min_block_weight, &hi, &lo);
3358 div128_32(hi, lo, median_block_weight, &hi, &lo);
3359 assert(hi == 0);
3360 lo /= 5;
3361 return lo;
3362 }
3363
3365
3366 uint64_t unscaled_fee_base = (fee_base * min_block_weight / median_block_weight);
3367 lo = mul128(unscaled_fee_base, block_reward, &hi);
3368 static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD % 1000000 == 0, "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD must be divisible by 1000000");
3369 static_assert(DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000 <= std::numeric_limits<uint32_t>::max(), "DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD is too large");
3370
3371 // divide in two steps, since the divisor must be 32 bits, but DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD isn't
3372 div128_32(hi, lo, DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD / 1000000, &hi, &lo);
3373 div128_32(hi, lo, 1000000, &hi, &lo);
3374 assert(hi == 0);
3375
3376 // quantize fee up to 8 decimals
3378 uint64_t qlo = (lo + mask - 1) / mask * mask;
3379 MDEBUG("lo " << print_etn(lo) << ", qlo " << print_etn(qlo) << ", mask " << mask);
3380
3381 return qlo;
3382}
#define DYNAMIC_FEE_PER_KB_BASE_FEE_V5
#define DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD
#define DYNAMIC_FEE_REFERENCE_TRANSACTION_WEIGHT
#define DYNAMIC_FEE_PER_KB_BASE_FEE
size_t get_min_block_weight(uint8_t version)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_dynamic_base_fee_estimate()

uint64_t Blockchain::get_dynamic_base_fee_estimate ( uint64_t grace_blocks) const

get dynamic per kB or byte fee estimate for the next few blocks

The dynamic fee is based on the block weight in a past window, and the current block reward. It is expressed by kB before v8, and per byte from v8. This function calculates an estimate for a dynamic fee which will be valid for the next grace_blocks

Parameters
grace_blocksnumber of blocks we want the fee to be valid for
Returns
the fee estimate

Definition at line 3446 of file blockchain.cpp.

3447{
3449 const uint64_t db_height = m_db->height();
3450
3452 if (version >= 11) {
3453 return FEE_PER_KB_V11;
3454 } else if (version < 11 && version >= 6) {
3455 return FEE_PER_KB_V6;
3456 } else {
3457 return FEE_PER_KB;
3458 }
3459 }
3460
3461 if (grace_blocks >= CRYPTONOTE_REWARD_BLOCKS_WINDOW)
3462 grace_blocks = CRYPTONOTE_REWARD_BLOCKS_WINDOW - 1;
3463
3464 const uint64_t min_block_weight = get_min_block_weight(version);
3465 std::vector<uint64_t> weights;
3466 get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks);
3467 weights.reserve(grace_blocks);
3468 for (size_t i = 0; i < grace_blocks; ++i)
3469 weights.push_back(min_block_weight);
3470
3472 if(median <= min_block_weight)
3473 median = min_block_weight;
3474
3475 uint64_t already_generated_coins = db_height ? m_db->get_block_already_generated_coins(db_height - 1) : 0;
3476 uint64_t base_reward;
3477 if (!get_block_reward(median, 1, already_generated_coins, base_reward, version, get_current_blockchain_height(), get_nettype()))
3478 {
3479 MERROR("Failed to determine block reward, using placeholder " << print_etn(BLOCK_REWARD_OVERESTIMATE) << " as a high bound");
3480 base_reward = BLOCK_REWARD_OVERESTIMATE;
3481 }
3482
3483 const bool use_long_term_median_in_fee = version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT;
3484 uint64_t fee = get_dynamic_base_fee(base_reward, use_long_term_median_in_fee ? m_long_term_effective_median_block_weight : median, version);
3485 const bool per_byte = version < HF_VERSION_PER_BYTE_FEE;
3486 MDEBUG("Estimating " << grace_blocks << "-block fee at " << print_etn(fee) << "/" << (per_byte ? "byte" : "kB"));
3487 return fee;
3488}
#define BLOCK_REWARD_OVERESTIMATE
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW
Here is the call graph for this function:

◆ get_earliest_ideal_height_for_version()

uint64_t cryptonote::Blockchain::get_earliest_ideal_height_for_version ( uint8_t version) const
inline

returns the earliest block a given version may activate

Returns
the height

Definition at line 865 of file blockchain.h.

865{ return m_hardfork->get_earliest_ideal_height_for_version(version); }
Here is the caller graph for this function:

◆ get_fee_quantization_mask()

uint64_t Blockchain::get_fee_quantization_mask ( )
static

get fee quantization mask

The dynamic fee may be quantized, to mask out the last decimal places

Returns
the fee quantized mask

Definition at line 3334 of file blockchain.cpp.

3335{
3336 static uint64_t mask = 0;
3337 if (mask == 0)
3338 {
3339 mask = 1;
3341 mask *= 10;
3342 }
3343 return mask;
3344}
#define PER_KB_FEE_QUANTIZATION_DECIMALS
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT
Here is the caller graph for this function:

◆ get_hard_fork_heights()

const std::vector< HardFork::Params > & Blockchain::get_hard_fork_heights ( network_type nettype)
static

gets the hardfork heights of given network

Returns
the HardFork object

Definition at line 4852 of file blockchain.cpp.

4853{
4854 static const std::vector<HardFork::Params> mainnet_heights = []()
4855 {
4856 std::vector<HardFork::Params> heights;
4857 for (const auto& i : mainnet_hard_forks)
4858 heights.emplace_back(i.version, i.height, i.threshold, i.time);
4859 return heights;
4860 }();
4861 static const std::vector<HardFork::Params> testnet_heights = []()
4862 {
4863 std::vector<HardFork::Params> heights;
4864 for (const auto& i : testnet_hard_forks)
4865 heights.emplace_back(i.version, i.height, i.threshold, i.time);
4866 return heights;
4867 }();
4868 static const std::vector<HardFork::Params> stagenet_heights = []()
4869 {
4870 std::vector<HardFork::Params> heights;
4871 for (const auto& i : stagenet_hard_forks)
4872 heights.emplace_back(i.version, i.height, i.threshold, i.time);
4873 return heights;
4874 }();
4875 static const std::vector<HardFork::Params> dummy;
4876 switch (nettype)
4877 {
4878 case MAINNET: return mainnet_heights;
4879 case TESTNET: return testnet_heights;
4880 case STAGENET: return stagenet_heights;
4881 default: return dummy;
4882 }
4883}
Here is the caller graph for this function:

◆ get_hard_fork_state()

HardFork::State Blockchain::get_hard_fork_state ( ) const

gets the hardfork voting state object

Returns
the HardFork object

Definition at line 4847 of file blockchain.cpp.

4848{
4849 return m_hardfork->get_state();
4850}
Here is the caller graph for this function:

◆ get_hard_fork_version()

uint8_t cryptonote::Blockchain::get_hard_fork_version ( uint64_t height) const
inline

returns the actual hardfork version for a given block height

Parameters
heightthe height for which to check version info
Returns
the version

Definition at line 858 of file blockchain.h.

858{ return m_hardfork->get(height); }
Here is the caller graph for this function:

◆ get_hard_fork_voting_info()

bool Blockchain::get_hard_fork_voting_info ( uint8_t version,
uint32_t & window,
uint32_t & votes,
uint32_t & threshold,
uint64_t & earliest_height,
uint8_t & voting ) const

get information about hardfork voting for a version

Parameters
versionthe version in question
windowthe size of the voting window
votesthe number of votes to enable <version>
thresholdthe number of votes required to enable <version>
earliest_heightthe earliest height at which <version> is allowed
votingwhich version this node is voting for/using
Returns
whether the version queried is enabled

Definition at line 4885 of file blockchain.cpp.

4886{
4887 return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting);
4888}
uint8_t threshold
Here is the caller graph for this function:

◆ get_ideal_hard_fork_version() [1/2]

uint8_t cryptonote::Blockchain::get_ideal_hard_fork_version ( ) const
inline

returns the newest hardfork version known to the blockchain

Returns
the version

Definition at line 832 of file blockchain.h.

832{ return m_hardfork->get_ideal_version(); }
Here is the caller graph for this function:

◆ get_ideal_hard_fork_version() [2/2]

uint8_t cryptonote::Blockchain::get_ideal_hard_fork_version ( uint64_t height) const
inline

returns the newest hardfork version voted to be enabled as of a certain height

Parameters
heightthe height for which to check version info
Returns
the version

Definition at line 849 of file blockchain.h.

849{ return m_hardfork->get_ideal_version(height); }

◆ get_last_block_timestamps()

std::vector< time_t > Blockchain::get_last_block_timestamps ( unsigned int blocks) const

returns the timestamps of the last N blocks

Definition at line 1084 of file blockchain.cpp.

1085{
1086 uint64_t height = m_db->height();
1087 if (blocks > height)
1088 blocks = height;
1089 std::vector<time_t> timestamps(blocks);
1090 while (blocks--)
1091 timestamps[blocks] = m_db->get_block_timestamp(height - blocks - 1);
1092 return timestamps;
1093}

◆ get_mempool_tx_livetime()

uint32_t Blockchain::get_mempool_tx_livetime ( ) const

Definition at line 4808 of file blockchain.cpp.

4809{
4811 {
4813 }
4815}
uint8_t get_hard_fork_version(uint64_t height) const
returns the actual hardfork version for a given block height
Definition blockchain.h:858
#define CRYPTONOTE_MEMPOOL_TX_LIVETIME
#define CRYPTONOTE_MEMPOOL_TX_LIVETIME_V6
Here is the call graph for this function:

◆ get_nettype()

network_type cryptonote::Blockchain::get_nettype ( ) const
inline

get blockchain nettype

Definition at line 1073 of file blockchain.h.

1073{ return m_nettype; };
Here is the caller graph for this function:

◆ get_next_hard_fork_version()

uint8_t cryptonote::Blockchain::get_next_hard_fork_version ( ) const
inline

returns the next hardfork version

Returns
the version

Definition at line 839 of file blockchain.h.

839{ return m_hardfork->get_next_version(); }
Here is the caller graph for this function:

◆ get_next_long_term_block_weight()

uint64_t Blockchain::get_next_long_term_block_weight ( uint64_t block_weight) const

gets the long term block weight for a new block

Returns
the long term block weight

Definition at line 4100 of file blockchain.cpp.

4101{
4103
4104 const uint64_t db_height = m_db->height();
4105 const uint64_t nblocks = std::min<uint64_t>(m_long_term_block_weights_window, db_height);
4106
4107 const uint8_t hf_version = get_current_hard_fork_version();
4108 if (hf_version < HF_VERSION_LONG_TERM_BLOCK_WEIGHT)
4109 return block_weight;
4110
4111 uint64_t long_term_median = get_long_term_block_weight_median(db_height - nblocks, nblocks);
4112 uint64_t long_term_effective_median_block_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, long_term_median);
4113
4114 uint64_t short_term_constraint = long_term_effective_median_block_weight + long_term_effective_median_block_weight * 2 / 5;
4115 uint64_t long_term_block_weight = std::min<uint64_t>(block_weight, short_term_constraint);
4116
4117 return long_term_block_weight;
4118}
uint64_t get_next_long_term_block_weight(uint64_t block_weight) const
gets the long term block weight for a new block
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5
#define PERF_TIMER(name)
Definition perf_timer.h:82
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_num_mature_outputs()

uint64_t Blockchain::get_num_mature_outputs ( uint64_t amount) const

get number of outputs of an amount past the minimum spendable age

Parameters
amountthe output amount
Returns
the number of mature outputs

Definition at line 2215 of file blockchain.cpp.

2216{
2217 uint64_t num_outs = m_db->get_num_outputs(amount);
2218 // ensure we don't include outputs that aren't yet eligible to be used
2219 // outpouts are sorted by height
2220 const uint64_t blockchain_height = m_db->height();
2221 while (num_outs > 0)
2222 {
2223 const tx_out_index toi = m_db->get_output_tx_and_index(amount, num_outs - 1);
2224 const uint64_t height = m_db->get_tx_block_height(toi.first);
2226 break;
2227 --num_outs;
2228 }
2229
2230 return num_outs;
2231}
#define ETN_DEFAULT_TX_SPENDABLE_AGE_V8
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE
std::pair< crypto::hash, uint64_t > tx_out_index
Here is the call graph for this function:

◆ get_output_distribution()

bool Blockchain::get_output_distribution ( uint64_t amount,
uint64_t from_height,
uint64_t to_height,
uint64_t & start_height,
std::vector< uint64_t > & distribution,
uint64_t & base ) const

gets per block distribution of outputs of a given amount

Parameters
amountthe amount to get a ditribution for
from_heightthe height before which we do not care about the data
to_heightthe height after which we do not care about the data
return-by-referencestart_height the height of the first rct output
return-by-referencedistribution the start offset of the first rct output in this block (same as previous if none)
return-by-referencebase how many outputs of that amount are before the stated distribution

Definition at line 2293 of file blockchain.cpp.

2294{
2295 // rct outputs don't exist before v4
2296 if (amount == 0)
2297 {
2298 switch (m_nettype)
2299 {
2300 case STAGENET: start_height = stagenet_hard_forks[3].height; break;
2301 case TESTNET: start_height = testnet_hard_forks[3].height; break;
2302 case MAINNET: start_height = mainnet_hard_forks[3].height; break;
2303 case FAKECHAIN: start_height = 0; break;
2304 default: return false;
2305 }
2306 }
2307 else
2308 start_height = 0;
2309 base = 0;
2310
2311 if (to_height > 0 && to_height < from_height)
2312 return false;
2313
2314 const uint64_t real_start_height = start_height;
2315 if (from_height > start_height)
2316 start_height = from_height;
2317
2318 distribution.clear();
2319 uint64_t db_height = m_db->height();
2320 if (db_height == 0)
2321 return false;
2322 if (start_height >= db_height || to_height >= db_height)
2323 return false;
2324 if (amount == 0)
2325 {
2326 std::vector<uint64_t> heights;
2327 heights.reserve(to_height + 1 - start_height);
2328 uint64_t real_start_height = start_height > 0 ? start_height-1 : start_height;
2329 for (uint64_t h = real_start_height; h <= to_height; ++h)
2330 heights.push_back(h);
2331 distribution = m_db->get_block_cumulative_rct_outputs(heights);
2332 if (start_height > 0)
2333 {
2334 base = distribution[0];
2335 distribution.erase(distribution.begin());
2336 }
2337 return true;
2338 }
2339 else
2340 {
2341 return m_db->get_output_distribution(amount, start_height, to_height, distribution, base);
2342 }
2343}

◆ get_output_histogram()

std::map< uint64_t, std::tuple< uint64_t, uint64_t, uint64_t > > Blockchain::get_output_histogram ( const std::vector< uint64_t > & amounts,
bool unlocked,
uint64_t recent_cutoff,
uint64_t min_count = 0 ) const

return a histogram of outputs on the blockchain

Parameters
amountsoptional set of amounts to lookup
unlockedwhether to restrict instances to unlocked ones
recent_cutofftimestamp to consider outputs as recent
min_countreturn only amounts with at least that many instances
Returns
a set of amount/instances

Definition at line 4895 of file blockchain.cpp.

4896{
4897 return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count);
4898}

◆ get_output_key()

crypto::public_key Blockchain::get_output_key ( uint64_t amount,
uint64_t global_index ) const

get the public key for an output

Parameters
amountthe output amount
global_indexthe output amount-global index
Returns
the public key

Definition at line 2233 of file blockchain.cpp.

2234{
2235 output_data_t data = m_db->get_output_key(amount, global_index);
2236 return data.pubkey;
2237}
crypto::public_key pubkey
the output's public key (for spend verification)

◆ get_output_key_mask_unlocked()

void Blockchain::get_output_key_mask_unlocked ( const uint64_t & amount,
const uint64_t & index,
crypto::public_key & key,
rct::key & mask,
bool & unlocked ) const

gets an output's key and unlocked state

Parameters
amountin - the output amount
indexin - the output global amount index
maskout - the output's RingCT mask
keyout - the output's key
unlockedout - the output's unlocked state

Definition at line 2284 of file blockchain.cpp.

2285{
2286 const auto o_data = m_db->get_output_key(amount, index);
2287 key = o_data.pubkey;
2288 mask = o_data.commitment;
2289 tx_out_index toi = m_db->get_output_tx_and_index(amount, index);
2290 unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first));
2291}
const char * key

◆ get_outs()

bool Blockchain::get_outs ( const COMMAND_RPC_GET_OUTPUTS_BIN::request & req,
COMMAND_RPC_GET_OUTPUTS_BIN::response & res ) const

gets specific outputs to mix with

This function takes an RPC request for outputs to mix with and creates an RPC response with the resultant output indices.

Outputs to mix with are specified in the request.

Parameters
reqthe outputs to return
resreturn-by-reference the resultant output indices and keys
Returns
true

Definition at line 2240 of file blockchain.cpp.

2241{
2242 LOG_PRINT_L3("Blockchain::" << __func__);
2243 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2244
2245 res.outs.clear();
2246 res.outs.reserve(req.outputs.size());
2247
2248 std::vector<cryptonote::output_data_t> data;
2249 try
2250 {
2251 std::vector<uint64_t> amounts, offsets;
2252 amounts.reserve(req.outputs.size());
2253 offsets.reserve(req.outputs.size());
2254 for (const auto &i: req.outputs)
2255 {
2256 amounts.push_back(i.amount);
2257 offsets.push_back(i.index);
2258 }
2259 m_db->get_output_key(epee::span<const uint64_t>(amounts.data(), amounts.size()), offsets, data);
2260 if (data.size() != req.outputs.size())
2261 {
2262 MERROR("Unexpected output data size: expected " << req.outputs.size() << ", got " << data.size());
2263 return false;
2264 }
2265 for (const auto &t: data)
2266 res.outs.push_back({t.pubkey, t.commitment, is_tx_spendtime_unlocked(t.unlock_time), t.height, crypto::null_hash});
2267
2268 if (req.get_txid)
2269 {
2270 for (size_t i = 0; i < req.outputs.size(); ++i)
2271 {
2272 tx_out_index toi = m_db->get_output_tx_and_index(req.outputs[i].amount, req.outputs[i].index);
2273 res.outs[i].txid = toi.first;
2274 }
2275 }
2276 }
2277 catch (const std::exception &e)
2278 {
2279 return false;
2280 }
2281 return true;
2282}

◆ get_short_chain_history()

bool Blockchain::get_short_chain_history ( std::list< crypto::hash > & ids) const

gets the hashes for a subset of the blockchain

puts into list <ids> a list of hashes representing certain blocks from the blockchain in reverse chronological order

the blocks chosen, at the time of this writing, are: the most recent 11 powers of 2 less recent from there, so 13, 17, 25, etc...

Parameters
idsreturn-by-reference list to put the resulting hashes in
Returns
true

Definition at line 859 of file blockchain.cpp.

860{
861 LOG_PRINT_L3("Blockchain::" << __func__);
862 CRITICAL_REGION_LOCAL(m_blockchain_lock);
863 uint64_t i = 0;
864 uint64_t current_multiplier = 1;
865 uint64_t sz = m_db->height();
866
867 if(!sz)
868 return true;
869
870 db_rtxn_guard rtxn_guard(m_db);
871 bool genesis_included = false;
872 uint64_t current_back_offset = 1;
873 while(current_back_offset < sz)
874 {
875 ids.push_back(m_db->get_block_hash_from_height(sz - current_back_offset));
876
877 if(sz-current_back_offset == 0)
878 {
879 genesis_included = true;
880 }
881 if(i < 10)
882 {
883 ++current_back_offset;
884 }
885 else
886 {
887 current_multiplier *= 2;
888 current_back_offset += current_multiplier;
889 }
890 ++i;
891 }
892
893 if (!genesis_included)
894 {
895 ids.push_back(m_db->get_block_hash_from_height(0));
896 }
897
898 return true;
899}

◆ get_split_transactions_blobs()

template<class t_ids_container, class t_tx_container, class t_missed_container>
template bool cryptonote::Blockchain::get_split_transactions_blobs ( const t_ids_container & txs_ids,
t_tx_container & txs,
t_missed_container & missed_txs ) const

Definition at line 2500 of file blockchain.cpp.

2501{
2502 LOG_PRINT_L3("Blockchain::" << __func__);
2503 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2504
2505 reserve_container(txs, txs_ids.size());
2506 for (const auto& tx_hash : txs_ids)
2507 {
2508 try
2509 {
2511 if (m_db->get_pruned_tx_blob(tx_hash, tx))
2512 {
2513 txs.push_back(std::make_tuple(tx_hash, std::move(tx), crypto::null_hash, cryptonote::blobdata()));
2514 if (!is_v1_tx(std::get<1>(txs.back())) && !m_db->get_prunable_tx_hash(tx_hash, std::get<2>(txs.back())))
2515 {
2516 MERROR("Prunable data hash not found for " << tx_hash);
2517 return false;
2518 }
2519 if (!m_db->get_prunable_tx_blob(tx_hash, std::get<3>(txs.back())))
2520 std::get<3>(txs.back()).clear();
2521 }
2522 else
2523 missed_txs.push_back(tx_hash);
2524 }
2525 catch (const std::exception& e)
2526 {
2527 return false;
2528 }
2529 }
2530 return true;
2531}
bool is_v1_tx(const blobdata_ref &tx_blob)
Here is the call graph for this function:

◆ get_tail_id() [1/2]

crypto::hash Blockchain::get_tail_id ( ) const

get the hash of the most recent block on the blockchain

Returns
the hash

Definition at line 837 of file blockchain.cpp.

838{
839 LOG_PRINT_L3("Blockchain::" << __func__);
840 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
841 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
842 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
843 // lock if it is otherwise needed.
844 return m_db->top_block_hash();
845}
Here is the caller graph for this function:

◆ get_tail_id() [2/2]

crypto::hash Blockchain::get_tail_id ( uint64_t & height) const

get the height and hash of the most recent block on the blockchain

Parameters
heightreturn-by-reference variable to store the height in
Returns
the hash

Definition at line 830 of file blockchain.cpp.

831{
832 LOG_PRINT_L3("Blockchain::" << __func__);
833 CRITICAL_REGION_LOCAL(m_blockchain_lock);
834 return m_db->top_block_hash(&height);
835}

◆ get_total_transactions()

size_t Blockchain::get_total_transactions ( ) const

gets the total number of transactions on the main chain

Returns
the number of transactions on the main chain

Definition at line 2721 of file blockchain.cpp.

2722{
2723 LOG_PRINT_L3("Blockchain::" << __func__);
2724 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
2725 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
2726 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
2727 // lock if it is otherwise needed.
2728 return m_db->get_tx_count();
2729}

◆ get_transactions()

template<class t_ids_container, class t_tx_container, class t_missed_container>
template bool cryptonote::Blockchain::get_transactions ( const t_ids_container & txs_ids,
t_tx_container & txs,
t_missed_container & missed_txs ) const

Definition at line 2534 of file blockchain.cpp.

2535{
2536 LOG_PRINT_L3("Blockchain::" << __func__);
2537 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2538
2539 reserve_container(txs, txs_ids.size());
2540 for (const auto& tx_hash : txs_ids)
2541 {
2542 try
2543 {
2545 if (m_db->get_tx_blob(tx_hash, tx))
2546 {
2547 txs.push_back(transaction());
2548 if (!parse_and_validate_tx_from_blob(tx, txs.back()))
2549 {
2550 LOG_ERROR("Invalid transaction");
2551 return false;
2552 }
2553 }
2554 else
2555 missed_txs.push_back(tx_hash);
2556 }
2557 catch (const std::exception& e)
2558 {
2559 return false;
2560 }
2561 }
2562 return true;
2563}
bool parse_and_validate_tx_from_blob(const blobdata &tx_blob, transaction &tx)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_transactions_blobs() [1/2]

template<class t_ids_container, class t_tx_container, class t_missed_container>
bool cryptonote::Blockchain::get_transactions_blobs ( const t_ids_container & txs_ids,
t_tx_container & txs,
t_missed_container & missed_txs,
bool pruned ) const

Definition at line 2462 of file blockchain.cpp.

2463{
2464 LOG_PRINT_L3("Blockchain::" << __func__);
2465 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2466
2467 reserve_container(txs, txs_ids.size());
2468 for (const auto& tx_hash : txs_ids)
2469 {
2470 try
2471 {
2473 if (pruned && m_db->get_pruned_tx_blob(tx_hash, tx))
2474 txs.push_back(std::move(tx));
2475 else if (!pruned && m_db->get_tx_blob(tx_hash, tx))
2476 txs.push_back(std::move(tx));
2477 else
2478 missed_txs.push_back(tx_hash);
2479 }
2480 catch (const std::exception& e)
2481 {
2482 return false;
2483 }
2484 }
2485 return true;
2486}
Here is the call graph for this function:

◆ get_transactions_blobs() [2/2]

template<class t_ids_container, class t_tx_container, class t_missed_container>
bool cryptonote::Blockchain::get_transactions_blobs ( const t_ids_container & txs_ids,
t_tx_container & txs,
t_missed_container & missed_txs,
bool pruned = false ) const

gets transactions based on a list of transaction hashes

Template Parameters
t_ids_containera standard-iterable container
t_tx_containera standard-iterable container
t_missed_containera standard-iterable container
Parameters
txs_idsa container of hashes for which to get the corresponding transactions
txsreturn-by-reference a container to store result transactions in
missed_txsreturn-by-reference a container to store missed transactions in
prunedwhether to return full or pruned blobs
Returns
false if an unexpected exception occurs, else true
Here is the caller graph for this function:

◆ get_tx_outputs_gindexs() [1/2]

bool Blockchain::get_tx_outputs_gindexs ( const crypto::hash & tx_id,
size_t n_txes,
std::vector< std::vector< uint64_t > > & indexs ) const

Definition at line 2801 of file blockchain.cpp.

2802{
2803 LOG_PRINT_L3("Blockchain::" << __func__);
2804 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2805 uint64_t tx_index;
2806 if (!m_db->tx_exists(tx_id, tx_index))
2807 {
2808 MERROR_VER("get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
2809 return false;
2810 }
2811
2812 //no output indexes for tx.version >= 2 (public tx)
2813 if (m_db->get_tx(tx_id).version >= 2)
2814 return true;
2815
2816 indexs = m_db->get_tx_amount_output_indices(tx_index, n_txes);
2817 CHECK_AND_ASSERT_MES(n_txes == indexs.size(), false, "Wrong indexs size");
2818
2819 return true;
2820}

◆ get_tx_outputs_gindexs() [2/2]

bool Blockchain::get_tx_outputs_gindexs ( const crypto::hash & tx_id,
std::vector< uint64_t > & indexs ) const

gets the global indices for outputs from a given transaction

This function gets the global indices for all outputs belonging to a specific transaction.

Parameters
tx_idthe hash of the transaction to fetch indices for
indexsreturn-by-reference the global indices for the transaction's outputs
n_txeshow many txes in a row to get results for
Returns
false if the transaction does not exist, or if no indices are found, otherwise true

Definition at line 2822 of file blockchain.cpp.

2823{
2824 LOG_PRINT_L3("Blockchain::" << __func__);
2825 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2826 uint64_t tx_index;
2827 if (!m_db->tx_exists(tx_id, tx_index))
2828 {
2829 MERROR_VER("get_tx_outputs_gindexs failed to find transaction with id = " << tx_id);
2830 return false;
2831 }
2832
2833 //no output indexes for tx.version >= 2 (public tx)
2834 if (m_db->get_tx(tx_id).version >= 2)
2835 return true;
2836
2837 std::vector<std::vector<uint64_t>> indices = m_db->get_tx_amount_output_indices(tx_index, 1);
2838 CHECK_AND_ASSERT_MES(indices.size() == 1, false, "Wrong indices size");
2839 indexs = indices.front();
2840 return true;
2841}

◆ get_txpool_tx_blob() [1/2]

cryptonote::blobdata Blockchain::get_txpool_tx_blob ( const crypto::hash & txid) const

Definition at line 4798 of file blockchain.cpp.

4799{
4800 return m_db->get_txpool_tx_blob(txid);
4801}

◆ get_txpool_tx_blob() [2/2]

bool Blockchain::get_txpool_tx_blob ( const crypto::hash & txid,
cryptonote::blobdata & bd ) const

Definition at line 4793 of file blockchain.cpp.

4794{
4795 return m_db->get_txpool_tx_blob(txid, bd);
4796}

◆ get_txpool_tx_count()

uint64_t Blockchain::get_txpool_tx_count ( bool include_unrelayed_txes = true) const

Definition at line 4783 of file blockchain.cpp.

4784{
4785 return m_db->get_txpool_tx_count(include_unrelayed_txes);
4786}

◆ get_txpool_tx_meta()

bool Blockchain::get_txpool_tx_meta ( const crypto::hash & txid,
txpool_tx_meta_t & meta ) const

Definition at line 4788 of file blockchain.cpp.

4789{
4790 return m_db->get_txpool_tx_meta(txid, meta);
4791}

◆ get_validator_by_height()

electroneum::basic::Validator Blockchain::get_validator_by_height ( uint64_t height)

Definition at line 5085 of file blockchain.cpp.

5085 {
5086
5087 block blk;
5089
5090 std::string signatory = std::string(blk.signatory.begin(), blk.signatory.end());
5091 return m_validators->getValidatorByKey(boost::algorithm::hex(signatory));
5092
5093}
crypto::hash get_block_id_by_height(uint64_t height) const
gets a block's hash given a height
std::vector< uint8_t > signatory
Here is the call graph for this function:

◆ handle_get_objects()

bool Blockchain::handle_get_objects ( NOTIFY_REQUEST_GET_OBJECTS::request & arg,
NOTIFY_RESPONSE_GET_OBJECTS::request & rsp )

retrieves a set of blocks and their transactions, and possibly other transactions

the request object encapsulates a list of block hashes and a (possibly empty) list of transaction hashes. for each block hash, the block is fetched along with all of that block's transactions. Any transactions requested separately are fetched afterwards.

Parameters
argthe request
rspreturn-by-reference the response to fill in
Returns
true unless any blocks or transactions are missing

Definition at line 2146 of file blockchain.cpp.

2147{
2148 LOG_PRINT_L3("Blockchain::" << __func__);
2149 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2150 db_rtxn_guard rtxn_guard (m_db);
2151 rsp.current_blockchain_height = get_current_blockchain_height();
2152 std::vector<std::pair<cryptonote::blobdata,block>> blocks;
2153 get_blocks(arg.blocks, blocks, rsp.missed_ids);
2154
2155 for (auto& bl: blocks)
2156 {
2157 std::vector<crypto::hash> missed_tx_ids;
2158
2159 rsp.blocks.push_back(block_complete_entry());
2160 block_complete_entry& e = rsp.blocks.back();
2161
2162 // FIXME: s/rsp.missed_ids/missed_tx_id/ ? Seems like rsp.missed_ids
2163 // is for missed blocks, not missed transactions as well.
2164 get_transactions_blobs(bl.second.tx_hashes, e.txs, missed_tx_ids);
2165
2166 if (missed_tx_ids.size() != 0)
2167 {
2168 // do not display an error if the peer asked for an unpruned block which we are not meant to have
2170 {
2171 LOG_ERROR("Error retrieving blocks, missed " << missed_tx_ids.size()
2172 << " transactions for block with hash: " << get_block_hash(bl.second)
2173 << std::endl
2174 );
2175 }
2176
2177 // append missed transaction hashes to response missed_ids field,
2178 // as done below if any standalone transactions were requested
2179 // and missed.
2180 rsp.missed_ids.insert(rsp.missed_ids.end(), missed_tx_ids.begin(), missed_tx_ids.end());
2181 return false;
2182 }
2183
2184 //pack block
2185 e.block = std::move(bl.first);
2186 }
2187 //get and pack other transactions, if needed
2188 get_transactions_blobs(arg.txs, rsp.txs, rsp.missed_ids);
2189
2190 return true;
2191}
bool has_unpruned_block(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed)
Definition pruning.cpp:44
std::vector< blobdata > txs
blobdata block
Here is the call graph for this function:

◆ have_block()

bool Blockchain::have_block ( const crypto::hash & id) const

checks if a block is known about with a given hash

This function checks the main chain, alternate chains, and invalid blocks for a block with the given hash

Parameters
idthe hash to search for
Returns
true if the block is known, else false

Definition at line 2688 of file blockchain.cpp.

2689{
2690 LOG_PRINT_L3("Blockchain::" << __func__);
2691 CRITICAL_REGION_LOCAL(m_blockchain_lock);
2692
2693 if(m_db->block_exists(id))
2694 {
2695 LOG_PRINT_L2("block " << id << " found in main chain");
2696 return true;
2697 }
2698
2699 if(m_alternative_chains.count(id))
2700 {
2701 LOG_PRINT_L2("block " << id << " found in m_alternative_chains");
2702 return true;
2703 }
2704
2705 if(m_invalid_blocks.count(id))
2706 {
2707 LOG_PRINT_L2("block " << id << " found in m_invalid_blocks");
2708 return true;
2709 }
2710
2711 return false;
2712}
#define LOG_PRINT_L2(x)
Here is the caller graph for this function:

◆ have_tx()

bool Blockchain::have_tx ( const crypto::hash & id) const

search the blockchain for a transaction by hash

Parameters
idthe hash to search for
Returns
true if the tx exists, else false

Definition at line 167 of file blockchain.cpp.

168{
169 LOG_PRINT_L3("Blockchain::" << __func__);
170 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
171 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
172 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
173 // lock if it is otherwise needed.
174 return m_db->tx_exists(id);
175}

◆ have_tx_keyimg_as_spent()

bool Blockchain::have_tx_keyimg_as_spent ( const crypto::key_image & key_im) const

check if a key image is already spent on the blockchain

Whenever a transaction output is used as an input for another transaction (a true input, not just one of a mixing set), a key image is generated and stored in the transaction in order to prevent double spending. If this key image is seen again, the transaction using it is rejected.

Parameters
key_imthe key image to search for
Returns
true if the key image is already spent in the blockchain, else false

Definition at line 177 of file blockchain.cpp.

178{
179 LOG_PRINT_L3("Blockchain::" << __func__);
180 // WARNING: this function does not take m_blockchain_lock, and thus should only call read only
181 // m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
182 // well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
183 // lock if it is otherwise needed.
184 return m_db->has_key_image(key_im);
185}
Here is the caller graph for this function:

◆ init() [1/2]

bool Blockchain::init ( BlockchainDB * db,
const network_type nettype = MAINNET,
bool offline = false,
const cryptonote::test_options * test_options = NULL,
difficulty_type fixed_difficulty = 0,
const GetCheckpointsCallback & get_checkpoints = nullptr,
bool ignore_bsig = false,
bool fallback_to_pow = false )

Initialize the Blockchain state.

Parameters
dba pointer to the backing store to use for the blockchain
nettypenetwork type
offlinetrue if running offline, else false
test_optionstest parameters
fixed_difficultyfixed difficulty for testing purposes; 0 means disabled
get_checkpointsif set, will be called to get checkpoints data
Returns
true on success, false if any initialization steps fail

Definition at line 334 of file blockchain.cpp.

335{
336 LOG_PRINT_L3("Blockchain::" << __func__);
337
338 CHECK_AND_ASSERT_MES(nettype != FAKECHAIN || test_options, false, "fake chain network type used without options");
339
340 CRITICAL_REGION_LOCAL(m_tx_pool);
341 CRITICAL_REGION_LOCAL1(m_blockchain_lock);
342
343 if (db == nullptr)
344 {
345 LOG_ERROR("Attempted to init Blockchain with null DB");
346 return false;
347 }
348 if (!db->is_open())
349 {
350 LOG_ERROR("Attempted to init Blockchain with unopened DB");
351 delete db;
352 return false;
353 }
354
355 m_db = db;
356
357 m_nettype = test_options != NULL ? FAKECHAIN : nettype;
358 m_offline = offline;
359 m_fixed_difficulty = fixed_difficulty;
360 m_ignore_bsig = ignore_bsig;
361 m_fallback_to_pow = fallback_to_pow;
362 if (m_hardfork == nullptr)
363 {
364 if (m_nettype == FAKECHAIN || m_nettype == STAGENET)
365 m_hardfork = new HardFork(*db, 1, 0);
366 else if (m_nettype == TESTNET)
367 m_hardfork = new HardFork(*db, 1, testnet_hard_fork_version_1_till);
368 else
369 m_hardfork = new HardFork(*db, 1, mainnet_hard_fork_version_1_till);
370 }
371 if (m_nettype == FAKECHAIN)
372 {
373 for (size_t n = 0; test_options->hard_forks[n].first; ++n)
374 m_hardfork->add_fork(test_options->hard_forks[n].first, test_options->hard_forks[n].second, 0, n + 1);
375 }
376 else if (m_nettype == TESTNET)
377 {
378 for (size_t n = 0; n < sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]); ++n)
379 m_hardfork->add_fork(testnet_hard_forks[n].version, testnet_hard_forks[n].height, testnet_hard_forks[n].threshold, testnet_hard_forks[n].time);
380 }
381 else if (m_nettype == STAGENET)
382 {
383 for (size_t n = 0; n < sizeof(stagenet_hard_forks) / sizeof(stagenet_hard_forks[0]); ++n)
384 m_hardfork->add_fork(stagenet_hard_forks[n].version, stagenet_hard_forks[n].height, stagenet_hard_forks[n].threshold, stagenet_hard_forks[n].time);
385 }
386 else
387 {
388 for (size_t n = 0; n < sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]); ++n)
389 m_hardfork->add_fork(mainnet_hard_forks[n].version, mainnet_hard_forks[n].height, mainnet_hard_forks[n].threshold, mainnet_hard_forks[n].time);
390 }
391 m_hardfork->init();
392
393 m_db->set_hard_fork(m_hardfork);
394
395 // if the blockchain is new, add the genesis block
396 // this feels kinda kludgy to do it this way, but can be looked at later.
397 // TODO: add function to create and store genesis block,
398 // taking testnet into account
399 if(!m_db->height())
400 {
401 MINFO("Blockchain not loaded, generating genesis block.");
402 block bl;
403 block_verification_context bvc = boost::value_initialized<block_verification_context>();
404 generate_genesis_block(bl, get_config(m_nettype).GENESIS_TX, get_config(m_nettype).GENESIS_NONCE);
405 db_wtxn_guard wtxn_guard(m_db);
406 add_new_block(bl, bvc);
407 CHECK_AND_ASSERT_MES(!bvc.m_verification_failed, false, "Failed to add genesis block to blockchain");
408 }
409 // TODO: if blockchain load successful, verify blockchain against both
410 // hard-coded and runtime-loaded (and enforced) checkpoints.
411 else
412 {
413 }
414
415 if (m_nettype != FAKECHAIN)
416 {
417 m_db->set_batch_transactions(true);
418 }
419
420 db_rtxn_guard rtxn_guard(m_db);
421
422 // check how far behind we are
423 uint64_t top_block_timestamp = m_db->get_top_block_timestamp();
424 uint64_t timestamp_diff = time(NULL) - top_block_timestamp;
425
426 // genesis block has no timestamp, could probably change it to have timestamp of 1397818133...
427 if(!top_block_timestamp)
428 timestamp_diff = time(NULL) - 1397818133;
429
430 // create general purpose async service queue
431
432 m_async_work_idle = std::unique_ptr < boost::asio::io_service::work > (new boost::asio::io_service::work(m_async_service));
433 // we only need 1
434 m_async_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_async_service));
435
436#if defined(PER_BLOCK_CHECKPOINT)
437 if (m_nettype != FAKECHAIN)
438 load_compiled_in_block_hashes(get_checkpoints);
439#endif
440
441 MINFO("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block());
442
443 rtxn_guard.stop();
444
445 uint64_t num_popped_blocks = 0;
446 while (!m_db->is_read_only())
447 {
448 uint64_t top_height;
449 const crypto::hash top_id = m_db->top_block_hash(&top_height);
450 const block top_block = m_db->get_top_block();
451 const uint8_t ideal_hf_version = get_ideal_hard_fork_version(top_height);
452 if (ideal_hf_version <= 1 || ideal_hf_version == top_block.major_version)
453 {
454 if (num_popped_blocks > 0)
455 MGINFO("Initial popping done, top block: " << top_id << ", top height: " << top_height << ", block version: " << (uint64_t)top_block.major_version);
456 break;
457 }
458 else
459 {
460 if (num_popped_blocks == 0)
461 MGINFO("Current top block " << top_id << " at height " << top_height << " has version " << (uint64_t)top_block.major_version << " which disagrees with the ideal version " << (uint64_t)ideal_hf_version);
462 if (num_popped_blocks % 100 == 0)
463 MGINFO("Popping blocks... " << top_height);
464 ++num_popped_blocks;
465 block popped_block;
466 std::vector<transaction> popped_txs;
467 try
468 {
469 m_db->pop_block(popped_block, popped_txs);
470 }
471 // anything that could cause this to throw is likely catastrophic,
472 // so we re-throw
473 catch (const std::exception& e)
474 {
475 MERROR("Error popping block from blockchain: " << e.what());
476 throw;
477 }
478 catch (...)
479 {
480 MERROR("Error popping block from blockchain, throwing!");
481 throw;
482 }
483 }
484 }
485
486 if (num_popped_blocks > 0)
487 {
488 m_timestamps_and_difficulties_height = 0;
489 m_hardfork->reorganize_from_chain_height(get_current_blockchain_height());
490 uint64_t top_block_height;
491 crypto::hash top_block_hash = get_tail_id(top_block_height);
492 m_tx_pool.on_blockchain_dec(top_block_height, top_block_hash);
493 }
494
495 if (test_options && test_options->long_term_block_weight_window)
496 {
497 m_long_term_block_weights_window = test_options->long_term_block_weight_window;
498 m_long_term_block_weights_cache_rolling_median = epee::misc_utils::rolling_median_t<uint64_t>(m_long_term_block_weights_window);
499 }
500
501 {
502 db_txn_guard txn_guard(m_db, m_db->is_read_only());
503 if (!update_next_cumulative_weight_limit())
504 return false;
505 }
506
507 {
508 if(!m_db->is_read_only())
509 {
510 uint64_t top_height;
511 m_db->top_block_hash(&top_height);
512
513 if(top_height >= 1175315)
514 {
515 block b = m_db->get_block_from_height(1175315);
516 const auto &txout = boost::get<txout_to_key_public>(b.miner_tx.vout[0].target);
517 std::vector<cryptonote::address_outputs> addr_outs = m_db->get_addr_output_all(addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key));
518
519 if(addr_outs.empty()) {
520 MGINFO("Recomputing address_outputs database...");
521 m_db->top_block_hash(&top_height);
522 uint64_t diff = top_height - 1175200;
523 for(auto i = 0; i < diff; i++) {
524 block popped_block;
525 std::vector<transaction> popped_txs;
526 try
527 {
528 m_db->pop_block(popped_block, popped_txs);
529 }
530 catch (const std::exception& e)
531 {
532 MERROR("Error popping block from blockchain: " << e.what());
533 throw;
534 }
535 catch (...)
536 {
537 MERROR("Error popping block from blockchain, throwing!");
538 throw;
539 }
540 }
541 if (diff > 0)
542 {
543 m_hardfork->reorganize_from_chain_height(get_current_blockchain_height());
544 uint64_t top_block_height;
545 crypto::hash top_block_hash = get_tail_id(top_block_height);
546 m_tx_pool.on_blockchain_dec(top_block_height, top_block_hash);
547 }
548 MGINFO("Address_outputs database recomputed OK");
549 }
550 }
551 }
552 }
553
554 // GO BACK AND POPULATE A DATABASE OF KEY: COMBINED KEY , VALUE: TX INPUT
555 {
556 db_txn_guard txn_guard(m_db, m_db->is_read_only());
557 if(!m_db->is_read_only())
558 {
559 uint64_t top_height;
560 m_db->top_block_hash(&top_height);
561 uint64_t private_to_public_fork_height = m_nettype == MAINNET ? 1175315 : 1086402;
562 if(top_height >= private_to_public_fork_height)
563 {
564 block b = m_db->get_block_from_height(private_to_public_fork_height);
565 const auto &txout = boost::get<txout_to_key_public>(b.miner_tx.vout[0].target);
566 std::vector<cryptonote::address_txs> addr_txs = m_db->get_addr_tx_all(addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key));
567 if(addr_txs.empty()) {
568 MGINFO("Populating addr tx database...");
569 m_db->top_block_hash(&top_height);
570 // begin at the private to public fork block and store the data in addr_tx db one block at a time
571 uint64_t working_height = private_to_public_fork_height;
572 while (working_height <= top_height) {
573 block working_block = m_db->get_block_from_height(working_height);
574 //deal with miner tx first
575 for( auto vout: working_block.miner_tx.vout){ // all vouts are of type txout to key public
576 const auto &txout = boost::get<txout_to_key_public>(vout.target);
577 m_db->add_addr_tx(get_transaction_hash(working_block.miner_tx), addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key));
578
579 }
580 //deal with all other tx
581 std::vector<transaction> transactions = m_db->get_tx_list(working_block.tx_hashes);
582 for (auto tx : transactions){
583 auto hash = get_transaction_hash(tx);
584 std::unordered_set<crypto::public_key> addr_tx_addresses;
585 for (size_t i = 0; i < tx.vin.size(); i++){
586 if (tx.vin[i].type() == typeid(txin_to_key_public))
587 {
588 const auto &txin = boost::get<txin_to_key_public>(tx.vin[i]);
589 transaction parent_tx = m_db->get_tx(txin.tx_hash);
590 const auto &txout = boost::get<txout_to_key_public>(parent_tx.vout[txin.relative_offset].target); //previous tx out that this tx in references
591 crypto::public_key combined_key = addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key);
592 if(addr_tx_addresses.find(combined_key) == addr_tx_addresses.end()){ //if addr hasn't been used for another input yet, add the unique addr tx record for this address
593 m_db->add_addr_tx(hash, combined_key);
594 addr_tx_addresses.emplace(combined_key);
595 }
596 }
597 }
598 for(size_t i = 0; i < tx.vout.size(); i++){ // all vouts are of type txout to key public
599 const auto &txout = boost::get<txout_to_key_public>(tx.vout[i].target);
600 crypto::public_key combined_key = addKeys(txout.address.m_view_public_key, txout.address.m_spend_public_key);
601 if(addr_tx_addresses.find(combined_key) == addr_tx_addresses.end()){ //if addr hasn't been used for another input yet, add the unique addr tx record for this address
602 m_db->add_addr_tx(tx.hash, combined_key);
603 addr_tx_addresses.emplace(combined_key);
604 }
605 }
606 }
607 ++working_height;
608 }
609 MGINFO("Addr_txs database recomputed OK");
610 }
611
612 }
613 }
614
615 txn_guard.stop();
616 }
617 return true;
618}
bool is_open() const
Gets the current open/ready state of the BlockchainDB.
uint8_t get_ideal_hard_fork_version() const
returns the newest hardfork version known to the blockchain
Definition blockchain.h:832
bool add_new_block(const block &bl_, block_verification_context &bvc)
adds a block to the blockchain
#define MGINFO(x)
Definition misc_log_ex.h:80
public_key addKeys(const public_key &A, const public_key &B)
Definition crypto.h:339
POD_CLASS public_key
Definition crypto.h:79
bool generate_genesis_block(block &bl, std::string const &genesis_tx, uint32_t nonce)
std::string get_time_interval_string(const time_t &time_)
const size_t long_term_block_weight_window
const std::pair< uint8_t, uint64_t > * hard_forks
Here is the call graph for this function:
Here is the caller graph for this function:

◆ init() [2/2]

bool Blockchain::init ( BlockchainDB * db,
HardFork *& hf,
const network_type nettype = MAINNET,
bool offline = false )

Initialize the Blockchain state.

Parameters
dba pointer to the backing store to use for the blockchain
hfa structure containing hardfork information
nettypenetwork type
offlinetrue if running offline, else false
Returns
true on success, false if any initialization steps fail

Definition at line 620 of file blockchain.cpp.

621{
622 if (hf != nullptr)
623 m_hardfork = hf;
624 bool res = init(db, nettype, offline, NULL);
625 if (hf == nullptr)
626 hf = m_hardfork;
627 return res;
628}
bool init(BlockchainDB *db, const network_type nettype=MAINNET, bool offline=false, const cryptonote::test_options *test_options=NULL, difficulty_type fixed_difficulty=0, const GetCheckpointsCallback &get_checkpoints=nullptr, bool ignore_bsig=false, bool fallback_to_pow=false)
Initialize the Blockchain state.
Here is the call graph for this function:

◆ is_within_compiled_block_hash_area() [1/2]

bool cryptonote::Blockchain::is_within_compiled_block_hash_area ( ) const
inline

Definition at line 1016 of file blockchain.h.

1016{ return is_within_compiled_block_hash_area(m_db->height()); }
bool is_within_compiled_block_hash_area() const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_within_compiled_block_hash_area() [2/2]

bool Blockchain::is_within_compiled_block_hash_area ( uint64_t height) const

Definition at line 5022 of file blockchain.cpp.

5023{
5024#if defined(PER_BLOCK_CHECKPOINT)
5025 return height < m_blocks_hash_check.size();
5026#else
5027 return false;
5028#endif
5029}

◆ key_images_already_spent()

bool Blockchain::key_images_already_spent ( const transaction & tx) const

check if any key image in a transaction has already been spent

Parameters
txthe transaction to check
Returns
true if any key image is already spent in the blockchain, else false

Definition at line 2958 of file blockchain.cpp.

2959{
2960 LOG_PRINT_L3("Blockchain::" << __func__);
2961
2962 for (const txin_v& in: tx.vin)
2963 {
2964 if(in.type() == typeid(txin_to_key))
2965 {
2966 const auto &in_to_key = boost::get<txin_to_key>(in);
2967 if(have_tx_keyimg_as_spent(in_to_key.k_image))
2968 return true;
2969 }
2970 }
2971
2972 return false;
2973}
bool have_tx_keyimg_as_spent(const crypto::key_image &key_im) const
check if a key image is already spent on the blockchain
boost::variant< txin_gen, txin_to_script, txin_to_scripthash, txin_to_key, txin_to_key_public > txin_v
Here is the call graph for this function:

◆ lock()

void Blockchain::lock ( )

Definition at line 5031 of file blockchain.cpp.

5032{
5033 m_blockchain_lock.lock();
5034}

◆ normalize_v7_difficulties()

void Blockchain::normalize_v7_difficulties ( )

Normalize the cumulative difficulty for V7 blocks, fixing the differing difficulty among nodes.

Definition at line 1098 of file blockchain.cpp.

1098 {
1099
1100 auto height = m_db->height();
1101 const uint64_t v8height = m_nettype == TESTNET ? 446674 : 589169;
1102
1103 if(height != v8height) {
1104 return;
1105 }
1106
1107 const uint64_t v7height = m_nettype == TESTNET ? 215000 : 324500;
1108 const size_t V7_DIFFICULTY_BLOCKS_COUNT = 735;
1109 const size_t V7_DIFFICULTY_TARGET = 120;
1110
1111 std::vector<uint64_t> timestamps;
1112 std::vector<difficulty_type> difficulties;
1113
1114 uint64_t start_height = v7height - V7_DIFFICULTY_BLOCKS_COUNT;
1115
1116 // Populate the timestamps & difficulties vectors with data from 735 blocks prior to V7 fork height (324500)
1117 for(uint64_t i = 0; start_height + i < v7height; i++) {
1118 timestamps.push_back(m_db->get_block_timestamp(start_height + i));
1119 difficulties.push_back(m_db->get_block_cumulative_difficulty(start_height + i));
1120 }
1121
1122 // Calculate the cumulative difficulty of block 324500 based on the 735 prior blocks' timestamp and difficulty values
1123 difficulty_type diff = difficulties.back() + next_difficulty(timestamps, difficulties, V7_DIFFICULTY_TARGET, 1);
1124
1125 // Override block's 324500 cumulative difficulty
1126 m_db->set_block_cumulative_difficulty(v7height, diff);
1127
1128 // Iterate over V7 blocks, starting from 324500 until current block height
1129 for(uint64_t i = v7height; i < height - 1; i++) {
1130
1131 // Add "324500 + i" timestamp & difficulty into the vectors
1132 timestamps.push_back(m_db->get_block_timestamp(i));
1133 difficulties.push_back(m_db->get_block_cumulative_difficulty(i));
1134
1135 // Erase the vector's first position maintaining its 735 size
1136 timestamps.erase(timestamps.begin());
1137 difficulties.erase(difficulties.begin());
1138
1139 // Calculate/set the correct cumulative difficulty of block "324500 + i"
1140 diff = difficulties.back() + next_difficulty(timestamps, difficulties, V7_DIFFICULTY_TARGET, 1);
1141 m_db->set_block_cumulative_difficulty(i + 1, diff);
1142 }
1143
1144 m_timestamps.clear();
1145 m_difficulties.clear();
1146}
Here is the call graph for this function:

◆ on_new_tx_from_block()

void Blockchain::on_new_tx_from_block ( const cryptonote::transaction & tx)

called when we see a tx originating from a block

Used for handling txes from historical blocks in a fast way

Definition at line 2843 of file blockchain.cpp.

2844{
2845#if defined(PER_BLOCK_CHECKPOINT)
2846 // check if we're doing per-block checkpointing
2847 if (m_db->height() < m_blocks_hash_check.size())
2848 {
2850 m_blocks_txs_check.push_back(get_transaction_hash(tx));
2852 if(m_show_time_stats)
2853 {
2854 size_t ring_size = !tx.vin.empty() && tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0;
2855 MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a);
2856 }
2857 }
2858#endif
2859}
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1124
Here is the call graph for this function:
Here is the caller graph for this function:

◆ output_scan_worker()

void Blockchain::output_scan_worker ( const uint64_t amount,
const std::vector< uint64_t > & offsets,
std::vector< output_data_t > & outputs ) const

get a number of outputs of a specific amount

Parameters
amountthe amount
offsetsthe indices (indexed to the amount) of the outputs
outputsreturn-by-reference the outputs collected

Definition at line 4396 of file blockchain.cpp.

4397{
4398 try
4399 {
4400 m_db->get_output_key(epee::span<const uint64_t>(&amount, 1), offsets, outputs, true);
4401 }
4402 catch (const std::exception& e)
4403 {
4404 MERROR_VER("EXCEPTION: " << e.what());
4405 }
4406 catch (...)
4407 {
4408
4409 }
4410}
Here is the caller graph for this function:

◆ pop_blocks()

void Blockchain::pop_blocks ( uint64_t nblocks)

removes blocks from the top of the blockchain

Parameters
nblocksnumber of blocks to be removed

Definition at line 700 of file blockchain.cpp.

701{
702 uint64_t i;
703 CRITICAL_REGION_LOCAL(m_tx_pool);
704 CRITICAL_REGION_LOCAL1(m_blockchain_lock);
705
706 bool stop_batch = m_db->batch_start();
707
708 try
709 {
710 const uint64_t blockchain_height = m_db->height();
711 if (blockchain_height > 0)
712 nblocks = std::min(nblocks, blockchain_height - 1);
713 for (i=0; i < nblocks; ++i)
714 {
715 pop_block_from_blockchain();
716 }
717 }
718 catch (const std::exception& e)
719 {
720 LOG_ERROR("Error when popping blocks after processing " << i << " blocks: " << e.what());
721 if (stop_batch)
722 m_db->batch_abort();
723 return;
724 }
725
726 if (stop_batch)
727 m_db->batch_stop();
728}

◆ prepare_handle_incoming_blocks()

bool Blockchain::prepare_handle_incoming_blocks ( const std::vector< block_complete_entry > & blocks_entry,
std::vector< block > & blocks )

performs some preprocessing on a group of incoming blocks to speed up verification

Parameters
blocks_entrya list of incoming blocks
blocksthe parsed blocks
Returns
false on erroneous blocks, else true

Definition at line 4419 of file blockchain.cpp.

4420{
4421 MTRACE("Blockchain::" << __func__);
4422 TIME_MEASURE_START(prepare);
4423 bool stop_batch;
4424 uint64_t bytes = 0;
4425 size_t total_txs = 0;
4426 blocks.clear();
4427
4428 // Order of locking must be:
4429 // m_incoming_tx_lock (optional)
4430 // m_tx_pool lock
4431 // blockchain lock
4432 //
4433 // Something which takes the blockchain lock may never take the txpool lock
4434 // if it has not provably taken the txpool lock earlier
4435 //
4436 // The txpool lock is now taken in prepare_handle_incoming_blocks
4437 // and released in cleanup_handle_incoming_blocks. This avoids issues
4438 // when something uses the pool, which now uses the blockchain and
4439 // needs a batch, since a batch could otherwise be active while the
4440 // txpool and blockchain locks were not held
4441
4442 m_tx_pool.lock();
4443 CRITICAL_REGION_LOCAL1(m_blockchain_lock);
4444
4445 if(blocks_entry.size() == 0)
4446 return false;
4447
4448 for (const auto &entry : blocks_entry)
4449 {
4450 bytes += entry.block.size();
4451 for (const auto &tx_blob : entry.txs)
4452 {
4453 bytes += tx_blob.size();
4454 }
4455 total_txs += entry.txs.size();
4456 }
4457 m_bytes_to_sync += bytes;
4458 while (!(stop_batch = m_db->batch_start(blocks_entry.size(), bytes))) {
4459 m_blockchain_lock.unlock();
4460 m_tx_pool.unlock();
4462 m_tx_pool.lock();
4463 m_blockchain_lock.lock();
4464 }
4465 m_batch_success = true;
4466
4467 const uint64_t height = m_db->height();
4468 if ((height + blocks_entry.size()) < m_blocks_hash_check.size())
4469 return true;
4470
4471 bool blocks_exist = false;
4472 tools::threadpool& tpool = tools::threadpool::getInstance();
4473 unsigned threads = tpool.get_max_concurrency();
4474 blocks.resize(blocks_entry.size());
4475
4476 if (1)
4477 {
4478 // limit threads, default limit = 4
4479 if(threads > m_max_prepare_blocks_threads)
4480 threads = m_max_prepare_blocks_threads;
4481
4482 unsigned int batches = blocks_entry.size() / threads;
4483 unsigned int extra = blocks_entry.size() % threads;
4484 MDEBUG("block_batches: " << batches);
4485 std::vector<std::unordered_map<crypto::hash, crypto::hash>> maps(threads);
4486 auto it = blocks_entry.begin();
4487 unsigned blockidx = 0;
4488
4489 const crypto::hash tophash = m_db->top_block_hash();
4490 for (unsigned i = 0; i < threads; i++)
4491 {
4492 for (unsigned int j = 0; j < batches; j++, ++blockidx)
4493 {
4494 block &block = blocks[blockidx];
4495 crypto::hash block_hash;
4496
4497 if (!parse_and_validate_block_from_blob(it->block, block, block_hash))
4498 return false;
4499
4500 // check first block and skip all blocks if its not chained properly
4501 if (blockidx == 0)
4502 {
4503 if (block.prev_id != tophash)
4504 {
4505 MDEBUG("Skipping prepare blocks. New blocks don't belong to chain.");
4506 blocks.clear();
4507 return true;
4508 }
4509 }
4510 if (have_block(block_hash))
4511 blocks_exist = true;
4512
4513 std::advance(it, 1);
4514 }
4515 }
4516
4517 for (unsigned i = 0; i < extra && !blocks_exist; i++, blockidx++)
4518 {
4519 block &block = blocks[blockidx];
4520 crypto::hash block_hash;
4521
4522 if (!parse_and_validate_block_from_blob(it->block, block, block_hash))
4523 return false;
4524
4525 if (have_block(block_hash))
4526 blocks_exist = true;
4527
4528 std::advance(it, 1);
4529 }
4530
4531 if (!blocks_exist)
4532 {
4533 m_blocks_longhash_table.clear();
4534 uint64_t thread_height = height;
4535 tools::threadpool::waiter waiter;
4536 for (unsigned int i = 0; i < threads; i++)
4537 {
4538 unsigned nblocks = batches;
4539 if (i < extra)
4540 ++nblocks;
4541 tpool.submit(&waiter, boost::bind(&Blockchain::block_longhash_worker, this, thread_height, epee::span<const block>(&blocks[thread_height - height], nblocks), std::ref(maps[i])), true);
4542 thread_height += nblocks;
4543 }
4544
4545 waiter.wait(&tpool);
4546
4547 if (m_cancel)
4548 return false;
4549
4550 for (const auto & map : maps)
4551 {
4552 m_blocks_longhash_table.insert(map.begin(), map.end());
4553 }
4554 }
4555 }
4556
4557 if (m_cancel)
4558 return false;
4559
4560 if (blocks_exist)
4561 {
4562 MDEBUG("Skipping remainder of prepare blocks. Blocks exist.");
4563 return true;
4564 }
4565
4566 m_fake_scan_time = 0;
4567 m_fake_pow_calc_time = 0;
4568
4569 m_scan_table.clear();
4570 m_check_txin_table.clear();
4571
4572 TIME_MEASURE_FINISH(prepare);
4573 m_fake_pow_calc_time = prepare / blocks_entry.size();
4574
4575 if (blocks_entry.size() > 1 && threads > 1 && m_show_time_stats)
4576 MDEBUG("Prepare blocks took: " << prepare << " ms");
4577
4578 TIME_MEASURE_START(scantable);
4579
4580 // [input] stores all unique amounts found
4581 std::vector < uint64_t > amounts;
4582 // [input] stores all absolute_offsets for each amount
4583 std::map<uint64_t, std::vector<uint64_t>> offset_map;
4584 // [output] stores all output_data_t for each absolute_offset
4585 std::map<uint64_t, std::vector<output_data_t>> tx_map;
4586 std::vector<std::pair<cryptonote::transaction, crypto::hash>> txes(total_txs);
4587
4588#define SCAN_TABLE_QUIT(m) \
4589 do { \
4590 MERROR_VER(m) ;\
4591 m_scan_table.clear(); \
4592 return false; \
4593 } while(0); \
4594
4595 // generate sorted tables for all amounts and absolute offsets
4596 size_t tx_index = 0, block_index = 0;
4597 for (const auto &entry : blocks_entry)
4598 {
4599 if (m_cancel)
4600 return false;
4601
4602 for (const auto &tx_blob : entry.txs)
4603 {
4604 if (tx_index >= txes.size())
4605 SCAN_TABLE_QUIT("tx_index is out of sync");
4606 transaction &tx = txes[tx_index].first;
4607 crypto::hash &tx_prefix_hash = txes[tx_index].second;
4608 ++tx_index;
4609
4610 if (!parse_and_validate_tx_base_from_blob(tx_blob, tx))
4611 SCAN_TABLE_QUIT("Could not parse tx from incoming blocks.");
4612 cryptonote::get_transaction_prefix_hash(tx, tx_prefix_hash);
4613
4614 auto its = m_scan_table.find(tx_prefix_hash);
4615 if (its != m_scan_table.end())
4616 SCAN_TABLE_QUIT("Duplicate tx found from incoming blocks.");
4617
4618 m_scan_table.emplace(tx_prefix_hash, std::unordered_map<crypto::key_image, std::vector<output_data_t>>());
4619 its = m_scan_table.find(tx_prefix_hash);
4620 assert(its != m_scan_table.end());
4621
4622 if(tx.version <= 2)
4623 {
4624 // get all amounts from tx.vin(s)
4625 for (const auto &txin : tx.vin)
4626 {
4627 const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
4628
4629 // check for duplicate
4630 auto it = its->second.find(in_to_key.k_image);
4631 if (it != its->second.end())
4632 SCAN_TABLE_QUIT("Duplicate key_image found from incoming blocks.");
4633
4634 amounts.push_back(in_to_key.amount);
4635 }
4636 }
4637
4638 // sort and remove duplicate amounts from amounts list
4639 std::sort(amounts.begin(), amounts.end());
4640 auto last = std::unique(amounts.begin(), amounts.end());
4641 amounts.erase(last, amounts.end());
4642
4643 // add amount to the offset_map and tx_map
4644 for (const uint64_t &amount : amounts)
4645 {
4646 if (offset_map.find(amount) == offset_map.end())
4647 offset_map.emplace(amount, std::vector<uint64_t>());
4648
4649 if (tx_map.find(amount) == tx_map.end())
4650 tx_map.emplace(amount, std::vector<output_data_t>());
4651 }
4652
4653 if(tx.version <= 2)
4654 {
4655 // add new absolute_offsets to offset_map
4656 for (const auto &txin : tx.vin)
4657 {
4658 const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
4659 // no need to check for duplicate here.
4660 auto absolute_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets);
4661 for (const auto & offset : absolute_offsets)
4662 offset_map[in_to_key.amount].push_back(offset);
4663
4664 }
4665 }
4666 }
4667 ++block_index;
4668 }
4669
4670 // sort and remove duplicate absolute_offsets in offset_map
4671 for (auto &offsets : offset_map)
4672 {
4673 std::sort(offsets.second.begin(), offsets.second.end());
4674 auto last = std::unique(offsets.second.begin(), offsets.second.end());
4675 offsets.second.erase(last, offsets.second.end());
4676 }
4677
4678 // gather all the output keys
4679 threads = tpool.get_max_concurrency();
4680 if (!m_db->can_thread_bulk_indices())
4681 threads = 1;
4682
4683 if (threads > 1 && amounts.size() > 1)
4684 {
4685 tools::threadpool::waiter waiter;
4686
4687 for (size_t i = 0; i < amounts.size(); i++)
4688 {
4689 uint64_t amount = amounts[i];
4690 tpool.submit(&waiter, boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount])), true);
4691 }
4692 waiter.wait(&tpool);
4693 }
4694 else
4695 {
4696 for (size_t i = 0; i < amounts.size(); i++)
4697 {
4698 uint64_t amount = amounts[i];
4699 output_scan_worker(amount, offset_map[amount], tx_map[amount]);
4700 }
4701 }
4702
4703 // now generate a table for each tx_prefix and k_image hashes
4704 tx_index = 0;
4705 for (const auto &entry : blocks_entry)
4706 {
4707 if (m_cancel)
4708 return false;
4709
4710 for (const auto &tx_blob : entry.txs)
4711 {
4712 if (tx_index >= txes.size())
4713 SCAN_TABLE_QUIT("tx_index is out of sync");
4714 const transaction &tx = txes[tx_index].first;
4715 const crypto::hash &tx_prefix_hash = txes[tx_index].second;
4716 ++tx_index;
4717
4718 auto its = m_scan_table.find(tx_prefix_hash);
4719 if (its == m_scan_table.end())
4720 SCAN_TABLE_QUIT("Tx not found on scan table from incoming blocks.");
4721
4722 if(tx.version >= 3) continue;
4723
4724 for (const auto &txin : tx.vin)
4725 {
4726 const txin_to_key &in_to_key = boost::get < txin_to_key > (txin);
4727 auto needed_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets);
4728
4729 std::vector<output_data_t> outputs;
4730 for (const uint64_t & offset_needed : needed_offsets)
4731 {
4732 size_t pos = 0;
4733 bool found = false;
4734
4735 for (const uint64_t &offset_found : offset_map[in_to_key.amount])
4736 {
4737 if (offset_needed == offset_found)
4738 {
4739 found = true;
4740 break;
4741 }
4742
4743 ++pos;
4744 }
4745
4746 if (found && pos < tx_map[in_to_key.amount].size())
4747 outputs.push_back(tx_map[in_to_key.amount].at(pos));
4748 else
4749 break;
4750 }
4751
4752 its->second.emplace(in_to_key.k_image, outputs);
4753 }
4754 }
4755 }
4756
4757 TIME_MEASURE_FINISH(scantable);
4758 if (total_txs > 0)
4759 {
4760 m_fake_scan_time = scantable / total_txs;
4761 if(m_show_time_stats)
4762 MDEBUG("Prepare scantable took: " << scantable << " ms");
4763 }
4764
4765 return true;
4766}
#define SCAN_TABLE_QUIT(m)
void output_scan_worker(const uint64_t amount, const std::vector< uint64_t > &offsets, std::vector< output_data_t > &outputs) const
get a number of outputs of a specific amount
void block_longhash_worker(uint64_t height, const epee::span< const block > &blocks, std::unordered_map< crypto::hash, crypto::hash > &map) const
computes the "short" and "long" hashes for a set of blocks
void wait(threadpool *tpool)
void submit(waiter *waiter, std::function< void()> f, bool leaf=false)
unsigned int get_max_concurrency() const
static threadpool & getInstance()
Definition threadpool.h:46
POD_CLASS key_image
Definition crypto.h:105
void get_transaction_prefix_hash(const transaction_prefix &tx, crypto::hash &h)
std::vector< uint64_t > relative_output_offsets_to_absolute(const std::vector< uint64_t > &off)
bool parse_and_validate_tx_base_from_blob(const blobdata &tx_blob, transaction &tx)
bool sleep_no_w(long ms)
crypto::key_image k_image
std::vector< uint64_t > key_offsets
Here is the call graph for this function:

◆ prune_blockchain()

bool Blockchain::prune_blockchain ( uint32_t pruning_seed = 0)

Definition at line 4073 of file blockchain.cpp.

4074{
4075 m_tx_pool.lock();
4077 CRITICAL_REGION_LOCAL(m_blockchain_lock);
4078
4079 return m_db->prune_blockchain(pruning_seed);
4080}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_txpool_tx()

void Blockchain::remove_txpool_tx ( const crypto::hash & txid)

Definition at line 4778 of file blockchain.cpp.

4779{
4780 m_db->remove_txpool_tx(txid);
4781}

◆ reset_and_set_genesis_block()

bool Blockchain::reset_and_set_genesis_block ( const block & b)

clears the blockchain and starts a new one

Parameters
bthe first block in the new chain (the genesis block)
Returns
true on success, else false

Definition at line 812 of file blockchain.cpp.

813{
814 LOG_PRINT_L3("Blockchain::" << __func__);
815 CRITICAL_REGION_LOCAL(m_blockchain_lock);
816 m_timestamps_and_difficulties_height = 0;
817 m_alternative_chains.clear();
818 invalidate_block_template_cache();
819 m_db->reset();
820 m_hardfork->init();
821
822 db_wtxn_guard wtxn_guard(m_db);
823 block_verification_context bvc = boost::value_initialized<block_verification_context>();
824 add_new_block(b, bvc);
825 if (!update_next_cumulative_weight_limit())
826 return false;
828}
Here is the call graph for this function:

◆ safesyncmode()

void Blockchain::safesyncmode ( const bool onoff)

Put DB in safe sync mode.

Definition at line 4835 of file blockchain.cpp.

4836{
4837 /* all of this is no-op'd if the user set a specific
4838 * --db-sync-mode at startup.
4839 */
4840 if (m_db_default_sync)
4841 {
4842 m_db->safesyncmode(onoff);
4843 m_db_sync_mode = onoff ? db_nosync : db_async;
4844 }
4845}

◆ set_block_notify()

void cryptonote::Blockchain::set_block_notify ( const std::shared_ptr< tools::Notify > & notify)
inline

sets a block notify object to call for every new block

Parameters
notifythe notify object to call at every new block

Definition at line 785 of file blockchain.h.

785{ m_block_notify = notify; }

◆ set_checkpoints()

void cryptonote::Blockchain::set_checkpoints ( checkpoints && chk_pts)
inline

assign a set of blockchain checkpoint hashes

Parameters
chk_ptsthe set of checkpoints to assign

Definition at line 175 of file blockchain.h.

175{ m_checkpoints = chk_pts; }

◆ set_enforce_dns_checkpoints()

void Blockchain::set_enforce_dns_checkpoints ( bool enforce)

configure whether or not to enforce DNS-based checkpoints

Parameters
enforcethe new enforcement setting

Definition at line 4307 of file blockchain.cpp.

4308{
4309 m_enforce_dns_checkpoints = enforce_checkpoints;
4310}

◆ set_reorg_notify()

void cryptonote::Blockchain::set_reorg_notify ( const std::shared_ptr< tools::Notify > & notify)
inline

sets a reorg notify object to call for every reorg

Parameters
notifythe notify object to call at every reorg

Definition at line 792 of file blockchain.h.

792{ m_reorg_notify = notify; }

◆ set_show_time_stats()

void cryptonote::Blockchain::set_show_time_stats ( bool stats)
inline

set whether or not to show/print time statistics

Parameters
statsthe new time stats setting

Definition at line 804 of file blockchain.h.

804{ m_show_time_stats = stats; }

◆ set_user_options()

void Blockchain::set_user_options ( uint64_t maxthreads,
bool sync_on_blocks,
uint64_t sync_threshold,
blockchain_db_sync_mode sync_mode,
bool fast_sync,
std::string validator_key )

Update the validators public key by fetching data from electroneum's endpoint.

Returns
true if successfull

sets various performance options

Parameters
maxthreadsmax number of threads when preparing blocks for addition
sync_on_blockswhether to sync based on blocks or bytes
sync_thresholdnumber of blocks/bytes to cache before syncing to database
sync_modethe ::blockchain_db_sync_mode to use
fast_syncsync using built-in block hashes as trusted

Definition at line 4817 of file blockchain.cpp.

4818{
4819 if (sync_mode == db_defaultsync)
4820 {
4821 m_db_default_sync = true;
4822 sync_mode = db_async;
4823 }
4824 m_db_sync_mode = sync_mode;
4825 m_fast_sync = fast_sync;
4826 m_db_sync_on_blocks = sync_on_blocks;
4827 m_db_sync_threshold = sync_threshold;
4828 m_max_prepare_blocks_threads = maxthreads;
4829
4830 if(!validator_key.empty()) {
4831 m_validator_key = boost::algorithm::unhex(validator_key);
4832 }
4833}
@ db_defaultsync
user didn't specify, use db_async
Definition blockchain.h:79

◆ set_validator_key()

void cryptonote::Blockchain::set_validator_key ( std::string key)
inline

set validator key

Definition at line 1064 of file blockchain.h.

1064{ m_validator_key = boost::algorithm::unhex(key); }

◆ set_validators_list_instance()

void cryptonote::Blockchain::set_validators_list_instance ( std::unique_ptr< electroneum::basic::Validators > & v)
inline

Definition at line 1066 of file blockchain.h.

1066{ m_validators = v.get(); }

◆ sign_block()

void Blockchain::sign_block ( block & b,
std::string privateKey )

Digitally sign the block.

Parameters
bthe block to be digitally signed
privateKeykey to generate the signature

Definition at line 1811 of file blockchain.cpp.

1811 {
1812 crypto::hash tx_tree_hash = get_tx_tree_hash(b);
1813
1814 std::string signature = crypto::sign_message(std::string(reinterpret_cast<char const*>(tx_tree_hash.data), sizeof(tx_tree_hash.data)), privateKey);
1815 if(signature.empty() || signature.size() != 64) {
1816 LOG_ERROR("The daemon has failed to digitally sign a block and therefore it cannot be accepted by the network. Please check your validator-key configuration before resuming mining.");
1817 return;
1818 }
1819
1820 b.signature = std::vector<uint8_t>(signature.begin(), signature.end());
1821}
std::string privateKey
POD_CLASS signature
Definition crypto.h:108
std::string sign_message(const std::string &message, const std::string &privateKey)
Definition crypto.h:376
void get_tx_tree_hash(const std::vector< crypto::hash > &tx_hashes, crypto::hash &h)
std::vector< uint8_t > signature
Here is the call graph for this function:
Here is the caller graph for this function:

◆ store_blockchain()

bool Blockchain::store_blockchain ( )

stores the blockchain

If Blockchain is handling storing of the blockchain (rather than BlockchainDB), this initiates a blockchain save.

Returns
true unless saving the blockchain fails

Definition at line 630 of file blockchain.cpp.

631{
632 LOG_PRINT_L3("Blockchain::" << __func__);
633 // lock because the rpc_thread command handler also calls this
634 CRITICAL_REGION_LOCAL(m_db->m_synchronization_lock);
635
636 TIME_MEASURE_START(save);
637 // TODO: make sure sync(if this throws that it is not simply ignored higher
638 // up the call stack
639 try
640 {
641 m_db->sync();
642 }
643 catch (const std::exception& e)
644 {
645 MERROR(std::string("Error syncing blockchain db: ") + e.what() + "-- shutting down now to prevent issues!");
646 throw;
647 }
648 catch (...)
649 {
650 MERROR("There was an issue storing the blockchain, shutting down now to prevent issues!");
651 throw;
652 }
653
655 if(m_show_time_stats)
656 MINFO("Blockchain stored OK, took: " << save << " ms");
657 return true;
658}
Here is the caller graph for this function:

◆ unlock()

void Blockchain::unlock ( )

Definition at line 5036 of file blockchain.cpp.

5037{
5038 m_blockchain_lock.unlock();
5039}

◆ update_blockchain_pruning()

bool Blockchain::update_blockchain_pruning ( )

Definition at line 4082 of file blockchain.cpp.

4083{
4084 m_tx_pool.lock();
4086 CRITICAL_REGION_LOCAL(m_blockchain_lock);
4087
4088 return m_db->update_pruning();
4089}
Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_checkpoints()

bool Blockchain::update_checkpoints ( const std::string & file_path,
bool check_dns )

loads new checkpoints from a file and optionally from DNS

Parameters
file_paththe path of the file to look for and load checkpoints from
check_dnswhether or not to check for new DNS-based checkpoints
Returns
false if any enforced checkpoint type fails to load, otherwise true

Definition at line 4272 of file blockchain.cpp.

4273{
4274 if (!m_checkpoints.load_checkpoints_from_json(file_path))
4275 {
4276 return false;
4277 }
4278
4279 // if we're checking both dns and json, load checkpoints from dns.
4280 // if we're not hard-enforcing dns checkpoints, handle accordingly
4281 if (m_enforce_dns_checkpoints && check_dns && !m_offline)
4282 {
4283 if (!m_checkpoints.load_checkpoints_from_dns())
4284 {
4285 return false;
4286 }
4287 }
4288 else if (check_dns && !m_offline)
4289 {
4290 checkpoints dns_points;
4291 dns_points.load_checkpoints_from_dns();
4292 if (m_checkpoints.check_for_conflicts(dns_points))
4293 {
4294 check_against_checkpoints(dns_points, false);
4295 }
4296 else
4297 {
4298 MERROR("One or more checkpoints fetched from DNS conflicted with existing checkpoints!");
4299 }
4300 }
4301
4302 check_against_checkpoints(m_checkpoints, true);
4303
4304 return true;
4305}
const unsigned char checkpoints[]
void check_against_checkpoints(const checkpoints &points, bool enforce)
check the blockchain against a set of checkpoints
bool load_checkpoints_from_dns(network_type nettype=MAINNET)
load new checkpoints from DNS
Here is the call graph for this function:

◆ update_txpool_tx()

void Blockchain::update_txpool_tx ( const crypto::hash & txid,
const txpool_tx_meta_t & meta )

Definition at line 4773 of file blockchain.cpp.

4774{
4775 m_db->update_txpool_tx(txid, meta);
4776}

◆ utxo_nonexistence_from_output()

bool Blockchain::utxo_nonexistence_from_output ( const txin_to_key_public & public_output) const

check if a single utxo in a transaction has already been spent using the hash and out index (v3 tx onwards)

Parameters
public_outputthe output to check
Returns
true if any utxo is nonexistent, else false

Definition at line 2993 of file blockchain.cpp.

2994{
2995 LOG_PRINT_L3("Blockchain::" << __func__);
2996
2997 if(!m_db->check_chainstate_utxo(public_output.tx_hash, public_output.relative_offset))
2998 return true;
2999
3000 return false;
3001}

◆ utxo_nonexistent()

bool Blockchain::utxo_nonexistent ( const transaction & tx) const

check if any utxo in a transaction has already been spent using the tx (v3 tx onwards)

Parameters
txthe transaction to check
Returns
true if any utxo is nonexistent, else false

Definition at line 2975 of file blockchain.cpp.

2976{
2977 LOG_PRINT_L3("Blockchain::" << __func__);
2978
2979 for (const txin_v& in: tx.vin)
2980 {
2981 if(in.type() == typeid(txin_to_key_public))
2982 {
2983 const auto &in_to_key = boost::get<txin_to_key_public>(in);
2984 if(!m_db->check_chainstate_utxo(in_to_key.tx_hash, in_to_key.relative_offset))
2985 return true;
2986 }
2987 }
2988 return false;
2989}

◆ verify_block_signature()

bool Blockchain::verify_block_signature ( const block & b)

Verify block's digital signature.

Parameters
bblock to be verified

Definition at line 1823 of file blockchain.cpp.

1823 {
1824 crypto::hash tx_tree_hash = get_tx_tree_hash(b);
1825 const std::vector<std::string> public_keys = m_validators->getApplicablePublicKeys(m_db->height(), true);
1826
1827 for(auto &key : public_keys) {
1828 if(crypto::verify_signature(std::string(reinterpret_cast<char const *>(tx_tree_hash.data), sizeof(tx_tree_hash.data)),
1829 key, std::string(b.signature.begin(), b.signature.end()))){
1830 b.signatory = std::vector<uint8_t>(key.begin(), key.end());
1831 return true;
1832 }
1833 }
1834 return false;
1835}
bool verify_signature(const std::string &message, const std::string &publicKey, const std::string &signature)
Definition crypto.h:380
Here is the call graph for this function:

The documentation for this class was generated from the following files:
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/src/cryptonote_core/blockchain.h
  • /home/abuild/rpmbuild/BUILD/electroneum-5.1.3.1-build/electroneum-5.1.3.1/src/cryptonote_core/blockchain.cpp