mirror of
https://github.com/monero-project/monero.git
synced 2025-08-09 10:02:24 -04:00
monerod can now sync from pruned blocks
If the peer (whether pruned or not itself) supports sending pruned blocks to syncing nodes, the pruned version will be sent along with the hash of the pruned data and the block weight. The original tx hashes can be reconstructed from the pruned txes and theur prunable data hash. Those hashes and the block weights are hashes and checked against the set of precompiled hashes, ensuring the data we received is the original data. It is currently not possible to use this system when not using the set of precompiled hashes, since block weights can not otherwise be checked for validity. This is off by default for now, and is enabled by --sync-pruned-blocks
This commit is contained in:
parent
d0d76f771a
commit
8330e772f1
30 changed files with 731 additions and 195 deletions
|
@ -1255,7 +1255,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
|||
}
|
||||
if(base_reward + fee < money_in_use)
|
||||
{
|
||||
MERROR_VER("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) << ")");
|
||||
MERROR_VER("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) << "), cumulative_block_weight " << cumulative_block_weight);
|
||||
return false;
|
||||
}
|
||||
// From hard fork 2, we allow a miner to claim less block reward than is allowed, in case a miner wants less dust
|
||||
|
@ -1907,8 +1907,9 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
|
|||
std::vector<std::pair<cryptonote::blobdata,block>> blocks;
|
||||
get_blocks(arg.blocks, blocks, rsp.missed_ids);
|
||||
|
||||
for (auto& bl: blocks)
|
||||
for (size_t i = 0; i < blocks.size(); ++i)
|
||||
{
|
||||
auto& bl = blocks[i];
|
||||
std::vector<crypto::hash> missed_tx_ids;
|
||||
|
||||
rsp.blocks.push_back(block_complete_entry());
|
||||
|
@ -1916,8 +1917,8 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
|
|||
|
||||
// FIXME: s/rsp.missed_ids/missed_tx_id/ ? Seems like rsp.missed_ids
|
||||
// is for missed blocks, not missed transactions as well.
|
||||
get_transactions_blobs(bl.second.tx_hashes, e.txs, missed_tx_ids);
|
||||
|
||||
e.pruned = arg.prune;
|
||||
get_transactions_blobs(bl.second.tx_hashes, e.txs, missed_tx_ids, arg.prune);
|
||||
if (missed_tx_ids.size() != 0)
|
||||
{
|
||||
// do not display an error if the peer asked for an unpruned block which we are not meant to have
|
||||
|
@ -1938,6 +1939,9 @@ bool Blockchain::handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NO
|
|||
|
||||
//pack block
|
||||
e.block = std::move(bl.first);
|
||||
e.block_weight = 0;
|
||||
if (arg.prune && m_db->block_exists(arg.blocks[i]))
|
||||
e.block_weight = m_db->get_block_weight(m_db->get_block_height(arg.blocks[i]));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -2216,23 +2220,95 @@ bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container
|
|||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
static bool fill(BlockchainDB *db, const crypto::hash &tx_hash, cryptonote::blobdata &tx, bool pruned)
|
||||
{
|
||||
if (pruned)
|
||||
{
|
||||
if (!db->get_pruned_tx_blob(tx_hash, tx))
|
||||
{
|
||||
MDEBUG("Pruned transaction blob not found for " << tx_hash);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!db->get_tx_blob(tx_hash, tx))
|
||||
{
|
||||
MDEBUG("Transaction blob not found for " << tx_hash);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
static bool fill(BlockchainDB *db, const crypto::hash &tx_hash, tx_blob_entry &tx, bool pruned)
|
||||
{
|
||||
if (!fill(db, tx_hash, tx.blob, pruned))
|
||||
return false;
|
||||
if (pruned)
|
||||
{
|
||||
if (is_v1_tx(tx.blob))
|
||||
{
|
||||
// v1 txes aren't pruned, so fetch the whole thing
|
||||
cryptonote::blobdata prunable_blob;
|
||||
if (!db->get_prunable_tx_blob(tx_hash, prunable_blob))
|
||||
{
|
||||
MDEBUG("Prunable transaction blob not found for " << tx_hash);
|
||||
return false;
|
||||
}
|
||||
tx.blob.append(prunable_blob);
|
||||
tx.prunable_hash = crypto::null_hash;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!db->get_prunable_tx_hash(tx_hash, tx.prunable_hash))
|
||||
{
|
||||
MDEBUG("Prunable transaction data hash not found for " << tx_hash);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
//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, bool pruned) const
|
||||
bool Blockchain::get_transactions_blobs(const std::vector<crypto::hash>& txs_ids, std::vector<cryptonote::blobdata>& txs, std::vector<crypto::hash>& missed_txs, bool pruned) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
reserve_container(txs, txs_ids.size());
|
||||
txs.reserve(txs_ids.size());
|
||||
for (const auto& tx_hash : txs_ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
cryptonote::blobdata tx;
|
||||
if (pruned && m_db->get_pruned_tx_blob(tx_hash, tx))
|
||||
if (fill(m_db, tx_hash, tx, pruned))
|
||||
txs.push_back(std::move(tx));
|
||||
else if (!pruned && m_db->get_tx_blob(tx_hash, tx))
|
||||
else
|
||||
missed_txs.push_back(tx_hash);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::get_transactions_blobs(const std::vector<crypto::hash>& txs_ids, std::vector<tx_blob_entry>& txs, std::vector<crypto::hash>& missed_txs, bool pruned) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
txs.reserve(txs_ids.size());
|
||||
for (const auto& tx_hash : txs_ids)
|
||||
{
|
||||
try
|
||||
{
|
||||
tx_blob_entry tx;
|
||||
if (fill(m_db, tx_hash, tx, pruned))
|
||||
txs.push_back(std::move(tx));
|
||||
else
|
||||
missed_txs.push_back(tx_hash);
|
||||
|
@ -2325,7 +2401,7 @@ bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container
|
|||
// 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.
|
||||
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
|
||||
bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, std::vector<crypto::hash>& hashes, std::vector<uint64_t>* weights, uint64_t& start_height, uint64_t& current_height, bool clip_pruned) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
@ -2342,25 +2418,34 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
|
|||
if (clip_pruned)
|
||||
{
|
||||
const uint32_t pruning_seed = get_blockchain_pruning_seed();
|
||||
start_height = tools::get_next_unpruned_block_height(start_height, current_height, pruning_seed);
|
||||
if (start_height < tools::get_next_unpruned_block_height(start_height, current_height, pruning_seed))
|
||||
{
|
||||
MDEBUG("We only have a pruned version of the common ancestor");
|
||||
return false;
|
||||
}
|
||||
stop_height = tools::get_next_pruned_block_height(start_height, current_height, pruning_seed);
|
||||
}
|
||||
size_t count = 0;
|
||||
hashes.reserve(std::min((size_t)(stop_height - start_height), (size_t)BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT));
|
||||
const size_t reserve = std::min((size_t)(stop_height - start_height), (size_t)BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT);
|
||||
hashes.reserve(reserve);
|
||||
if (weights)
|
||||
weights->reserve(reserve);
|
||||
for(size_t i = start_height; i < stop_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++)
|
||||
{
|
||||
hashes.push_back(m_db->get_block_hash_from_height(i));
|
||||
if (weights)
|
||||
weights->push_back(m_db->get_block_weight(i));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const
|
||||
bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, bool clip_pruned, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height, true);
|
||||
bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, &resp.m_block_weights, resp.start_height, resp.total_height, clip_pruned);
|
||||
if (result)
|
||||
{
|
||||
cryptonote::difficulty_type wide_cumulative_difficulty = m_db->get_block_cumulative_difficulty(resp.total_height - 1);
|
||||
|
@ -2799,18 +2884,24 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
|||
// II
|
||||
if (rv.type == rct::RCTTypeFull)
|
||||
{
|
||||
rv.p.MGs.resize(1);
|
||||
rv.p.MGs[0].II.resize(tx.vin.size());
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
rv.p.MGs[0].II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
|
||||
if (!tx.pruned)
|
||||
{
|
||||
rv.p.MGs.resize(1);
|
||||
rv.p.MGs[0].II.resize(tx.vin.size());
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
rv.p.MGs[0].II[n] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
|
||||
}
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == tx.vin.size(), false, "Bad MGs size");
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
if (!tx.pruned)
|
||||
{
|
||||
rv.p.MGs[n].II.resize(1);
|
||||
rv.p.MGs[n].II[0] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
|
||||
CHECK_AND_ASSERT_MES(rv.p.MGs.size() == tx.vin.size(), false, "Bad MGs size");
|
||||
for (size_t n = 0; n < tx.vin.size(); ++n)
|
||||
{
|
||||
rv.p.MGs[n].II.resize(1);
|
||||
rv.p.MGs[n].II[0] = rct::ki2rct(boost::get<txin_to_key>(tx.vin[n]).k_image);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2836,6 +2927,10 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
|||
if(pmax_used_block_height)
|
||||
*pmax_used_block_height = 0;
|
||||
|
||||
// pruned txes are skipped, as they're only allowed in sync-pruned-blocks mode, which is within the builtin hashes
|
||||
if (tx.pruned)
|
||||
return true;
|
||||
|
||||
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
|
||||
|
||||
const uint8_t hf_version = m_hardfork->get_current_version();
|
||||
|
@ -3539,9 +3634,9 @@ bool Blockchain::flush_txes_from_pool(const std::vector<crypto::hash> &txids)
|
|||
cryptonote::blobdata txblob;
|
||||
size_t tx_weight;
|
||||
uint64_t fee;
|
||||
bool relayed, do_not_relay, double_spend_seen;
|
||||
bool relayed, do_not_relay, double_spend_seen, pruned;
|
||||
MINFO("Removing txid " << txid << " from the pool");
|
||||
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))
|
||||
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, pruned))
|
||||
{
|
||||
MERROR("Failed to remove txid " << txid << " from the pool");
|
||||
res = false;
|
||||
|
@ -3639,7 +3734,7 @@ leave:
|
|||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
if (blockchain_height < m_blocks_hash_check.size())
|
||||
{
|
||||
const auto &expected_hash = m_blocks_hash_check[blockchain_height];
|
||||
const auto &expected_hash = m_blocks_hash_check[blockchain_height].first;
|
||||
if (expected_hash != crypto::null_hash)
|
||||
{
|
||||
if (memcmp(&id, &expected_hash, sizeof(hash)) != 0)
|
||||
|
@ -3713,6 +3808,7 @@ leave:
|
|||
uint64_t t_exists = 0;
|
||||
uint64_t t_pool = 0;
|
||||
uint64_t t_dblspnd = 0;
|
||||
uint64_t n_pruned = 0;
|
||||
TIME_MEASURE_FINISH(t3);
|
||||
|
||||
// XXX old code adds miner tx here
|
||||
|
@ -3728,7 +3824,7 @@ leave:
|
|||
blobdata txblob;
|
||||
size_t tx_weight = 0;
|
||||
uint64_t fee = 0;
|
||||
bool relayed = false, do_not_relay = false, double_spend_seen = false;
|
||||
bool relayed = false, do_not_relay = false, double_spend_seen = false, pruned = false;
|
||||
TIME_MEASURE_START(aa);
|
||||
|
||||
// XXX old code does not check whether tx exists
|
||||
|
@ -3745,13 +3841,15 @@ leave:
|
|||
TIME_MEASURE_START(bb);
|
||||
|
||||
// get transaction with hash <tx_id> from tx_pool
|
||||
if(!m_tx_pool.take_tx(tx_id, tx_tmp, txblob, 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, pruned))
|
||||
{
|
||||
MERROR_VER("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id);
|
||||
bvc.m_verifivation_failed = true;
|
||||
return_tx_to_pool(txs);
|
||||
goto leave;
|
||||
}
|
||||
if (pruned)
|
||||
++n_pruned;
|
||||
|
||||
TIME_MEASURE_FINISH(bb);
|
||||
t_pool += bb;
|
||||
|
@ -3822,6 +3920,17 @@ leave:
|
|||
cumulative_block_weight += tx_weight;
|
||||
}
|
||||
|
||||
// if we were syncing pruned blocks
|
||||
if (n_pruned > 0)
|
||||
{
|
||||
if (blockchain_height >= m_blocks_hash_check.size() || m_blocks_hash_check[blockchain_height].second == 0)
|
||||
{
|
||||
MERROR("Block at " << blockchain_height << " is pruned, but we do not have a weight for it");
|
||||
goto leave;
|
||||
}
|
||||
cumulative_block_weight = m_blocks_hash_check[blockchain_height].second;
|
||||
}
|
||||
|
||||
m_blocks_txs_check.clear();
|
||||
|
||||
TIME_MEASURE_START(vmt);
|
||||
|
@ -4262,11 +4371,13 @@ void Blockchain::output_scan_worker(const uint64_t amount, const std::vector<uin
|
|||
}
|
||||
}
|
||||
|
||||
uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector<crypto::hash> &hashes)
|
||||
uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector<crypto::hash> &hashes, const std::vector<uint64_t> &weights)
|
||||
{
|
||||
// new: . . . . . X X X X X . . . . . .
|
||||
// pre: A A A A B B B B C C C C D D D D
|
||||
|
||||
CHECK_AND_ASSERT_MES(weights.empty() || weights.size() == hashes.size(), 0, "Unexpected weights size");
|
||||
|
||||
// easy case: height >= hashes
|
||||
if (height >= m_blocks_hash_of_hashes.size() * HASH_OF_HASHES_STEP)
|
||||
return hashes.size();
|
||||
|
@ -4285,8 +4396,11 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
|
|||
return hashes.size();
|
||||
|
||||
// build hashes vector to hash hashes together
|
||||
std::vector<crypto::hash> data;
|
||||
data.reserve(hashes.size() + HASH_OF_HASHES_STEP - 1); // may be a bit too much
|
||||
std::vector<crypto::hash> data_hashes;
|
||||
std::vector<uint64_t> data_weights;
|
||||
data_hashes.reserve(hashes.size() + HASH_OF_HASHES_STEP - 1); // may be a bit too much
|
||||
if (!weights.empty())
|
||||
data_weights.reserve(data_hashes.size());
|
||||
|
||||
// we expect height to be either equal or a bit below db height
|
||||
bool disconnected = (height > m_db->height());
|
||||
|
@ -4301,18 +4415,24 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
|
|||
// we might need some already in the chain for the first part of the first hash
|
||||
for (uint64_t h = first_index * HASH_OF_HASHES_STEP; h < height; ++h)
|
||||
{
|
||||
data.push_back(m_db->get_block_hash_from_height(h));
|
||||
data_hashes.push_back(m_db->get_block_hash_from_height(h));
|
||||
if (!weights.empty())
|
||||
data_weights.push_back(m_db->get_block_weight(h));
|
||||
}
|
||||
pop = 0;
|
||||
}
|
||||
|
||||
// push the data to check
|
||||
for (const auto &h: hashes)
|
||||
for (size_t i = 0; i < hashes.size(); ++i)
|
||||
{
|
||||
if (pop)
|
||||
--pop;
|
||||
else
|
||||
data.push_back(h);
|
||||
{
|
||||
data_hashes.push_back(hashes[i]);
|
||||
if (!weights.empty())
|
||||
data_weights.push_back(weights[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// hash and check
|
||||
|
@ -4322,12 +4442,17 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
|
|||
if (n < m_blocks_hash_of_hashes.size())
|
||||
{
|
||||
// if the last index isn't fully filled, we can't tell if valid
|
||||
if (data.size() < (n - first_index) * HASH_OF_HASHES_STEP + HASH_OF_HASHES_STEP)
|
||||
if (data_hashes.size() < (n - first_index) * HASH_OF_HASHES_STEP + HASH_OF_HASHES_STEP)
|
||||
break;
|
||||
|
||||
crypto::hash hash;
|
||||
cn_fast_hash(data.data() + (n - first_index) * HASH_OF_HASHES_STEP, HASH_OF_HASHES_STEP * sizeof(crypto::hash), hash);
|
||||
bool valid = hash == m_blocks_hash_of_hashes[n];
|
||||
cn_fast_hash(data_hashes.data() + (n - first_index) * HASH_OF_HASHES_STEP, HASH_OF_HASHES_STEP * sizeof(crypto::hash), hash);
|
||||
bool valid = hash == m_blocks_hash_of_hashes[n].first;
|
||||
if (valid && !weights.empty())
|
||||
{
|
||||
cn_fast_hash(data_weights.data() + (n - first_index) * HASH_OF_HASHES_STEP, HASH_OF_HASHES_STEP * sizeof(uint64_t), hash);
|
||||
valid &= hash == m_blocks_hash_of_hashes[n].second;
|
||||
}
|
||||
|
||||
// add to the known hashes array
|
||||
if (!valid)
|
||||
|
@ -4339,9 +4464,15 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
|
|||
size_t end = n * HASH_OF_HASHES_STEP + HASH_OF_HASHES_STEP;
|
||||
for (size_t i = n * HASH_OF_HASHES_STEP; i < end; ++i)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(m_blocks_hash_check[i] == crypto::null_hash || m_blocks_hash_check[i] == data[i - first_index * HASH_OF_HASHES_STEP],
|
||||
CHECK_AND_ASSERT_MES(m_blocks_hash_check[i].first == crypto::null_hash || m_blocks_hash_check[i].first == data_hashes[i - first_index * HASH_OF_HASHES_STEP],
|
||||
0, "Consistency failure in m_blocks_hash_check construction");
|
||||
m_blocks_hash_check[i] = data[i - first_index * HASH_OF_HASHES_STEP];
|
||||
m_blocks_hash_check[i].first = data_hashes[i - first_index * HASH_OF_HASHES_STEP];
|
||||
if (!weights.empty())
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(m_blocks_hash_check[i].second == 0 || m_blocks_hash_check[i].second == data_weights[i - first_index * HASH_OF_HASHES_STEP],
|
||||
0, "Consistency failure in m_blocks_hash_check construction");
|
||||
m_blocks_hash_check[i].second = data_weights[i - first_index * HASH_OF_HASHES_STEP];
|
||||
}
|
||||
}
|
||||
usable += HASH_OF_HASHES_STEP;
|
||||
}
|
||||
|
@ -4358,6 +4489,18 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
|
|||
return usable;
|
||||
}
|
||||
|
||||
bool Blockchain::has_block_weights(uint64_t height, uint64_t nblocks) const
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(nblocks > 0, false, "nblocks is 0");
|
||||
uint64_t last_block_height = height + nblocks - 1;
|
||||
if (last_block_height >= m_blocks_hash_check.size())
|
||||
return false;
|
||||
for (uint64_t h = height; h <= last_block_height; ++h)
|
||||
if (m_blocks_hash_check[h].second == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// ND: Speedups:
|
||||
// 1. Thread long_hash computations if possible (m_max_prepare_blocks_threads = nthreads, default = 4)
|
||||
|
@ -4399,7 +4542,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
|
|||
bytes += entry.block.size();
|
||||
for (const auto &tx_blob : entry.txs)
|
||||
{
|
||||
bytes += tx_blob.size();
|
||||
bytes += tx_blob.blob.size();
|
||||
}
|
||||
total_txs += entry.txs.size();
|
||||
}
|
||||
|
@ -4555,7 +4698,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
|
|||
crypto::hash &tx_prefix_hash = txes[tx_index].second;
|
||||
++tx_index;
|
||||
|
||||
if (!parse_and_validate_tx_base_from_blob(tx_blob, tx))
|
||||
if (!parse_and_validate_tx_base_from_blob(tx_blob.blob, tx))
|
||||
SCAN_TABLE_QUIT("Could not parse tx from incoming blocks.");
|
||||
cryptonote::get_transaction_prefix_hash(tx, tx_prefix_hash);
|
||||
|
||||
|
@ -4887,7 +5030,7 @@ void Blockchain::cancel()
|
|||
}
|
||||
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
static const char expected_block_hashes_hash[] = "7dafb40b414a0e59bfced6682ef519f0b416bc914dd3d622b72e0dd1a47117c2";
|
||||
static const char expected_block_hashes_hash[] = "95e60612c1a16f4cd992c335b66daabd98e2d351c2b02b66e43ced0296848d33";
|
||||
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
|
||||
{
|
||||
if (get_checkpoints == nullptr || !m_fast_sync)
|
||||
|
@ -4931,19 +5074,21 @@ void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get
|
|||
MERROR("Block hash data is too large");
|
||||
return;
|
||||
}
|
||||
const size_t size_needed = 4 + nblocks * sizeof(crypto::hash);
|
||||
const size_t size_needed = 4 + nblocks * (sizeof(crypto::hash) * 2);
|
||||
if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP && checkpoints.size() >= size_needed)
|
||||
{
|
||||
p += sizeof(uint32_t);
|
||||
m_blocks_hash_of_hashes.reserve(nblocks);
|
||||
for (uint32_t i = 0; i < nblocks; i++)
|
||||
{
|
||||
crypto::hash hash;
|
||||
memcpy(hash.data, p, sizeof(hash.data));
|
||||
p += sizeof(hash.data);
|
||||
m_blocks_hash_of_hashes.push_back(hash);
|
||||
crypto::hash hash_hashes, hash_weights;
|
||||
memcpy(hash_hashes.data, p, sizeof(hash_hashes.data));
|
||||
p += sizeof(hash_hashes.data);
|
||||
memcpy(hash_weights.data, p, sizeof(hash_weights.data));
|
||||
p += sizeof(hash_weights.data);
|
||||
m_blocks_hash_of_hashes.push_back(std::make_pair(hash_hashes, hash_weights));
|
||||
}
|
||||
m_blocks_hash_check.resize(m_blocks_hash_of_hashes.size() * HASH_OF_HASHES_STEP, crypto::null_hash);
|
||||
m_blocks_hash_check.resize(m_blocks_hash_of_hashes.size() * HASH_OF_HASHES_STEP, std::make_pair(crypto::null_hash, 0));
|
||||
MINFO(nblocks << " block hashes loaded");
|
||||
|
||||
// FIXME: clear tx_pool because the process might have been
|
||||
|
@ -4958,13 +5103,13 @@ void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get
|
|||
|
||||
size_t tx_weight;
|
||||
uint64_t fee;
|
||||
bool relayed, do_not_relay, double_spend_seen;
|
||||
bool relayed, do_not_relay, double_spend_seen, pruned;
|
||||
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, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen);
|
||||
m_tx_pool.take_tx(tx_hash, pool_tx, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen, pruned);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5037,6 +5182,5 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_
|
|||
|
||||
namespace cryptonote {
|
||||
template bool Blockchain::get_transactions(const std::vector<crypto::hash>&, std::vector<transaction>&, std::vector<crypto::hash>&) const;
|
||||
template bool Blockchain::get_transactions_blobs(const std::vector<crypto::hash>&, std::vector<cryptonote::blobdata>&, std::vector<crypto::hash>&, bool) const;
|
||||
template bool Blockchain::get_split_transactions_blobs(const std::vector<crypto::hash>&, std::vector<std::tuple<crypto::hash, cryptonote::blobdata, crypto::hash, cryptonote::blobdata>>&, std::vector<crypto::hash>&) const;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue