@ -468,8 +468,8 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
uint64_t num_popped_blocks = 0 ;
while ( ! m_db - > is_read_only ( ) )
{
const uint64_t top_height = m_db - > height ( ) - 1 ;
const crypto : : hash top_id = m_db - > top_block_hash ( ) ;
uint64_t top_height ;
const crypto : : hash top_id = m_db - > top_block_hash ( & top_height ) ;
const block top_block = m_db - > get_top_block ( ) ;
const uint8_t ideal_hf_version = get_ideal_hard_fork_version ( top_height ) ;
if ( ideal_hf_version < = 1 | | ideal_hf_version = = top_block . major_version )
@ -509,7 +509,9 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
{
m_timestamps_and_difficulties_height = 0 ;
m_hardfork - > reorganize_from_chain_height ( get_current_blockchain_height ( ) ) ;
m_tx_pool . on_blockchain_dec ( m_db - > height ( ) - 1 , get_tail_id ( ) ) ;
uint64_t top_block_height ;
crypto : : hash top_block_hash = get_tail_id ( top_block_height ) ;
m_tx_pool . on_blockchain_dec ( top_block_height , top_block_hash ) ;
}
if ( test_options & & test_options - > long_term_block_weight_window )
@ -702,7 +704,9 @@ block Blockchain::pop_block_from_blockchain()
m_check_txin_table . clear ( ) ;
CHECK_AND_ASSERT_THROW_MES ( update_next_cumulative_weight_limit ( ) , " Error updating next cumulative weight limit " ) ;
m_tx_pool . on_blockchain_dec ( m_db - > height ( ) - 1 , get_tail_id ( ) ) ;
uint64_t top_block_height ;
crypto : : hash top_block_hash = get_tail_id ( top_block_height ) ;
m_tx_pool . on_blockchain_dec ( top_block_height , top_block_hash ) ;
invalidate_block_template_cache ( ) ;
return popped_block ;
@ -729,8 +733,7 @@ crypto::hash Blockchain::get_tail_id(uint64_t& height) const
{
LOG_PRINT_L3 ( " Blockchain:: " < < __func__ ) ;
CRITICAL_REGION_LOCAL ( m_blockchain_lock ) ;
height = m_db - > height ( ) - 1 ;
return get_tail_id ( ) ;
return m_db - > top_block_hash ( & height ) ;
}
//------------------------------------------------------------------
crypto : : hash Blockchain : : get_tail_id ( ) const
@ -891,8 +894,9 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
CRITICAL_REGION_LOCAL ( m_blockchain_lock ) ;
std : : vector < uint64_t > timestamps ;
std : : vector < difficulty_type > difficulties ;
auto height = m_db - > height ( ) ;
top_hash = get_tail_id ( ) ; // get it again now that we have the lock
uint64_t height ;
top_hash = get_tail_id ( height ) ; // get it again now that we have the lock
+ + height ; // top block height to blockchain height
// ND: Speedup
// 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty,
// then when the next block difficulty is queried, push the latest height data and
@ -1806,11 +1810,12 @@ uint64_t Blockchain::get_num_mature_outputs(uint64_t amount) const
uint64_t num_outs = m_db - > get_num_outputs ( amount ) ;
// ensure we don't include outputs that aren't yet eligible to be used
// outpouts are sorted by height
const uint64_t blockchain_height = m_db - > height ( ) ;
while ( num_outs > 0 )
{
const tx_out_index toi = m_db - > get_output_tx_and_index ( amount , num_outs - 1 ) ;
const uint64_t height = m_db - > get_tx_block_height ( toi . first ) ;
if ( height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE < = m_db- > height ( ) )
if ( height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE < = blockchain_height )
break ;
- - num_outs ;
}
@ -3325,14 +3330,15 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons
return false ;
}
const auto h = m_db - > height ( ) ;
// if not enough blocks, no proper median yet, return true
if ( m_db - > height ( ) < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW )
if ( h < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW )
{
return true ;
}
std : : vector < uint64_t > timestamps ;
auto h = m_db - > height ( ) ;
// need most recent 60 blocks, get index of first of those
size_t offset = h - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW ;
@ -3345,7 +3351,7 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons
return check_block_timestamp ( timestamps , b , median_ts ) ;
}
//------------------------------------------------------------------
void Blockchain : : return_tx_to_pool ( std : : vector < transaction> & txs )
void Blockchain : : return_tx_to_pool ( std : : vector < std: : pair < transaction, blobdata > > & txs )
{
uint8_t version = get_current_hard_fork_version ( ) ;
for ( auto & tx : txs )
@ -3356,9 +3362,11 @@ void Blockchain::return_tx_to_pool(std::vector<transaction> &txs)
// that might not be always true. Unlikely though, and always relaying
// these again might cause a spike of traffic as many nodes re-relay
// all the transactions in a popped block when a reorg happens.
if ( ! m_tx_pool . add_tx ( tx , tvc , true , true , false , version ) )
const size_t weight = get_transaction_weight ( tx . first , tx . second . size ( ) ) ;
const crypto : : hash tx_hash = get_transaction_hash ( tx . first ) ;
if ( ! m_tx_pool . add_tx ( tx . first , tx_hash , tx . second , weight , tvc , true , true , false , version ) )
{
MERROR ( " Failed to return taken transaction with hash: " < < get_transaction_hash ( tx ) < < " to tx_pool " ) ;
MERROR ( " Failed to return taken transaction with hash: " < < get_transaction_hash ( tx .first ) < < " to tx_pool " ) ;
}
}
}
@ -3371,11 +3379,12 @@ bool Blockchain::flush_txes_from_pool(const std::vector<crypto::hash> &txids)
for ( const auto & txid : txids )
{
cryptonote : : transaction tx ;
cryptonote : : blobdata txblob ;
size_t tx_weight ;
uint64_t fee ;
bool relayed , do_not_relay , double_spend_seen ;
MINFO ( " Removing txid " < < txid < < " from the pool " ) ;
if ( m_tx_pool . have_tx ( txid ) & & ! m_tx_pool . take_tx ( txid , tx , tx _weight, fee , relayed , do_not_relay , double_spend_seen ) )
if ( m_tx_pool . have_tx ( txid ) & & ! m_tx_pool . take_tx ( txid , tx , tx blob, tx _weight, fee , relayed , do_not_relay , double_spend_seen ) )
{
MERROR ( " Failed to remove txid " < < txid < < " from the pool " ) ;
res = false ;
@ -3398,9 +3407,12 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash&
static bool seen_future_version = false ;
m_db - > block_txn_start ( true ) ;
if ( bl . prev_id ! = get_tail_id ( ) )
uint64_t blockchain_height ;
const crypto : : hash top_hash = get_tail_id ( blockchain_height ) ;
+ + blockchain_height ; // block height to chain height
if ( bl . prev_id ! = top_hash )
{
MERROR_VER ( " Block with id: " < < id < < std : : endl < < " has wrong prev_id: " < < bl . prev_id < < std : : endl < < " expected: " < < get_tail_id ( ) ) ;
MERROR_VER ( " Block with id: " < < id < < std : : endl < < " has wrong prev_id: " < < bl . prev_id < < std : : endl < < " expected: " < < top_hash ) ;
bvc . m_verifivation_failed = true ;
leave :
m_db - > block_txn_stop ( ) ;
@ -3469,13 +3481,12 @@ leave:
bool precomputed = false ;
bool fast_check = false ;
# if defined(PER_BLOCK_CHECKPOINT)
if ( m_db- > height ( ) < m_blocks_hash_check . size ( ) )
if ( blockchain_height < m_blocks_hash_check . size ( ) )
{
auto hash = get_block_hash ( bl ) ;
const auto & expected_hash = m_blocks_hash_check [ m_db - > height ( ) ] ;
const auto & expected_hash = m_blocks_hash_check [ blockchain_height ] ;
if ( expected_hash ! = crypto : : null_hash )
{
if ( memcmp ( & hash , & expected_hash , sizeof ( hash ) ) ! = 0 )
if ( memcmp ( & id , & expected_hash , sizeof ( hash ) ) ! = 0 )
{
MERROR_VER ( " Block with id is INVALID: " < < id < < " , expected " < < expected_hash ) ;
bvc . m_verifivation_failed = true ;
@ -3485,7 +3496,7 @@ leave:
}
else
{
MCINFO ( " verify " , " No pre-validated hash at height " < < m_db- > height ( ) < < " , verifying fully " ) ;
MCINFO ( " verify " , " No pre-validated hash at height " < < blockchain_height < < " , verifying fully " ) ;
}
}
else
@ -3498,7 +3509,7 @@ leave:
proof_of_work = it - > second ;
}
else
proof_of_work = get_block_longhash ( bl , m_db- > height ( ) ) ;
proof_of_work = get_block_longhash ( bl , blockchain_height ) ;
// validate proof_of_work versus difficulty target
if ( ! check_hash ( proof_of_work , current_diffic ) )
@ -3511,9 +3522,9 @@ leave:
// If we're at a checkpoint, ensure that our hardcoded checkpoint hash
// is correct.
if ( m_checkpoints . is_in_checkpoint_zone ( get_current_ blockchain_height( ) ) )
if ( m_checkpoints . is_in_checkpoint_zone ( blockchain_height) )
{
if ( ! m_checkpoints . check_block ( get_current_ blockchain_height( ) , id ) )
if ( ! m_checkpoints . check_block ( blockchain_height, id ) )
{
LOG_ERROR ( " CHECKPOINT VALIDATION FAILED " ) ;
bvc . m_verifivation_failed = true ;
@ -3528,7 +3539,7 @@ leave:
TIME_MEASURE_START ( t3 ) ;
// sanity check basic miner tx properties;
if ( ! prevalidate_miner_transaction ( bl , m_db- > height ( ) ) )
if ( ! prevalidate_miner_transaction ( bl , blockchain_height ) )
{
MERROR_VER ( " Block with id: " < < id < < " failed to pass prevalidation " ) ;
bvc . m_verifivation_failed = true ;
@ -3538,7 +3549,7 @@ leave:
size_t coinbase_weight = get_transaction_weight ( bl . miner_tx ) ;
size_t cumulative_block_weight = coinbase_weight ;
std : : vector < transaction> txs ;
std : : vector < std: : pair < transaction, blobdata > > txs ;
key_images_container keys ;
uint64_t fee_summary = 0 ;
@ -3557,7 +3568,8 @@ leave:
txs . reserve ( bl . tx_hashes . size ( ) ) ;
for ( const crypto : : hash & tx_id : bl . tx_hashes )
{
transaction tx ;
transaction tx_tmp ;
blobdata txblob ;
size_t tx_weight = 0 ;
uint64_t fee = 0 ;
bool relayed = false , do_not_relay = false , double_spend_seen = false ;
@ -3577,7 +3589,7 @@ leave:
TIME_MEASURE_START ( bb ) ;
// get transaction with hash <tx_id> from tx_pool
if ( ! m_tx_pool . take_tx ( tx_id , tx , tx_weight , fee , relayed , do_not_relay , double_spend_seen ) )
if ( ! m_tx_pool . take_tx ( tx_id , tx _tmp, txblob , tx_weight , fee , relayed , do_not_relay , double_spend_seen ) )
{
MERROR_VER ( " Block with id: " < < id < < " has at least one unknown transaction with id: " < < tx_id ) ;
bvc . m_verifivation_failed = true ;
@ -3590,7 +3602,8 @@ leave:
// add the transaction to the temp list of transactions, so we can either
// store the list of transactions all at once or return the ones we've
// taken from the tx_pool back to it if the block fails verification.
txs . push_back ( tx ) ;
txs . push_back ( std : : make_pair ( std : : move ( tx_tmp ) , std : : move ( txblob ) ) ) ;
transaction & tx = txs . back ( ) . first ;
TIME_MEASURE_START ( dd ) ;
// FIXME: the storage should not be responsible for validation.
@ -3655,7 +3668,7 @@ leave:
TIME_MEASURE_START ( vmt ) ;
uint64_t base_reward = 0 ;
uint64_t already_generated_coins = m_db- > height ( ) ? m_db - > get_block_already_generated_coins ( m_db- > height ( ) - 1 ) : 0 ;
uint64_t already_generated_coins = blockchain_height ? m_db - > get_block_already_generated_coins ( blockchain_height - 1 ) : 0 ;
if ( ! validate_miner_transaction ( bl , cumulative_block_weight , fee_summary , base_reward , already_generated_coins , bvc . m_partial_block_reward , m_hardfork - > get_current_version ( ) ) )
{
MERROR_VER ( " Block with id: " < < id < < " has incorrect miner transaction " ) ;
@ -3676,8 +3689,8 @@ leave:
// at MONEY_SUPPLY. already_generated_coins is only used to compute the block subsidy and MONEY_SUPPLY yields a
// subsidy of 0 under the base formula and therefore the minimum subsidy >0 in the tail state.
already_generated_coins = base_reward < ( MONEY_SUPPLY - already_generated_coins ) ? already_generated_coins + base_reward : MONEY_SUPPLY ;
if ( m_db- > height ( ) )
cumulative_difficulty + = m_db - > get_block_cumulative_difficulty ( m_db- > height ( ) - 1 ) ;
if ( blockchain_height )
cumulative_difficulty + = m_db - > get_block_cumulative_difficulty ( blockchain_height - 1 ) ;
TIME_MEASURE_FINISH ( block_processing_time ) ;
if ( precomputed )
@ -3691,7 +3704,8 @@ leave:
try
{
uint64_t long_term_block_weight = get_next_long_term_block_weight ( block_weight ) ;
new_height = m_db - > add_block ( bl , block_weight , long_term_block_weight , cumulative_difficulty , already_generated_coins , txs ) ;
cryptonote : : blobdata bd = cryptonote : : block_to_blob ( bl ) ;
new_height = m_db - > add_block ( std : : make_pair ( std : : move ( bl ) , std : : move ( bd ) ) , block_weight , long_term_block_weight , cumulative_difficulty , already_generated_coins , txs ) ;
}
catch ( const KEY_IMAGE_EXISTS & e )
{
@ -3875,11 +3889,9 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
return true ;
}
//------------------------------------------------------------------
bool Blockchain : : add_new_block ( const block & bl _ , block_verification_context & bvc )
bool Blockchain : : add_new_block ( const block & bl , block_verification_context & bvc )
{
LOG_PRINT_L3 ( " Blockchain:: " < < __func__ ) ;
//copy block here to let modify block.target
block bl = bl_ ;
crypto : : hash id = get_block_hash ( bl ) ;
CRITICAL_REGION_LOCAL ( m_tx_pool ) ; //to avoid deadlock lets lock tx_pool for whole add/reorganize process
CRITICAL_REGION_LOCAL1 ( m_blockchain_lock ) ;
@ -3918,10 +3930,11 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor
CRITICAL_REGION_LOCAL ( m_blockchain_lock ) ;
stop_batch = m_db - > batch_start ( ) ;
const uint64_t blockchain_height = m_db - > height ( ) ;
for ( const auto & pt : pts )
{
// if the checkpoint is for a block we don't have yet, move on
if ( pt . first > = m_db- > height ( ) )
if ( pt . first > = blockchain_height )
{
continue ;
}
@ -4196,13 +4209,14 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
// vs [k_image, output_keys] (m_scan_table). This is faster because it takes advantage of bulk queries
// and is threaded if possible. The table (m_scan_table) will be used later when querying output
// keys.
bool Blockchain : : prepare_handle_incoming_blocks ( const std : : vector < block_complete_entry > & blocks_entry )
bool Blockchain : : prepare_handle_incoming_blocks ( const std : : vector < block_complete_entry > & blocks_entry , std : : vector < block > & blocks )
{
MTRACE ( " Blockchain:: " < < __func__ ) ;
TIME_MEASURE_START ( prepare ) ;
bool stop_batch ;
uint64_t bytes = 0 ;
size_t total_txs = 0 ;
blocks . clear ( ) ;
// Order of locking must be:
// m_incoming_tx_lock (optional)
@ -4249,7 +4263,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
bool blocks_exist = false ;
tools : : threadpool & tpool = tools : : threadpool : : getInstance ( ) ;
unsigned threads = tpool . get_max_concurrency ( ) ;
std : : vector < block > blocks ;
blocks . resize ( blocks_entry . size ( ) ) ;
if ( 1 )
@ -4265,6 +4278,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
auto it = blocks_entry . begin ( ) ;
unsigned blockidx = 0 ;
const crypto : : hash tophash = m_db - > top_block_hash ( ) ;
for ( unsigned i = 0 ; i < threads ; i + + )
{
for ( unsigned int j = 0 ; j < batches ; j + + , + + blockidx )
@ -4277,18 +4291,15 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
// check first block and skip all blocks if its not chained properly
if ( blockidx = = 0 )
{
crypto : : hash tophash = m_db - > top_block_hash ( ) ;
if ( block . prev_id ! = tophash )
{
MDEBUG ( " Skipping prepare blocks. New blocks don't belong to chain. " ) ;
blocks . clear ( ) ;
return true ;
}
}
if ( have_block ( get_block_hash ( block ) ) )
{
blocks_exist = true ;
break ;
}
std : : advance ( it , 1 ) ;
}
@ -4302,10 +4313,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
return false ;
if ( have_block ( get_block_hash ( block ) ) )
{
blocks_exist = true ;
break ;
}
std : : advance ( it , 1 ) ;
}
@ -4341,7 +4349,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
if ( blocks_exist )
{
MDEBUG ( " Skipping prepare blocks. Blocks exist." ) ;
MDEBUG ( " Skipping remainder of prepare blocks. Blocks exist." ) ;
return true ;
}
@ -4770,10 +4778,11 @@ void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get
uint64_t fee ;
bool relayed , do_not_relay , double_spend_seen ;
transaction pool_tx ;
blobdata txblob ;
for ( const transaction & tx : txs )
{
crypto : : hash tx_hash = get_transaction_hash ( tx ) ;
m_tx_pool . take_tx ( tx_hash , pool_tx , tx _weight, fee , relayed , do_not_relay , double_spend_seen ) ;
m_tx_pool . take_tx ( tx_hash , pool_tx , tx blob, tx _weight, fee , relayed , do_not_relay , double_spend_seen ) ;
}
}
}