aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core/blockchain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_core/blockchain.cpp')
-rw-r--r--src/cryptonote_core/blockchain.cpp129
1 files changed, 96 insertions, 33 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 3db516847..54d8fac31 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -156,7 +156,9 @@ static const struct {
//------------------------------------------------------------------
Blockchain::Blockchain(tx_memory_pool& tx_pool) :
m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_current_block_cumul_sz_median(0),
- m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(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_cancel(false)
+ m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(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_cancel(false),
+ m_difficulty_for_next_block_top_hash(crypto::null_hash),
+ m_difficulty_for_next_block(1)
{
LOG_PRINT_L3("Blockchain::" << __func__);
}
@@ -441,6 +443,53 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
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());
m_db->block_txn_stop();
+ uint64_t num_popped_blocks = 0;
+ while (true)
+ {
+ const uint64_t top_height = m_db->height() - 1;
+ const crypto::hash top_id = m_db->top_block_hash();
+ 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)
+ {
+ if (num_popped_blocks > 0)
+ MGINFO("Initial popping done, top block: " << top_id << ", top height: " << top_height << ", block version: " << (uint64_t)top_block.major_version);
+ break;
+ }
+ else
+ {
+ if (num_popped_blocks == 0)
+ 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);
+ if (num_popped_blocks % 100 == 0)
+ MGINFO("Popping blocks... " << top_height);
+ ++num_popped_blocks;
+ block popped_block;
+ std::vector<transaction> popped_txs;
+ try
+ {
+ m_db->pop_block(popped_block, popped_txs);
+ }
+ // anything that could cause this to throw is likely catastrophic,
+ // so we re-throw
+ catch (const std::exception& e)
+ {
+ MERROR("Error popping block from blockchain: " << e.what());
+ throw;
+ }
+ catch (...)
+ {
+ MERROR("Error popping block from blockchain, throwing!");
+ throw;
+ }
+ }
+ }
+ if (num_popped_blocks > 0)
+ {
+ 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());
+ }
+
update_next_cumulative_size_limit();
return true;
}
@@ -584,6 +633,12 @@ block Blockchain::pop_block_from_blockchain()
}
}
}
+
+ m_blocks_longhash_table.clear();
+ m_scan_table.clear();
+ m_blocks_txs_check.clear();
+ m_check_txin_table.clear();
+
update_next_cumulative_size_limit();
m_tx_pool.on_blockchain_dec(m_db->height()-1, get_tail_id());
@@ -751,7 +806,17 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
difficulty_type Blockchain::get_difficulty_for_next_block()
{
LOG_PRINT_L3("Blockchain::" << __func__);
- CRITICAL_REGION_LOCAL(m_blockchain_lock);
+
+ CRITICAL_REGION_LOCAL(m_difficulty_lock);
+ // we can call this without the blockchain lock, it might just give us
+ // something a bit out of date, but that's fine since anything which
+ // requires the blockchain lock will have acquired it in the first place,
+ // and it will be unlocked only when called from the getinfo RPC
+ crypto::hash top_hash = get_tail_id();
+ if (top_hash == m_difficulty_for_next_block_top_hash)
+ return m_difficulty_for_next_block;
+
+ CRITICAL_REGION_LOCAL1(m_blockchain_lock);
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> difficulties;
auto height = m_db->height();
@@ -794,7 +859,10 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
m_difficulties = difficulties;
}
size_t target = get_difficulty_target();
- return next_difficulty(timestamps, difficulties, target);
+ difficulty_type diff = next_difficulty(timestamps, difficulties, target);
+ m_difficulty_for_next_block_top_hash = top_hash;
+ m_difficulty_for_next_block = diff;
+ return diff;
}
//------------------------------------------------------------------
// This function removes blocks from the blockchain until it gets to the
@@ -1142,6 +1210,12 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
b.prev_id = get_tail_id();
b.timestamp = time(NULL);
+ uint64_t median_ts;
+ if (!check_block_timestamp(b, median_ts))
+ {
+ b.timestamp = median_ts;
+ }
+
diffic = get_difficulty_for_next_block();
CHECK_AND_ASSERT_MES(diffic, false, "difficulty overhead.");
@@ -1903,7 +1977,7 @@ void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint
unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first));
}
//------------------------------------------------------------------
-bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const
+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
{
// rct outputs don't exist before v3
if (amount == 0)
@@ -1924,22 +1998,7 @@ bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height,
if (from_height > start_height)
start_height = from_height;
- distribution.clear();
- uint64_t db_height = m_db->height();
- if (start_height >= db_height)
- return false;
- distribution.resize(db_height - start_height, 0);
- bool r = for_all_outputs(amount, [&](uint64_t height) {
- CHECK_AND_ASSERT_MES(height >= real_start_height && height <= db_height, false, "Height not in expected range");
- if (height >= start_height)
- distribution[height - start_height]++;
- else
- base++;
- return true;
- });
- if (!r)
- return false;
- return true;
+ return m_db->get_output_distribution(amount, start_height, to_height, distribution, base);
}
//------------------------------------------------------------------
// This function takes a list of block hashes from another node
@@ -2054,7 +2113,7 @@ bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container
//TODO: return type should be void, throw on exception
// alternatively, return true only if no transactions missed
template<class t_ids_container, class t_tx_container, class t_missed_container>
-bool Blockchain::get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const
+bool Blockchain::get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs, bool pruned) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -2064,7 +2123,9 @@ bool Blockchain::get_transactions_blobs(const t_ids_container& txs_ids, t_tx_con
try
{
cryptonote::blobdata tx;
- if (m_db->get_tx_blob(tx_hash, tx))
+ if (pruned && m_db->get_pruned_tx_blob(tx_hash, tx))
+ txs.push_back(std::move(tx));
+ else if (!pruned && m_db->get_tx_blob(tx_hash, tx))
txs.push_back(std::move(tx));
else
missed_txs.push_back(tx_hash);
@@ -2149,7 +2210,7 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
// find split point between ours and foreign blockchain (or start at
// blockchain height <req_start_block>), and return up to max_count FULL
// blocks by reference.
-bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const
+bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::list<std::pair<cryptonote::blobdata, std::list<cryptonote::blobdata> > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, size_t max_count) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
@@ -2182,7 +2243,7 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
block b;
CHECK_AND_ASSERT_MES(parse_and_validate_block_from_blob(blocks.back().first, b), false, "internal error, invalid block");
std::list<crypto::hash> mis;
- get_transactions_blobs(b.tx_hashes, blocks.back().second, mis);
+ get_transactions_blobs(b.tx_hashes, blocks.back().second, mis, pruned);
CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, transaction from block not found");
size += blocks.back().first.size();
for (const auto &t: blocks.back().second)
@@ -2658,6 +2719,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
+ const auto waiter_guard = epee::misc_utils::create_scope_leave_handler([&]() { waiter.wait(); });
int threads = tpool.get_max_concurrency();
for (const auto& txin : tx.vin)
@@ -3127,10 +3189,10 @@ uint64_t Blockchain::get_adjusted_time() const
}
//------------------------------------------------------------------
//TODO: revisit, has changed a bit on upstream
-bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b) const
+bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const block& b, uint64_t& median_ts) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
- uint64_t median_ts = epee::misc_utils::median(timestamps);
+ median_ts = epee::misc_utils::median(timestamps);
if(b.timestamp < median_ts)
{
@@ -3148,7 +3210,7 @@ bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const
// true if the block's timestamp is not less than the timestamp of the
// median of the selected blocks
// false otherwise
-bool Blockchain::check_block_timestamp(const block& b) const
+bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
if(b.timestamp > get_adjusted_time() + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT)
@@ -3173,7 +3235,7 @@ bool Blockchain::check_block_timestamp(const block& b) const
timestamps.push_back(m_db->get_block_timestamp(offset));
}
- return check_block_timestamp(timestamps, b);
+ return check_block_timestamp(timestamps, b, median_ts);
}
//------------------------------------------------------------------
void Blockchain::return_tx_to_pool(std::vector<transaction> &txs)
@@ -4322,9 +4384,9 @@ uint64_t Blockchain::get_difficulty_target() const
return get_current_hard_fork_version() < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
}
-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) const
+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) const
{
- return m_db->get_output_histogram(amounts, unlocked, recent_cutoff);
+ return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count);
}
std::list<std::pair<Blockchain::block_extended_info,uint64_t>> Blockchain::get_alternative_chains() const
@@ -4365,7 +4427,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
-static const char expected_block_hashes_hash[] = "4b553162ee4e7af3c53666506591489c68560b9175e6e941dc96c89f96f0e35c";
+static const char expected_block_hashes_hash[] = "59261c03b54bcb21bd463f9fe40a94f40840a12642e9a3b3bfb11b35839a5fe3";
void Blockchain::load_compiled_in_block_hashes()
{
const bool testnet = m_nettype == TESTNET;
@@ -4476,9 +4538,9 @@ bool Blockchain::for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::f
return m_db->for_blocks_range(h1, h2, f);
}
-bool Blockchain::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f) const
+bool Blockchain::for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)> f, bool pruned) const
{
- return m_db->for_all_transactions(f);
+ return m_db->for_all_transactions(f, pruned);
}
bool Blockchain::for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const
@@ -4493,4 +4555,5 @@ bool Blockchain::for_all_outputs(uint64_t amount, std::function<bool(uint64_t he
namespace cryptonote {
template bool Blockchain::get_transactions(const std::vector<crypto::hash>&, std::list<transaction>&, std::list<crypto::hash>&) const;
+template bool Blockchain::get_transactions_blobs(const std::vector<crypto::hash>&, std::list<cryptonote::blobdata>&, std::list<crypto::hash>&, bool) const;
}