Merge pull request #5100

c4851024 wallet_rpc_server: avoid repeated string allocations when parsing (moneromooo-monero)
88c85c18 cryptonote: avoid double parsing blocks when syncing (moneromooo-monero)
9feda0ee cryptonote: speed up calculating coinbase tx prunable hash (moneromooo-monero)
238401d4 core: avoid double parsing blocks after hoh (moneromooo-monero)
dc5a7609 blockchain: avoid unneeded block copy (moneromooo-monero)
79b4e9f3 save some database calls when getting top block hash and height (moneromooo-monero)
98278808 blockchain: avoid pointless transaction copy and temporary (moneromooo-monero)
07d655e4 blockchain: avoid duplicate block hash computation (moneromooo-monero)
f75d51ab core: avoid calculating tx prefix hash when we don't need it (moneromooo-monero)
b044d03a Avoid repeated (de)serialization when syncing (moneromooo-monero)
b747e836 wallet2: don't calculate prefix hash when we don't need it (moneromooo-monero)
e69477bf db: speedup block addition (moneromooo-monero)
This commit is contained in:
Riccardo Spagni 2019-03-05 14:09:19 +02:00
commit ed6aa76cca
No known key found for this signature in database
GPG Key ID: 55432DF31CCD4FCD
25 changed files with 353 additions and 229 deletions

View File

@ -121,8 +121,10 @@ void BlockchainDB::pop_block()
pop_block(blk, txs); pop_block(blk, txs);
} }
void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr, const crypto::hash* tx_prunable_hash_ptr) void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& txp, const crypto::hash* tx_hash_ptr, const crypto::hash* tx_prunable_hash_ptr)
{ {
const transaction &tx = txp.first;
bool miner_tx = false; bool miner_tx = false;
crypto::hash tx_hash, tx_prunable_hash; crypto::hash tx_hash, tx_prunable_hash;
if (!tx_hash_ptr) if (!tx_hash_ptr)
@ -138,7 +140,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
if (tx.version >= 2) if (tx.version >= 2)
{ {
if (!tx_prunable_hash_ptr) if (!tx_prunable_hash_ptr)
tx_prunable_hash = get_transaction_prunable_hash(tx); tx_prunable_hash = get_transaction_prunable_hash(tx, &txp.second);
else else
tx_prunable_hash = *tx_prunable_hash_ptr; tx_prunable_hash = *tx_prunable_hash_ptr;
} }
@ -168,7 +170,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
} }
} }
uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash, tx_prunable_hash); uint64_t tx_id = add_transaction_data(blk_hash, txp, tx_hash, tx_prunable_hash);
std::vector<uint64_t> amount_output_indices(tx.vout.size()); std::vector<uint64_t> amount_output_indices(tx.vout.size());
@ -195,14 +197,16 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
add_tx_amount_output_indices(tx_id, amount_output_indices); add_tx_amount_output_indices(tx_id, amount_output_indices);
} }
uint64_t BlockchainDB::add_block( const block& blk uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
, size_t block_weight , size_t block_weight
, uint64_t long_term_block_weight , uint64_t long_term_block_weight
, const difficulty_type& cumulative_difficulty , const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated , const uint64_t& coins_generated
, const std::vector<transaction>& txs , const std::vector<std::pair<transaction, blobdata>>& txs
) )
{ {
const block &blk = blck.first;
// sanity // sanity
if (blk.tx_hashes.size() != txs.size()) if (blk.tx_hashes.size() != txs.size())
throw std::runtime_error("Inconsistent tx/hashes sizes"); throw std::runtime_error("Inconsistent tx/hashes sizes");
@ -221,16 +225,16 @@ uint64_t BlockchainDB::add_block( const block& blk
time1 = epee::misc_utils::get_tick_count(); time1 = epee::misc_utils::get_tick_count();
uint64_t num_rct_outs = 0; uint64_t num_rct_outs = 0;
add_transaction(blk_hash, blk.miner_tx); add_transaction(blk_hash, std::make_pair(blk.miner_tx, tx_to_blob(blk.miner_tx)));
if (blk.miner_tx.version == 2) if (blk.miner_tx.version == 2)
num_rct_outs += blk.miner_tx.vout.size(); num_rct_outs += blk.miner_tx.vout.size();
int tx_i = 0; int tx_i = 0;
crypto::hash tx_hash = crypto::null_hash; crypto::hash tx_hash = crypto::null_hash;
for (const transaction& tx : txs) for (const std::pair<transaction, blobdata>& tx : txs)
{ {
tx_hash = blk.tx_hashes[tx_i]; tx_hash = blk.tx_hashes[tx_i];
add_transaction(blk_hash, tx, &tx_hash); add_transaction(blk_hash, tx, &tx_hash);
for (const auto &vout: tx.vout) for (const auto &vout: tx.first.vout)
{ {
if (vout.amount == 0) if (vout.amount == 0)
++num_rct_outs; ++num_rct_outs;

View File

@ -404,7 +404,7 @@ private:
* @param tx_prunable_hash the hash of the prunable part of the transaction * @param tx_prunable_hash the hash of the prunable part of the transaction
* @return the transaction ID * @return the transaction ID
*/ */
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) = 0; virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) = 0;
/** /**
* @brief remove data about a transaction * @brief remove data about a transaction
@ -532,7 +532,7 @@ protected:
* @param tx_hash_ptr the hash of the transaction, if already calculated * @param tx_hash_ptr the hash of the transaction, if already calculated
* @param tx_prunable_hash_ptr the hash of the prunable part of the transaction, if already calculated * @param tx_prunable_hash_ptr the hash of the prunable part of the transaction, if already calculated
*/ */
void add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr = NULL, const crypto::hash* tx_prunable_hash_ptr = NULL); void add_transaction(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& tx, const crypto::hash* tx_hash_ptr = NULL, const crypto::hash* tx_prunable_hash_ptr = NULL);
mutable uint64_t time_tx_exists = 0; //!< a performance metric mutable uint64_t time_tx_exists = 0; //!< a performance metric
uint64_t time_commit1 = 0; //!< a performance metric uint64_t time_commit1 = 0; //!< a performance metric
@ -798,12 +798,12 @@ public:
* *
* @return the height of the chain post-addition * @return the height of the chain post-addition
*/ */
virtual uint64_t add_block( const block& blk virtual uint64_t add_block( const std::pair<block, blobdata>& blk
, size_t block_weight , size_t block_weight
, uint64_t long_term_block_weight , uint64_t long_term_block_weight
, const difficulty_type& cumulative_difficulty , const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated , const uint64_t& coins_generated
, const std::vector<transaction>& txs , const std::vector<std::pair<transaction, blobdata>>& txs
); );
/** /**
@ -1052,9 +1052,11 @@ public:
* *
* The subclass should return the hash of the most recent block * The subclass should return the hash of the most recent block
* *
* @param block_height if non NULL, returns the height of that block (ie, the blockchain height minus 1)
*
* @return the top block's hash * @return the top block's hash
*/ */
virtual crypto::hash top_block_hash() const = 0; virtual crypto::hash top_block_hash(uint64_t *block_height = NULL) const = 0;
/** /**
* @brief fetch the top block * @brief fetch the top block

View File

@ -823,7 +823,7 @@ void BlockchainLMDB::remove_block()
throw1(DB_ERROR(lmdb_error("Failed to add removal of block info to db transaction: ", result).c_str())); throw1(DB_ERROR(lmdb_error("Failed to add removal of block info to db transaction: ", result).c_str()));
} }
uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& txp, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash)
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
@ -849,6 +849,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
throw1(DB_ERROR(lmdb_error(std::string("Error checking if tx index exists for tx hash ") + epee::string_tools::pod_to_hex(tx_hash) + ": ", result).c_str())); throw1(DB_ERROR(lmdb_error(std::string("Error checking if tx index exists for tx hash ") + epee::string_tools::pod_to_hex(tx_hash) + ": ", result).c_str()));
} }
const cryptonote::transaction &tx = txp.first;
txindex ti; txindex ti;
ti.key = tx_hash; ti.key = tx_hash;
ti.data.tx_id = tx_id; ti.data.tx_id = tx_id;
@ -862,24 +863,29 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
if (result) if (result)
throw0(DB_ERROR(lmdb_error("Failed to add tx data to db transaction: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to add tx data to db transaction: ", result).c_str()));
cryptonote::blobdata blob = tx_to_blob(tx); const cryptonote::blobdata &blob = txp.second;
MDB_val_sized(blobval, blob); MDB_val_sized(blobval, blob);
std::stringstream ss; unsigned int unprunable_size = tx.unprunable_size;
binary_archive<true> ba(ss); if (unprunable_size == 0)
bool r = const_cast<cryptonote::transaction&>(tx).serialize_base(ba); {
if (!r) std::stringstream ss;
throw0(DB_ERROR("Failed to serialize pruned tx")); binary_archive<true> ba(ss);
std::string pruned = ss.str(); bool r = const_cast<cryptonote::transaction&>(tx).serialize_base(ba);
MDB_val_sized(pruned_blob, pruned); if (!r)
throw0(DB_ERROR("Failed to serialize pruned tx"));
unprunable_size = ss.str().size();
}
if (unprunable_size > blob.size())
throw0(DB_ERROR("pruned tx size is larger than tx size"));
MDB_val pruned_blob = {unprunable_size, (void*)blob.data()};
result = mdb_cursor_put(m_cur_txs_pruned, &val_tx_id, &pruned_blob, MDB_APPEND); result = mdb_cursor_put(m_cur_txs_pruned, &val_tx_id, &pruned_blob, MDB_APPEND);
if (result) if (result)
throw0(DB_ERROR(lmdb_error("Failed to add pruned tx blob to db transaction: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to add pruned tx blob to db transaction: ", result).c_str()));
if (pruned.size() > blob.size()) MDB_val prunable_blob = {blob.size() - unprunable_size, (void*)(blob.data() + unprunable_size)};
throw0(DB_ERROR("pruned tx size is larger than tx size"));
cryptonote::blobdata prunable(blob.data() + pruned.size(), blob.size() - pruned.size());
MDB_val_sized(prunable_blob, prunable);
result = mdb_cursor_put(m_cur_txs_prunable, &val_tx_id, &prunable_blob, MDB_APPEND); result = mdb_cursor_put(m_cur_txs_prunable, &val_tx_id, &prunable_blob, MDB_APPEND);
if (result) if (result)
throw0(DB_ERROR(lmdb_error("Failed to add prunable tx blob to db transaction: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to add prunable tx blob to db transaction: ", result).c_str()));
@ -2576,11 +2582,13 @@ std::vector<crypto::hash> BlockchainLMDB::get_hashes_range(const uint64_t& h1, c
return v; return v;
} }
crypto::hash BlockchainLMDB::top_block_hash() const crypto::hash BlockchainLMDB::top_block_hash(uint64_t *block_height) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
uint64_t m_height = height(); uint64_t m_height = height();
if (block_height)
*block_height = m_height - 1;
if (m_height != 0) if (m_height != 0)
{ {
return get_block_hash_from_height(m_height - 1); return get_block_hash_from_height(m_height - 1);
@ -3563,8 +3571,8 @@ void BlockchainLMDB::block_txn_abort()
} }
} }
uint64_t BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated,
const std::vector<transaction>& txs) const std::vector<std::pair<transaction, blobdata>>& txs)
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
@ -4483,7 +4491,7 @@ void BlockchainLMDB::migrate_0_1()
if (!parse_and_validate_block_from_blob(bd, b)) if (!parse_and_validate_block_from_blob(bd, b))
throw0(DB_ERROR("Failed to parse block from blob retrieved from the db")); throw0(DB_ERROR("Failed to parse block from blob retrieved from the db"));
add_transaction(null_hash, b.miner_tx); add_transaction(null_hash, std::make_pair(b.miner_tx, tx_to_blob(b.miner_tx)));
for (unsigned int j = 0; j<b.tx_hashes.size(); j++) { for (unsigned int j = 0; j<b.tx_hashes.size(); j++) {
transaction tx; transaction tx;
hk.mv_data = &b.tx_hashes[j]; hk.mv_data = &b.tx_hashes[j];
@ -4493,7 +4501,7 @@ void BlockchainLMDB::migrate_0_1()
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size); bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
if (!parse_and_validate_tx_from_blob(bd, tx)) if (!parse_and_validate_tx_from_blob(bd, tx))
throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db")); throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
add_transaction(null_hash, tx, &b.tx_hashes[j]); add_transaction(null_hash, std::make_pair(std::move(tx), bd), &b.tx_hashes[j]);
result = mdb_cursor_del(c_txs, 0); result = mdb_cursor_del(c_txs, 0);
if (result) if (result)
throw0(DB_ERROR(lmdb_error("Failed to get record from txs: ", result).c_str())); throw0(DB_ERROR(lmdb_error("Failed to get record from txs: ", result).c_str()));

View File

@ -233,7 +233,7 @@ public:
virtual std::vector<crypto::hash> get_hashes_range(const uint64_t& h1, const uint64_t& h2) const; virtual std::vector<crypto::hash> get_hashes_range(const uint64_t& h1, const uint64_t& h2) const;
virtual crypto::hash top_block_hash() const; virtual crypto::hash top_block_hash(uint64_t *block_height = NULL) const;
virtual block get_top_block() const; virtual block get_top_block() const;
@ -292,12 +292,12 @@ public:
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const; virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const;
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const; virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const;
virtual uint64_t add_block( const block& blk virtual uint64_t add_block( const std::pair<block, blobdata>& blk
, size_t block_weight , size_t block_weight
, uint64_t long_term_block_weight , uint64_t long_term_block_weight
, const difficulty_type& cumulative_difficulty , const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated , const uint64_t& coins_generated
, const std::vector<transaction>& txs , const std::vector<std::pair<transaction, blobdata>>& txs
); );
virtual void set_batch_transactions(bool batch_transactions); virtual void set_batch_transactions(bool batch_transactions);
@ -353,7 +353,7 @@ private:
virtual void remove_block(); virtual void remove_block();
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash); virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash);
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx); virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx);

View File

@ -79,7 +79,7 @@ public:
virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const { return crypto::hash(); } virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const { return crypto::hash(); }
virtual std::vector<cryptonote::block> get_blocks_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector<cryptonote::block>(); } virtual std::vector<cryptonote::block> get_blocks_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector<cryptonote::block>(); }
virtual std::vector<crypto::hash> get_hashes_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector<crypto::hash>(); } virtual std::vector<crypto::hash> get_hashes_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector<crypto::hash>(); }
virtual crypto::hash top_block_hash() const { return crypto::hash(); } virtual crypto::hash top_block_hash(uint64_t *block_height = NULL) const { if (block_height) *block_height = 0; return crypto::hash(); }
virtual cryptonote::block get_top_block() const { return cryptonote::block(); } virtual cryptonote::block get_top_block() const { return cryptonote::block(); }
virtual uint64_t height() const { return 1; } virtual uint64_t height() const { return 1; }
virtual bool tx_exists(const crypto::hash& h) const { return false; } virtual bool tx_exists(const crypto::hash& h) const { return false; }
@ -102,7 +102,7 @@ public:
virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_index, size_t n_txes) const { return std::vector<std::vector<uint64_t>>(); } virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_index, size_t n_txes) const { return std::vector<std::vector<uint64_t>>(); }
virtual bool has_key_image(const crypto::key_image& img) const { return false; } virtual bool has_key_image(const crypto::key_image& img) const { return false; }
virtual void remove_block() { } virtual void remove_block() { }
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const cryptonote::transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) {return 0;} virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<cryptonote::transaction, cryptonote::blobdata>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) {return 0;}
virtual void remove_transaction_data(const crypto::hash& tx_hash, const cryptonote::transaction& tx) {} virtual void remove_transaction_data(const crypto::hash& tx_hash, const cryptonote::transaction& tx) {}
virtual uint64_t add_output(const crypto::hash& tx_hash, const cryptonote::tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) {return 0;} virtual uint64_t add_output(const crypto::hash& tx_hash, const cryptonote::tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) {return 0;}
virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector<uint64_t>& amount_output_indices) {} virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector<uint64_t>& amount_output_indices) {}

View File

@ -193,8 +193,16 @@ int check_flush(cryptonote::core &core, std::vector<block_complete_entry> &block
} }
core.prevalidate_block_hashes(core.get_blockchain_storage().get_db().height(), hashes); core.prevalidate_block_hashes(core.get_blockchain_storage().get_db().height(), hashes);
core.prepare_handle_incoming_blocks(blocks); std::vector<block> pblocks;
core.prepare_handle_incoming_blocks(blocks, pblocks);
if (!pblocks.empty() && pblocks.size() != blocks.size())
{
MERROR("Unexpected parsed blocks size");
core.cleanup_handle_incoming_blocks();
return 1;
}
size_t blockidx = 0;
for(const block_complete_entry& block_entry: blocks) for(const block_complete_entry& block_entry: blocks)
{ {
// process transactions // process transactions
@ -215,7 +223,7 @@ int check_flush(cryptonote::core &core, std::vector<block_complete_entry> &block
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
core.handle_incoming_block(block_entry.block, bvc, false); // <--- process block core.handle_incoming_block(block_entry.block, pblocks.empty() ? NULL : &pblocks[blockidx++], bvc, false); // <--- process block
if(bvc.m_verifivation_failed) if(bvc.m_verifivation_failed)
{ {
@ -455,7 +463,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
} }
else else
{ {
std::vector<transaction> txs; std::vector<std::pair<transaction, blobdata>> txs;
std::vector<transaction> archived_txs; std::vector<transaction> archived_txs;
archived_txs = bp.txs; archived_txs = bp.txs;
@ -472,7 +480,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
// because add_block() calls // because add_block() calls
// add_transaction(blk_hash, blk.miner_tx) first, and // add_transaction(blk_hash, blk.miner_tx) first, and
// then a for loop for the transactions in txs. // then a for loop for the transactions in txs.
txs.push_back(tx); txs.push_back(std::make_pair(tx, tx_to_blob(tx)));
} }
size_t block_weight; size_t block_weight;
@ -486,7 +494,7 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
try try
{ {
uint64_t long_term_block_weight = core.get_blockchain_storage().get_next_long_term_block_weight(block_weight); uint64_t long_term_block_weight = core.get_blockchain_storage().get_next_long_term_block_weight(block_weight);
core.get_blockchain_storage().get_db().add_block(b, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs); core.get_blockchain_storage().get_db().add_block(std::make_pair(b, block_to_blob(b)), block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {

View File

@ -152,6 +152,10 @@ namespace cryptonote
}; };
template<typename T> static inline unsigned int getpos(T &ar) { return 0; }
template<> inline unsigned int getpos(binary_archive<true> &ar) { return ar.stream().tellp(); }
template<> inline unsigned int getpos(binary_archive<false> &ar) { return ar.stream().tellg(); }
class transaction_prefix class transaction_prefix
{ {
@ -203,9 +207,12 @@ namespace cryptonote
bool pruned; bool pruned;
std::atomic<unsigned int> unprunable_size;
std::atomic<unsigned int> prefix_size;
transaction(); transaction();
transaction(const transaction &t): transaction_prefix(t), hash_valid(false), blob_size_valid(false), signatures(t.signatures), rct_signatures(t.rct_signatures), pruned(t.pruned) { if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } } transaction(const transaction &t): transaction_prefix(t), hash_valid(false), blob_size_valid(false), signatures(t.signatures), rct_signatures(t.rct_signatures), pruned(t.pruned), unprunable_size(t.unprunable_size.load()), prefix_size(t.prefix_size.load()) { if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } }
transaction &operator=(const transaction &t) { transaction_prefix::operator=(t); set_hash_valid(false); set_blob_size_valid(false); signatures = t.signatures; rct_signatures = t.rct_signatures; if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } pruned = t.pruned; return *this; } transaction &operator=(const transaction &t) { transaction_prefix::operator=(t); set_hash_valid(false); set_blob_size_valid(false); signatures = t.signatures; rct_signatures = t.rct_signatures; if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } pruned = t.pruned; unprunable_size = t.unprunable_size.load(); prefix_size = t.prefix_size.load(); return *this; }
virtual ~transaction(); virtual ~transaction();
void set_null(); void set_null();
void invalidate_hashes(); void invalidate_hashes();
@ -223,10 +230,18 @@ namespace cryptonote
set_blob_size_valid(false); set_blob_size_valid(false);
} }
const unsigned int start_pos = getpos(ar);
FIELDS(*static_cast<transaction_prefix *>(this)) FIELDS(*static_cast<transaction_prefix *>(this))
if (std::is_same<Archive<W>, binary_archive<W>>())
prefix_size = getpos(ar) - start_pos;
if (version == 1) if (version == 1)
{ {
if (std::is_same<Archive<W>, binary_archive<W>>())
unprunable_size = getpos(ar) - start_pos;
ar.tag("signatures"); ar.tag("signatures");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures); PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures);
@ -265,6 +280,10 @@ namespace cryptonote
bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size()); bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size());
if (!r || !ar.stream().good()) return false; if (!r || !ar.stream().good()) return false;
ar.end_object(); ar.end_object();
if (std::is_same<Archive<W>, binary_archive<W>>())
unprunable_size = getpos(ar) - start_pos;
if (!pruned && rct_signatures.type != rct::RCTTypeNull) if (!pruned && rct_signatures.type != rct::RCTTypeNull)
{ {
ar.tag("rctsig_prunable"); ar.tag("rctsig_prunable");
@ -329,6 +348,8 @@ namespace cryptonote
set_hash_valid(false); set_hash_valid(false);
set_blob_size_valid(false); set_blob_size_valid(false);
pruned = false; pruned = false;
unprunable_size = 0;
prefix_size = 0;
} }
inline inline

View File

@ -210,7 +210,7 @@ namespace cryptonote
return true; return true;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash) bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash)
{ {
std::stringstream ss; std::stringstream ss;
ss << tx_blob; ss << tx_blob;
@ -222,6 +222,13 @@ namespace cryptonote
//TODO: validate tx //TODO: validate tx
get_transaction_hash(tx, tx_hash); get_transaction_hash(tx, tx_hash);
return true;
}
//---------------------------------------------------------------
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
{
if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash))
return false;
get_transaction_prefix_hash(tx, tx_prefix_hash); get_transaction_prefix_hash(tx, tx_prefix_hash);
return true; return true;
} }
@ -878,6 +885,11 @@ namespace cryptonote
return true; return true;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
void get_blob_hash(const epee::span<const char>& blob, crypto::hash& res)
{
cn_fast_hash(blob.data(), blob.size(), res);
}
//---------------------------------------------------------------
void get_blob_hash(const blobdata& blob, crypto::hash& res) void get_blob_hash(const blobdata& blob, crypto::hash& res)
{ {
cn_fast_hash(blob.data(), blob.size(), res); cn_fast_hash(blob.data(), blob.size(), res);
@ -946,6 +958,13 @@ namespace cryptonote
return h; return h;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
crypto::hash get_blob_hash(const epee::span<const char>& blob)
{
crypto::hash h = null_hash;
get_blob_hash(blob, h);
return h;
}
//---------------------------------------------------------------
crypto::hash get_transaction_hash(const transaction& t) crypto::hash get_transaction_hash(const transaction& t)
{ {
crypto::hash h = null_hash; crypto::hash h = null_hash;
@ -958,26 +977,42 @@ namespace cryptonote
return get_transaction_hash(t, res, NULL); return get_transaction_hash(t, res, NULL);
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
bool calculate_transaction_prunable_hash(const transaction& t, crypto::hash& res) bool calculate_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob, crypto::hash& res)
{ {
if (t.version == 1) if (t.version == 1)
return false; return false;
transaction &tt = const_cast<transaction&>(t); static const crypto::hash empty_hash = { (char)0x70, (char)0xa4, (char)0x85, (char)0x5d, (char)0x04, (char)0xd8, (char)0xfa, (char)0x7b, (char)0x3b, (char)0x27, (char)0x82, (char)0xca, (char)0x53, (char)0xb6, (char)0x00, (char)0xe5, (char)0xc0, (char)0x03, (char)0xc7, (char)0xdc, (char)0xb2, (char)0x7d, (char)0x7e, (char)0x92, (char)0x3c, (char)0x23, (char)0xf7, (char)0x86, (char)0x01, (char)0x46, (char)0xd2, (char)0xc5 };
std::stringstream ss; const unsigned int unprunable_size = t.unprunable_size;
binary_archive<true> ba(ss); if (blob && unprunable_size)
const size_t inputs = t.vin.size(); {
const size_t outputs = t.vout.size(); CHECK_AND_ASSERT_MES(unprunable_size <= blob->size(), false, "Inconsistent transaction unprunable and blob sizes");
const size_t mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 : 0; if (blob->size() - unprunable_size == 0)
bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin); res = empty_hash;
CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable"); else
cryptonote::get_blob_hash(ss.str(), res); cryptonote::get_blob_hash(epee::span<const char>(blob->data() + unprunable_size, blob->size() - unprunable_size), res);
}
else
{
transaction &tt = const_cast<transaction&>(t);
std::stringstream ss;
binary_archive<true> ba(ss);
const size_t inputs = t.vin.size();
const size_t outputs = t.vout.size();
const size_t mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 : 0;
bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin);
CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable");
if (ss.str().empty())
res = empty_hash;
else
cryptonote::get_blob_hash(ss.str(), res);
}
return true; return true;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
crypto::hash get_transaction_prunable_hash(const transaction& t) crypto::hash get_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blobdata)
{ {
crypto::hash res; crypto::hash res;
CHECK_AND_ASSERT_THROW_MES(calculate_transaction_prunable_hash(t, res), "Failed to calculate tx prunable hash"); CHECK_AND_ASSERT_THROW_MES(calculate_transaction_prunable_hash(t, blobdata, res), "Failed to calculate tx prunable hash");
return res; return res;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
@ -1030,16 +1065,13 @@ namespace cryptonote
transaction &tt = const_cast<transaction&>(t); transaction &tt = const_cast<transaction&>(t);
const blobdata blob = tx_to_blob(t);
const unsigned int unprunable_size = t.unprunable_size;
const unsigned int prefix_size = t.prefix_size;
// base rct // base rct
{ CHECK_AND_ASSERT_MES(prefix_size <= unprunable_size && unprunable_size <= blob.size(), false, "Inconsistent transaction prefix, unprunable and blob sizes");
std::stringstream ss; cryptonote::get_blob_hash(epee::span<const char>(blob.data() + prefix_size, unprunable_size - prefix_size), hashes[1]);
binary_archive<true> ba(ss);
const size_t inputs = t.vin.size();
const size_t outputs = t.vout.size();
bool r = tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs);
CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures base");
cryptonote::get_blob_hash(ss.str(), hashes[1]);
}
// prunable rct // prunable rct
if (t.rct_signatures.type == rct::RCTTypeNull) if (t.rct_signatures.type == rct::RCTTypeNull)
@ -1048,7 +1080,7 @@ namespace cryptonote
} }
else else
{ {
CHECK_AND_ASSERT_MES(calculate_transaction_prunable_hash(t, hashes[2]), false, "Failed to get tx prunable hash"); CHECK_AND_ASSERT_MES(calculate_transaction_prunable_hash(t, &blob, hashes[2]), false, "Failed to get tx prunable hash");
} }
// the tx hash is the hash of the 3 hashes // the tx hash is the hash of the 3 hashes

View File

@ -51,6 +51,7 @@ namespace cryptonote
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx); crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
bool parse_and_validate_tx_prefix_from_blob(const blobdata& tx_blob, transaction_prefix& tx); bool parse_and_validate_tx_prefix_from_blob(const blobdata& tx_blob, transaction_prefix& tx);
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash);
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash);
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx);
bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx); bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx);
bool is_v1_tx(const blobdata_ref& tx_blob); bool is_v1_tx(const blobdata_ref& tx_blob);
@ -98,15 +99,17 @@ namespace cryptonote
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev);
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev);
void get_blob_hash(const blobdata& blob, crypto::hash& res); void get_blob_hash(const blobdata& blob, crypto::hash& res);
void get_blob_hash(const epee::span<const char>& blob, crypto::hash& res);
crypto::hash get_blob_hash(const blobdata& blob); crypto::hash get_blob_hash(const blobdata& blob);
crypto::hash get_blob_hash(const epee::span<const char>& blob);
std::string short_hash_str(const crypto::hash& h); std::string short_hash_str(const crypto::hash& h);
crypto::hash get_transaction_hash(const transaction& t); crypto::hash get_transaction_hash(const transaction& t);
bool get_transaction_hash(const transaction& t, crypto::hash& res); bool get_transaction_hash(const transaction& t, crypto::hash& res);
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size); bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size);
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size); bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size);
bool calculate_transaction_prunable_hash(const transaction& t, crypto::hash& res); bool calculate_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob, crypto::hash& res);
crypto::hash get_transaction_prunable_hash(const transaction& t); crypto::hash get_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob = NULL);
bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size); bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size);
crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash); crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash);

View File

@ -468,8 +468,8 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
uint64_t num_popped_blocks = 0; uint64_t num_popped_blocks = 0;
while (!m_db->is_read_only()) while (!m_db->is_read_only())
{ {
const uint64_t top_height = m_db->height() - 1; uint64_t top_height;
const crypto::hash top_id = m_db->top_block_hash(); const crypto::hash top_id = m_db->top_block_hash(&top_height);
const block top_block = m_db->get_top_block(); const block top_block = m_db->get_top_block();
const uint8_t ideal_hf_version = get_ideal_hard_fork_version(top_height); 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 (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_timestamps_and_difficulties_height = 0;
m_hardfork->reorganize_from_chain_height(get_current_blockchain_height()); 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) 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(); m_check_txin_table.clear();
CHECK_AND_ASSERT_THROW_MES(update_next_cumulative_weight_limit(), "Error updating next cumulative weight limit"); 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(); invalidate_block_template_cache();
return popped_block; return popped_block;
@ -729,8 +733,7 @@ crypto::hash Blockchain::get_tail_id(uint64_t& height) const
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock); CRITICAL_REGION_LOCAL(m_blockchain_lock);
height = m_db->height() - 1; return m_db->top_block_hash(&height);
return get_tail_id();
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
crypto::hash Blockchain::get_tail_id() const 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); CRITICAL_REGION_LOCAL(m_blockchain_lock);
std::vector<uint64_t> timestamps; std::vector<uint64_t> timestamps;
std::vector<difficulty_type> difficulties; std::vector<difficulty_type> difficulties;
auto height = m_db->height(); uint64_t height;
top_hash = get_tail_id(); // get it again now that we have the lock top_hash = get_tail_id(height); // get it again now that we have the lock
++height; // top block height to blockchain height
// ND: Speedup // ND: Speedup
// 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty, // 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 // 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); uint64_t num_outs = m_db->get_num_outputs(amount);
// ensure we don't include outputs that aren't yet eligible to be used // ensure we don't include outputs that aren't yet eligible to be used
// outpouts are sorted by height // outpouts are sorted by height
const uint64_t blockchain_height = m_db->height();
while (num_outs > 0) while (num_outs > 0)
{ {
const tx_out_index toi = m_db->get_output_tx_and_index(amount, num_outs - 1); 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); 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; break;
--num_outs; --num_outs;
} }
@ -3325,14 +3330,15 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons
return false; return false;
} }
const auto h = m_db->height();
// if not enough blocks, no proper median yet, return true // 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; return true;
} }
std::vector<uint64_t> timestamps; std::vector<uint64_t> timestamps;
auto h = m_db->height();
// need most recent 60 blocks, get index of first of those // need most recent 60 blocks, get index of first of those
size_t offset = h - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW; 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); 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(); uint8_t version = get_current_hard_fork_version();
for (auto& tx : txs) 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 // that might not be always true. Unlikely though, and always relaying
// these again might cause a spike of traffic as many nodes re-relay // these again might cause a spike of traffic as many nodes re-relay
// all the transactions in a popped block when a reorg happens. // 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) for (const auto &txid: txids)
{ {
cryptonote::transaction tx; cryptonote::transaction tx;
cryptonote::blobdata txblob;
size_t tx_weight; size_t tx_weight;
uint64_t fee; uint64_t fee;
bool relayed, do_not_relay, double_spend_seen; bool relayed, do_not_relay, double_spend_seen;
MINFO("Removing txid " << txid << " from the pool"); 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, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen))
{ {
MERROR("Failed to remove txid " << txid << " from the pool"); MERROR("Failed to remove txid " << txid << " from the pool");
res = false; 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; static bool seen_future_version = false;
m_db->block_txn_start(true); 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; bvc.m_verifivation_failed = true;
leave: leave:
m_db->block_txn_stop(); m_db->block_txn_stop();
@ -3469,13 +3481,12 @@ leave:
bool precomputed = false; bool precomputed = false;
bool fast_check = false; bool fast_check = false;
#if defined(PER_BLOCK_CHECKPOINT) #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[blockchain_height];
const auto &expected_hash = m_blocks_hash_check[m_db->height()];
if (expected_hash != crypto::null_hash) 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); MERROR_VER("Block with id is INVALID: " << id << ", expected " << expected_hash);
bvc.m_verifivation_failed = true; bvc.m_verifivation_failed = true;
@ -3485,7 +3496,7 @@ leave:
} }
else 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 else
@ -3498,7 +3509,7 @@ leave:
proof_of_work = it->second; proof_of_work = it->second;
} }
else 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 // validate proof_of_work versus difficulty target
if(!check_hash(proof_of_work, current_diffic)) 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 // If we're at a checkpoint, ensure that our hardcoded checkpoint hash
// is correct. // 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"); LOG_ERROR("CHECKPOINT VALIDATION FAILED");
bvc.m_verifivation_failed = true; bvc.m_verifivation_failed = true;
@ -3528,7 +3539,7 @@ leave:
TIME_MEASURE_START(t3); TIME_MEASURE_START(t3);
// sanity check basic miner tx properties; // 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"); MERROR_VER("Block with id: " << id << " failed to pass prevalidation");
bvc.m_verifivation_failed = true; bvc.m_verifivation_failed = true;
@ -3538,7 +3549,7 @@ leave:
size_t coinbase_weight = get_transaction_weight(bl.miner_tx); size_t coinbase_weight = get_transaction_weight(bl.miner_tx);
size_t cumulative_block_weight = coinbase_weight; size_t cumulative_block_weight = coinbase_weight;
std::vector<transaction> txs; std::vector<std::pair<transaction, blobdata>> txs;
key_images_container keys; key_images_container keys;
uint64_t fee_summary = 0; uint64_t fee_summary = 0;
@ -3557,7 +3568,8 @@ leave:
txs.reserve(bl.tx_hashes.size()); txs.reserve(bl.tx_hashes.size());
for (const crypto::hash& tx_id : bl.tx_hashes) for (const crypto::hash& tx_id : bl.tx_hashes)
{ {
transaction tx; transaction tx_tmp;
blobdata txblob;
size_t tx_weight = 0; size_t tx_weight = 0;
uint64_t fee = 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;
@ -3577,7 +3589,7 @@ leave:
TIME_MEASURE_START(bb); TIME_MEASURE_START(bb);
// get transaction with hash <tx_id> from tx_pool // 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); MERROR_VER("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id);
bvc.m_verifivation_failed = true; bvc.m_verifivation_failed = true;
@ -3590,7 +3602,8 @@ leave:
// add the transaction to the temp list of transactions, so we can either // 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 // 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. // 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); TIME_MEASURE_START(dd);
// FIXME: the storage should not be responsible for validation. // FIXME: the storage should not be responsible for validation.
@ -3655,7 +3668,7 @@ leave:
TIME_MEASURE_START(vmt); TIME_MEASURE_START(vmt);
uint64_t base_reward = 0; 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())) 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"); 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 // 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. // 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; already_generated_coins = base_reward < (MONEY_SUPPLY-already_generated_coins) ? already_generated_coins + base_reward : MONEY_SUPPLY;
if(m_db->height()) if(blockchain_height)
cumulative_difficulty += m_db->get_block_cumulative_difficulty(m_db->height() - 1); cumulative_difficulty += m_db->get_block_cumulative_difficulty(blockchain_height - 1);
TIME_MEASURE_FINISH(block_processing_time); TIME_MEASURE_FINISH(block_processing_time);
if(precomputed) if(precomputed)
@ -3691,7 +3704,8 @@ leave:
try try
{ {
uint64_t long_term_block_weight = get_next_long_term_block_weight(block_weight); 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) catch (const KEY_IMAGE_EXISTS& e)
{ {
@ -3875,11 +3889,9 @@ bool Blockchain::update_next_cumulative_weight_limit(uint64_t *long_term_effecti
return true; 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__); LOG_PRINT_L3("Blockchain::" << __func__);
//copy block here to let modify block.target
block bl = bl_;
crypto::hash id = get_block_hash(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_LOCAL(m_tx_pool);//to avoid deadlock lets lock tx_pool for whole add/reorganize process
CRITICAL_REGION_LOCAL1(m_blockchain_lock); 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); CRITICAL_REGION_LOCAL(m_blockchain_lock);
stop_batch = m_db->batch_start(); stop_batch = m_db->batch_start();
const uint64_t blockchain_height = m_db->height();
for (const auto& pt : pts) for (const auto& pt : pts)
{ {
// if the checkpoint is for a block we don't have yet, move on // 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; 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 // 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 // and is threaded if possible. The table (m_scan_table) will be used later when querying output
// keys. // 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__); MTRACE("Blockchain::" << __func__);
TIME_MEASURE_START(prepare); TIME_MEASURE_START(prepare);
bool stop_batch; bool stop_batch;
uint64_t bytes = 0; uint64_t bytes = 0;
size_t total_txs = 0; size_t total_txs = 0;
blocks.clear();
// Order of locking must be: // Order of locking must be:
// m_incoming_tx_lock (optional) // m_incoming_tx_lock (optional)
@ -4249,7 +4263,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
bool blocks_exist = false; bool blocks_exist = false;
tools::threadpool& tpool = tools::threadpool::getInstance(); tools::threadpool& tpool = tools::threadpool::getInstance();
unsigned threads = tpool.get_max_concurrency(); unsigned threads = tpool.get_max_concurrency();
std::vector<block> blocks;
blocks.resize(blocks_entry.size()); blocks.resize(blocks_entry.size());
if (1) if (1)
@ -4265,6 +4278,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
auto it = blocks_entry.begin(); auto it = blocks_entry.begin();
unsigned blockidx = 0; unsigned blockidx = 0;
const crypto::hash tophash = m_db->top_block_hash();
for (unsigned i = 0; i < threads; i++) for (unsigned i = 0; i < threads; i++)
{ {
for (unsigned int j = 0; j < batches; j++, ++blockidx) 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 // check first block and skip all blocks if its not chained properly
if (blockidx == 0) if (blockidx == 0)
{ {
crypto::hash tophash = m_db->top_block_hash();
if (block.prev_id != tophash) if (block.prev_id != tophash)
{ {
MDEBUG("Skipping prepare blocks. New blocks don't belong to chain."); MDEBUG("Skipping prepare blocks. New blocks don't belong to chain.");
blocks.clear();
return true; return true;
} }
} }
if (have_block(get_block_hash(block))) if (have_block(get_block_hash(block)))
{
blocks_exist = true; blocks_exist = true;
break;
}
std::advance(it, 1); std::advance(it, 1);
} }
@ -4302,10 +4313,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
return false; return false;
if (have_block(get_block_hash(block))) if (have_block(get_block_hash(block)))
{
blocks_exist = true; blocks_exist = true;
break;
}
std::advance(it, 1); std::advance(it, 1);
} }
@ -4341,7 +4349,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
if (blocks_exist) if (blocks_exist)
{ {
MDEBUG("Skipping prepare blocks. Blocks exist."); MDEBUG("Skipping remainder of prepare blocks. Blocks exist.");
return true; return true;
} }
@ -4770,10 +4778,11 @@ void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get
uint64_t fee; uint64_t fee;
bool relayed, do_not_relay, double_spend_seen; bool relayed, do_not_relay, double_spend_seen;
transaction pool_tx; transaction pool_tx;
blobdata txblob;
for(const transaction &tx : txs) for(const transaction &tx : txs)
{ {
crypto::hash tx_hash = get_transaction_hash(tx); 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, txblob, tx_weight, fee, relayed, do_not_relay, double_spend_seen);
} }
} }
} }

View File

@ -230,11 +230,12 @@ namespace cryptonote
/** /**
* @brief performs some preprocessing on a group of incoming blocks to speed up verification * @brief performs some preprocessing on a group of incoming blocks to speed up verification
* *
* @param blocks a list of incoming blocks * @param blocks_entry a list of incoming blocks
* @param blocks the parsed blocks
* *
* @return false on erroneous blocks, else true * @return false on erroneous blocks, else true
*/ */
bool prepare_handle_incoming_blocks(const std::vector<block_complete_entry> &blocks); bool prepare_handle_incoming_blocks(const std::vector<block_complete_entry> &blocks_entry, std::vector<block> &blocks);
/** /**
* @brief incoming blocks post-processing, cleanup, and disk sync * @brief incoming blocks post-processing, cleanup, and disk sync
@ -1396,7 +1397,7 @@ namespace cryptonote
* @return true * @return true
*/ */
bool update_next_cumulative_weight_limit(uint64_t *long_term_effective_median_block_weight = NULL); bool update_next_cumulative_weight_limit(uint64_t *long_term_effective_median_block_weight = NULL);
void return_tx_to_pool(std::vector<transaction> &txs); void return_tx_to_pool(std::vector<std::pair<transaction, blobdata>> &txs);
/** /**
* @brief make sure a transaction isn't attempting a double-spend * @brief make sure a transaction isn't attempting a double-spend

View File

@ -724,7 +724,7 @@ namespace cryptonote
return false; return false;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::handle_incoming_tx_pre(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, crypto::hash &tx_prefixt_hash, bool keeped_by_block, bool relayed, bool do_not_relay) bool core::handle_incoming_tx_pre(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay)
{ {
tvc = boost::value_initialized<tx_verification_context>(); tvc = boost::value_initialized<tx_verification_context>();
@ -737,9 +737,8 @@ namespace cryptonote
} }
tx_hash = crypto::null_hash; tx_hash = crypto::null_hash;
tx_prefixt_hash = crypto::null_hash;
if(!parse_tx_from_blob(tx, tx_hash, tx_prefixt_hash, tx_blob)) if(!parse_tx_from_blob(tx, tx_hash, tx_blob))
{ {
LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to parse, rejected"); LOG_PRINT_L1("WRONG TRANSACTION BLOB, Failed to parse, rejected");
tvc.m_verifivation_failed = true; tvc.m_verifivation_failed = true;
@ -772,7 +771,7 @@ namespace cryptonote
return true; return true;
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::handle_incoming_tx_post(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, crypto::hash &tx_prefixt_hash, bool keeped_by_block, bool relayed, bool do_not_relay) bool core::handle_incoming_tx_post(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay)
{ {
if(!check_tx_syntax(tx)) if(!check_tx_syntax(tx))
{ {
@ -906,7 +905,7 @@ namespace cryptonote
TRY_ENTRY(); TRY_ENTRY();
CRITICAL_REGION_LOCAL(m_incoming_tx_lock); CRITICAL_REGION_LOCAL(m_incoming_tx_lock);
struct result { bool res; cryptonote::transaction tx; crypto::hash hash; crypto::hash prefix_hash; }; struct result { bool res; cryptonote::transaction tx; crypto::hash hash; };
std::vector<result> results(tx_blobs.size()); std::vector<result> results(tx_blobs.size());
tvc.resize(tx_blobs.size()); tvc.resize(tx_blobs.size());
@ -917,7 +916,7 @@ namespace cryptonote
tpool.submit(&waiter, [&, i, it] { tpool.submit(&waiter, [&, i, it] {
try try
{ {
results[i].res = handle_incoming_tx_pre(*it, tvc[i], results[i].tx, results[i].hash, results[i].prefix_hash, keeped_by_block, relayed, do_not_relay); results[i].res = handle_incoming_tx_pre(*it, tvc[i], results[i].tx, results[i].hash, keeped_by_block, relayed, do_not_relay);
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
@ -947,7 +946,7 @@ namespace cryptonote
tpool.submit(&waiter, [&, i, it] { tpool.submit(&waiter, [&, i, it] {
try try
{ {
results[i].res = handle_incoming_tx_post(*it, tvc[i], results[i].tx, results[i].hash, results[i].prefix_hash, keeped_by_block, relayed, do_not_relay); results[i].res = handle_incoming_tx_post(*it, tvc[i], results[i].tx, results[i].hash, keeped_by_block, relayed, do_not_relay);
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
@ -983,7 +982,7 @@ namespace cryptonote
continue; continue;
const size_t weight = get_transaction_weight(results[i].tx, it->size()); const size_t weight = get_transaction_weight(results[i].tx, it->size());
ok &= add_new_tx(results[i].tx, results[i].hash, tx_blobs[i], results[i].prefix_hash, weight, tvc[i], keeped_by_block, relayed, do_not_relay); ok &= add_new_tx(results[i].tx, results[i].hash, tx_blobs[i], weight, tvc[i], keeped_by_block, relayed, do_not_relay);
if(tvc[i].m_verifivation_failed) if(tvc[i].m_verifivation_failed)
{MERROR_VER("Transaction verification failed: " << results[i].hash);} {MERROR_VER("Transaction verification failed: " << results[i].hash);}
else if(tvc[i].m_verifivation_impossible) else if(tvc[i].m_verifivation_impossible)
@ -1197,11 +1196,10 @@ namespace cryptonote
bool core::add_new_tx(transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) bool core::add_new_tx(transaction& tx, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
{ {
crypto::hash tx_hash = get_transaction_hash(tx); crypto::hash tx_hash = get_transaction_hash(tx);
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
blobdata bl; blobdata bl;
t_serializable_object_to_blob(tx, bl); t_serializable_object_to_blob(tx, bl);
size_t tx_weight = get_transaction_weight(tx, bl.size()); size_t tx_weight = get_transaction_weight(tx, bl.size());
return add_new_tx(tx, tx_hash, bl, tx_prefix_hash, tx_weight, tvc, keeped_by_block, relayed, do_not_relay); return add_new_tx(tx, tx_hash, bl, tx_weight, tvc, keeped_by_block, relayed, do_not_relay);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
size_t core::get_blockchain_total_transactions() const size_t core::get_blockchain_total_transactions() const
@ -1209,7 +1207,7 @@ namespace cryptonote
return m_blockchain_storage.get_total_transactions(); return m_blockchain_storage.get_total_transactions();
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::add_new_tx(transaction& tx, const crypto::hash& tx_hash, const cryptonote::blobdata &blob, const crypto::hash& tx_prefix_hash, size_t tx_weight, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) bool core::add_new_tx(transaction& tx, const crypto::hash& tx_hash, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
{ {
if(m_mempool.have_tx(tx_hash)) if(m_mempool.have_tx(tx_hash))
{ {
@ -1250,8 +1248,8 @@ namespace cryptonote
{ {
std::vector<std::pair<crypto::hash, cryptonote::blobdata>> txs; std::vector<std::pair<crypto::hash, cryptonote::blobdata>> txs;
cryptonote::transaction tx; cryptonote::transaction tx;
crypto::hash tx_hash, tx_prefix_hash; crypto::hash tx_hash;
if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash, tx_prefix_hash)) if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash))
{ {
LOG_ERROR("Failed to parse relayed transaction"); LOG_ERROR("Failed to parse relayed transaction");
return; return;
@ -1332,7 +1330,13 @@ namespace cryptonote
m_miner.resume(); m_miner.resume();
return false; return false;
} }
prepare_handle_incoming_blocks(blocks); std::vector<block> pblocks;
if (!prepare_handle_incoming_blocks(blocks, pblocks))
{
MERROR("Block found, but failed to prepare to add");
m_miner.resume();
return false;
}
m_blockchain_storage.add_new_block(b, bvc); m_blockchain_storage.add_new_block(b, bvc);
cleanup_handle_incoming_blocks(true); cleanup_handle_incoming_blocks(true);
//anyway - update miner template //anyway - update miner template
@ -1383,10 +1387,14 @@ namespace cryptonote
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::prepare_handle_incoming_blocks(const std::vector<block_complete_entry> &blocks) bool core::prepare_handle_incoming_blocks(const std::vector<block_complete_entry> &blocks_entry, std::vector<block> &blocks)
{ {
m_incoming_tx_lock.lock(); m_incoming_tx_lock.lock();
m_blockchain_storage.prepare_handle_incoming_blocks(blocks); if (!m_blockchain_storage.prepare_handle_incoming_blocks(blocks_entry, blocks))
{
cleanup_handle_incoming_blocks(false);
return false;
}
return true; return true;
} }
@ -1403,7 +1411,7 @@ namespace cryptonote
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate) bool core::handle_incoming_block(const blobdata& block_blob, const block *b, block_verification_context& bvc, bool update_miner_blocktemplate)
{ {
TRY_ENTRY(); TRY_ENTRY();
@ -1419,14 +1427,18 @@ namespace cryptonote
return false; return false;
} }
block b = AUTO_VAL_INIT(b); block lb;
if(!parse_and_validate_block_from_blob(block_blob, b)) if (!b)
{ {
LOG_PRINT_L1("Failed to parse and validate new block"); if(!parse_and_validate_block_from_blob(block_blob, lb))
bvc.m_verifivation_failed = true; {
return false; LOG_PRINT_L1("Failed to parse and validate new block");
bvc.m_verifivation_failed = true;
return false;
}
b = &lb;
} }
add_new_block(b, bvc); add_new_block(*b, bvc);
if(update_miner_blocktemplate && bvc.m_added_to_main_chain) if(update_miner_blocktemplate && bvc.m_added_to_main_chain)
update_miner_block_template(); update_miner_block_template();
return true; return true;
@ -1466,9 +1478,9 @@ namespace cryptonote
return m_blockchain_storage.have_block(id); return m_blockchain_storage.have_block(id);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob) const bool core::parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, const blobdata& blob) const
{ {
return parse_and_validate_tx_from_blob(blob, tx, tx_hash, tx_prefix_hash); return parse_and_validate_tx_from_blob(blob, tx, tx_hash);
} }
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
bool core::check_tx_syntax(const transaction& tx) const bool core::check_tx_syntax(const transaction& tx) const

View File

@ -146,20 +146,21 @@ namespace cryptonote
* optionally updates the miner's block template. * optionally updates the miner's block template.
* *
* @param block_blob the block to be added * @param block_blob the block to be added
* @param block the block to be added, or NULL
* @param bvc return-by-reference metadata context about the block's validity * @param bvc return-by-reference metadata context about the block's validity
* @param update_miner_blocktemplate whether or not to update the miner's block template * @param update_miner_blocktemplate whether or not to update the miner's block template
* *
* @return false if loading new checkpoints fails, or the block is not * @return false if loading new checkpoints fails, or the block is not
* added, otherwise true * added, otherwise true
*/ */
bool handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate = true); bool handle_incoming_block(const blobdata& block_blob, const block *b, block_verification_context& bvc, bool update_miner_blocktemplate = true);
/** /**
* @copydoc Blockchain::prepare_handle_incoming_blocks * @copydoc Blockchain::prepare_handle_incoming_blocks
* *
* @note see Blockchain::prepare_handle_incoming_blocks * @note see Blockchain::prepare_handle_incoming_blocks
*/ */
bool prepare_handle_incoming_blocks(const std::vector<block_complete_entry> &blocks); bool prepare_handle_incoming_blocks(const std::vector<block_complete_entry> &blocks_entry, std::vector<block> &blocks);
/** /**
* @copydoc Blockchain::cleanup_handle_incoming_blocks * @copydoc Blockchain::cleanup_handle_incoming_blocks
@ -829,13 +830,12 @@ namespace cryptonote
* *
* @param tx_hash the transaction's hash * @param tx_hash the transaction's hash
* @param blob the transaction as a blob * @param blob the transaction as a blob
* @param tx_prefix_hash the transaction prefix' hash
* @param tx_weight the weight of the transaction * @param tx_weight the weight of the transaction
* @param relayed whether or not the transaction was relayed to us * @param relayed whether or not the transaction was relayed to us
* @param do_not_relay whether to prevent the transaction from being relayed * @param do_not_relay whether to prevent the transaction from being relayed
* *
*/ */
bool add_new_tx(transaction& tx, const crypto::hash& tx_hash, const cryptonote::blobdata &blob, const crypto::hash& tx_prefix_hash, size_t tx_weight, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay); bool add_new_tx(transaction& tx, const crypto::hash& tx_hash, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
/** /**
* @brief add a new transaction to the transaction pool * @brief add a new transaction to the transaction pool
@ -875,7 +875,7 @@ namespace cryptonote
* *
* @note see parse_tx_from_blob(transaction&, crypto::hash&, crypto::hash&, const blobdata&) const * @note see parse_tx_from_blob(transaction&, crypto::hash&, crypto::hash&, const blobdata&) const
*/ */
bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash, const blobdata& blob) const; bool parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, const blobdata& blob) const;
/** /**
* @brief check a transaction's syntax * @brief check a transaction's syntax
@ -908,8 +908,8 @@ namespace cryptonote
bool check_tx_semantic(const transaction& tx, bool keeped_by_block) const; bool check_tx_semantic(const transaction& tx, bool keeped_by_block) const;
void set_semantics_failed(const crypto::hash &tx_hash); void set_semantics_failed(const crypto::hash &tx_hash);
bool handle_incoming_tx_pre(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, crypto::hash &tx_prefixt_hash, bool keeped_by_block, bool relayed, bool do_not_relay); bool handle_incoming_tx_pre(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay);
bool handle_incoming_tx_post(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, crypto::hash &tx_prefixt_hash, bool keeped_by_block, bool relayed, bool do_not_relay); bool handle_incoming_tx_post(const blobdata& tx_blob, tx_verification_context& tvc, cryptonote::transaction &tx, crypto::hash &tx_hash, bool keeped_by_block, bool relayed, bool do_not_relay);
struct tx_verification_batch_info { const cryptonote::transaction *tx; crypto::hash tx_hash; tx_verification_context &tvc; bool &result; }; struct tx_verification_batch_info { const cryptonote::transaction *tx; crypto::hash tx_hash; tx_verification_context &tvc; bool &result; };
bool handle_incoming_tx_accumulated_batch(std::vector<tx_verification_batch_info> &tx_info, bool keeped_by_block); bool handle_incoming_tx_accumulated_batch(std::vector<tx_verification_batch_info> &tx_info, bool keeped_by_block);

View File

@ -453,7 +453,7 @@ namespace cryptonote
return true; return true;
} }
//--------------------------------------------------------------------------------- //---------------------------------------------------------------------------------
bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& tx_weight, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen) bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, cryptonote::blobdata &txblob, size_t& tx_weight, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen)
{ {
CRITICAL_REGION_LOCAL(m_transactions_lock); CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain); CRITICAL_REGION_LOCAL1(m_blockchain);
@ -469,7 +469,7 @@ namespace cryptonote
MERROR("Failed to find tx in txpool"); MERROR("Failed to find tx in txpool");
return false; return false;
} }
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(id); txblob = m_blockchain.get_txpool_tx_blob(id);
auto ci = m_parsed_tx_cache.find(id); auto ci = m_parsed_tx_cache.find(id);
if (ci != m_parsed_tx_cache.end()) if (ci != m_parsed_tx_cache.end())
{ {

View File

@ -133,6 +133,7 @@ namespace cryptonote
* *
* @param id the hash of the transaction * @param id the hash of the transaction
* @param tx return-by-reference the transaction taken * @param tx return-by-reference the transaction taken
* @param txblob return-by-reference the transaction as a blob
* @param tx_weight return-by-reference the transaction's weight * @param tx_weight return-by-reference the transaction's weight
* @param fee the transaction fee * @param fee the transaction fee
* @param relayed return-by-reference was transaction relayed to us by the network? * @param relayed return-by-reference was transaction relayed to us by the network?
@ -141,7 +142,7 @@ namespace cryptonote
* *
* @return true unless the transaction cannot be found in the pool * @return true unless the transaction cannot be found in the pool
*/ */
bool take_tx(const crypto::hash &id, transaction &tx, size_t& tx_weight, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen); bool take_tx(const crypto::hash &id, transaction &tx, cryptonote::blobdata &txblob, size_t& tx_weight, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen);
/** /**
* @brief checks if the pool has a transaction with the given hash * @brief checks if the pool has a transaction with the given hash

View File

@ -418,7 +418,14 @@ namespace cryptonote
m_core.pause_mine(); m_core.pause_mine();
std::vector<block_complete_entry> blocks; std::vector<block_complete_entry> blocks;
blocks.push_back(arg.b); blocks.push_back(arg.b);
m_core.prepare_handle_incoming_blocks(blocks); std::vector<block> pblocks;
if (!m_core.prepare_handle_incoming_blocks(blocks, pblocks))
{
LOG_PRINT_CCONTEXT_L1("Block verification failed: prepare_handle_incoming_blocks failed, dropping connection");
drop_connection(context, false, false);
m_core.resume_mine();
return 1;
}
for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++) for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++)
{ {
cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc); cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc);
@ -434,7 +441,7 @@ namespace cryptonote
} }
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block m_core.handle_incoming_block(arg.b.block, pblocks.empty() ? NULL : &pblocks[0], bvc); // got block from handle_notify_new_block
if (!m_core.cleanup_handle_incoming_blocks(true)) if (!m_core.cleanup_handle_incoming_blocks(true))
{ {
LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks"); LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
@ -697,10 +704,16 @@ namespace cryptonote
std::vector<block_complete_entry> blocks; std::vector<block_complete_entry> blocks;
blocks.push_back(b); blocks.push_back(b);
m_core.prepare_handle_incoming_blocks(blocks); std::vector<block> pblocks;
if (!m_core.prepare_handle_incoming_blocks(blocks, pblocks))
{
LOG_PRINT_CCONTEXT_L0("Failure in prepare_handle_incoming_blocks");
m_core.resume_mine();
return 1;
}
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block m_core.handle_incoming_block(arg.b.block, pblocks.empty() ? NULL : &pblocks[0], bvc); // got block from handle_notify_new_block
if (!m_core.cleanup_handle_incoming_blocks(true)) if (!m_core.cleanup_handle_incoming_blocks(true))
{ {
LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks"); LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
@ -1174,10 +1187,21 @@ namespace cryptonote
} }
} }
m_core.prepare_handle_incoming_blocks(blocks); std::vector<block> pblocks;
if (!m_core.prepare_handle_incoming_blocks(blocks, pblocks))
{
LOG_ERROR_CCONTEXT("Failure in prepare_handle_incoming_blocks");
return 1;
}
if (!pblocks.empty() && pblocks.size() != blocks.size())
{
m_core.cleanup_handle_incoming_blocks();
LOG_ERROR_CCONTEXT("Internal error: blocks.size() != block_entry.txs.size()");
return 1;
}
uint64_t block_process_time_full = 0, transactions_process_time_full = 0; uint64_t block_process_time_full = 0, transactions_process_time_full = 0;
size_t num_txs = 0; size_t num_txs = 0, blockidx = 0;
for(const block_complete_entry& block_entry: blocks) for(const block_complete_entry& block_entry: blocks)
{ {
if (m_stopping) if (m_stopping)
@ -1229,7 +1253,7 @@ namespace cryptonote
TIME_MEASURE_START(block_process_time); TIME_MEASURE_START(block_process_time);
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
m_core.handle_incoming_block(block_entry.block, bvc, false); // <--- process block m_core.handle_incoming_block(block_entry.block, pblocks.empty() ? NULL : &pblocks[blockidx], bvc, false); // <--- process block
if(bvc.m_verifivation_failed) if(bvc.m_verifivation_failed)
{ {
@ -1272,6 +1296,7 @@ namespace cryptonote
TIME_MEASURE_FINISH(block_process_time); TIME_MEASURE_FINISH(block_process_time);
block_process_time_full += block_process_time; block_process_time_full += block_process_time;
++blockidx;
} // each download block } // each download block

View File

@ -10175,11 +10175,11 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
else else
{ {
cryptonote::blobdata tx_data; cryptonote::blobdata tx_data;
crypto::hash tx_prefix_hash;
ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data); ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon"); THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash, tx_prefix_hash), THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx),
error::wallet_internal_error, "Failed to validate transaction from daemon"); error::wallet_internal_error, "Failed to validate transaction from daemon");
tx_hash = cryptonote::get_transaction_hash(tx);
} }
THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error,
@ -10321,11 +10321,11 @@ std::string wallet2::get_tx_proof(const crypto::hash &txid, const cryptonote::ac
else else
{ {
cryptonote::blobdata tx_data; cryptonote::blobdata tx_data;
crypto::hash tx_prefix_hash;
ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data); ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon"); THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash, tx_prefix_hash), THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx),
error::wallet_internal_error, "Failed to validate transaction from daemon"); error::wallet_internal_error, "Failed to validate transaction from daemon");
tx_hash = cryptonote::get_transaction_hash(tx);
} }
THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon"); THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
@ -10439,11 +10439,11 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account
else else
{ {
cryptonote::blobdata tx_data; cryptonote::blobdata tx_data;
crypto::hash tx_prefix_hash;
ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data); ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon"); THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash, tx_prefix_hash), THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx),
error::wallet_internal_error, "Failed to validate transaction from daemon"); error::wallet_internal_error, "Failed to validate transaction from daemon");
tx_hash = cryptonote::get_transaction_hash(tx);
} }
THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon"); THROW_WALLET_EXCEPTION_IF(tx_hash != txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");

View File

@ -1684,23 +1684,14 @@ namespace tools
cryptonote::blobdata payment_id_blob; cryptonote::blobdata payment_id_blob;
// TODO - should the whole thing fail because of one bad id? // TODO - should the whole thing fail because of one bad id?
bool r;
if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_blob)) if (payment_id_str.size() == 2 * sizeof(payment_id))
{ {
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; r = epee::string_tools::hex_to_pod(payment_id_str, payment_id);
er.message = "Payment ID has invalid format: " + payment_id_str;
return false;
} }
else if (payment_id_str.size() == 2 * sizeof(payment_id8))
if(sizeof(payment_id) == payment_id_blob.size())
{ {
payment_id = *reinterpret_cast<const crypto::hash*>(payment_id_blob.data()); r = epee::string_tools::hex_to_pod(payment_id_str, payment_id8);
}
else if(sizeof(payment_id8) == payment_id_blob.size())
{
payment_id8 = *reinterpret_cast<const crypto::hash8*>(payment_id_blob.data());
memcpy(payment_id.data, payment_id8.data, 8);
memset(payment_id.data + 8, 0, 24);
} }
else else
{ {
@ -1709,6 +1700,13 @@ namespace tools
return false; return false;
} }
if(!r)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID;
er.message = "Payment ID has invalid format: " + payment_id_str;
return false;
}
std::list<wallet2::payment_details> payment_list; std::list<wallet2::payment_details> payment_list;
m_wallet->get_payments(payment_id, payment_list, req.min_block_height); m_wallet->get_payments(payment_id, payment_list, req.min_block_height);
@ -2588,23 +2586,19 @@ namespace tools
ski.resize(req.signed_key_images.size()); ski.resize(req.signed_key_images.size());
for (size_t n = 0; n < ski.size(); ++n) for (size_t n = 0; n < ski.size(); ++n)
{ {
cryptonote::blobdata bd; if (!epee::string_tools::hex_to_pod(req.signed_key_images[n].key_image, ski[n].first))
if(!epee::string_tools::parse_hexstr_to_binbuff(req.signed_key_images[n].key_image, bd) || bd.size() != sizeof(crypto::key_image))
{ {
er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE; er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE;
er.message = "failed to parse key image"; er.message = "failed to parse key image";
return false; return false;
} }
ski[n].first = *reinterpret_cast<const crypto::key_image*>(bd.data());
if(!epee::string_tools::parse_hexstr_to_binbuff(req.signed_key_images[n].signature, bd) || bd.size() != sizeof(crypto::signature)) if (!epee::string_tools::hex_to_pod(req.signed_key_images[n].signature, ski[n].second))
{ {
er.code = WALLET_RPC_ERROR_CODE_WRONG_SIGNATURE; er.code = WALLET_RPC_ERROR_CODE_WRONG_SIGNATURE;
er.message = "failed to parse signature"; er.message = "failed to parse signature";
return false; return false;
} }
ski[n].second = *reinterpret_cast<const crypto::signature*>(bd.data());
} }
uint64_t spent = 0, unspent = 0; uint64_t spent = 0, unspent = 0;
uint64_t height = m_wallet->import_key_images(ski, req.offset, spent, unspent); uint64_t height = m_wallet->import_key_images(ski, req.offset, spent, unspent);

View File

@ -72,11 +72,13 @@ public:
virtual uint64_t height() const override { return blocks.size(); } virtual uint64_t height() const override { return blocks.size(); }
virtual size_t get_block_weight(const uint64_t &h) const override { return blocks[h].weight; } virtual size_t get_block_weight(const uint64_t &h) const override { return blocks[h].weight; }
virtual uint64_t get_block_long_term_weight(const uint64_t &h) const override { return blocks[h].long_term_weight; } virtual uint64_t get_block_long_term_weight(const uint64_t &h) const override { return blocks[h].long_term_weight; }
virtual crypto::hash top_block_hash() const override { virtual crypto::hash top_block_hash(uint64_t *block_height = NULL) const override {
uint64_t h = height(); uint64_t h = height();
crypto::hash top = crypto::null_hash; crypto::hash top = crypto::null_hash;
if (h) if (h)
*(uint64_t*)&top = h - 1; *(uint64_t*)&top = h - 1;
if (block_height)
*block_height = h - 1;
return top; return top;
} }
virtual void pop_block(cryptonote::block &blk, std::vector<cryptonote::transaction> &txs) override { blocks.pop_back(); } virtual void pop_block(cryptonote::block &blk, std::vector<cryptonote::transaction> &txs) override { blocks.pop_back(); }
@ -129,7 +131,7 @@ static void test(test_t t, uint64_t blocks)
cryptonote::block b; cryptonote::block b;
b.major_version = 1; b.major_version = 1;
b.minor_version = 1; b.minor_version = 1;
bc->get_db().add_block(b, 300000, 300000, bc->get_db().height(), bc->get_db().height(), {}); bc->get_db().add_block(std::make_pair(b, ""), 300000, 300000, bc->get_db().height(), bc->get_db().height(), {});
if (!bc->update_next_cumulative_weight_limit()) if (!bc->update_next_cumulative_weight_limit())
{ {
fprintf(stderr, "Failed to update cumulative weight limit 1\n"); fprintf(stderr, "Failed to update cumulative weight limit 1\n");
@ -163,7 +165,7 @@ static void test(test_t t, uint64_t blocks)
cryptonote::block b; cryptonote::block b;
b.major_version = 10; b.major_version = 10;
b.minor_version = 10; b.minor_version = 10;
bc->get_db().add_block(std::move(b), w, ltw, bc->get_db().height(), bc->get_db().height(), {}); bc->get_db().add_block(std::make_pair(std::move(b), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {});
if (!bc->update_next_cumulative_weight_limit()) if (!bc->update_next_cumulative_weight_limit())
{ {

View File

@ -197,7 +197,7 @@ bool tests::proxy_core::handle_incoming_txs(const std::vector<blobdata>& tx_blob
return true; return true;
} }
bool tests::proxy_core::handle_incoming_block(const cryptonote::blobdata& block_blob, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate) { bool tests::proxy_core::handle_incoming_block(const cryptonote::blobdata& block_blob, const cryptonote::block *block_, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate) {
block b = AUTO_VAL_INIT(b); block b = AUTO_VAL_INIT(b);
if(!parse_and_validate_block_from_blob(block_blob, b)) { if(!parse_and_validate_block_from_blob(block_blob, b)) {

View File

@ -77,7 +77,7 @@ namespace tests
void get_blockchain_top(uint64_t& height, crypto::hash& top_id); void get_blockchain_top(uint64_t& height, crypto::hash& top_id);
bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay); bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
bool handle_incoming_txs(const std::vector<cryptonote::blobdata>& tx_blobs, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay); bool handle_incoming_txs(const std::vector<cryptonote::blobdata>& tx_blobs, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay);
bool handle_incoming_block(const cryptonote::blobdata& block_blob, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true); bool handle_incoming_block(const cryptonote::blobdata& block_blob, const cryptonote::block *block, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true);
void pause_mine(){} void pause_mine(){}
void resume_mine(){} void resume_mine(){}
bool on_idle(){return true;} bool on_idle(){return true;}
@ -86,7 +86,7 @@ namespace tests
cryptonote::Blockchain &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } cryptonote::Blockchain &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); }
bool get_test_drop_download() {return true;} bool get_test_drop_download() {return true;}
bool get_test_drop_download_height() {return true;} bool get_test_drop_download_height() {return true;}
bool prepare_handle_incoming_blocks(const std::vector<cryptonote::block_complete_entry> &blocks) { return true; } bool prepare_handle_incoming_blocks(const std::vector<cryptonote::block_complete_entry> &blocks_entry, std::vector<cryptonote::block> &blocks) { return true; }
bool cleanup_handle_incoming_blocks(bool force_sync = false) { return true; } bool cleanup_handle_incoming_blocks(bool force_sync = false) { return true; }
uint64_t get_target_blockchain_height() const { return 1; } uint64_t get_target_blockchain_height() const { return 1; }
size_t get_block_sync_size(uint64_t height) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; } size_t get_block_sync_size(uint64_t height) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; }

View File

@ -388,7 +388,7 @@ public:
log_event("cryptonote::block"); log_event("cryptonote::block");
cryptonote::block_verification_context bvc = AUTO_VAL_INIT(bvc); cryptonote::block_verification_context bvc = AUTO_VAL_INIT(bvc);
m_c.handle_incoming_block(t_serializable_object_to_blob(b), bvc); m_c.handle_incoming_block(t_serializable_object_to_blob(b), &b, bvc);
bool r = check_block_verification_context(bvc, m_ev_index, b, m_validator); bool r = check_block_verification_context(bvc, m_ev_index, b, m_validator);
CHECK_AND_NO_ASSERT_MES(r, false, "block verification context check failed"); CHECK_AND_NO_ASSERT_MES(r, false, "block verification context check failed");
return r; return r;
@ -411,7 +411,7 @@ public:
log_event("serialized_block"); log_event("serialized_block");
cryptonote::block_verification_context bvc = AUTO_VAL_INIT(bvc); cryptonote::block_verification_context bvc = AUTO_VAL_INIT(bvc);
m_c.handle_incoming_block(sr_block.data, bvc); m_c.handle_incoming_block(sr_block.data, NULL, bvc);
cryptonote::block blk; cryptonote::block blk;
std::stringstream ss; std::stringstream ss;

View File

@ -56,7 +56,7 @@ public:
void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=crypto::null_hash;} void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=crypto::null_hash;}
bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; } bool handle_incoming_tx(const cryptonote::blobdata& tx_blob, cryptonote::tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; }
bool handle_incoming_txs(const std::vector<cryptonote::blobdata>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; } bool handle_incoming_txs(const std::vector<cryptonote::blobdata>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { return true; }
bool handle_incoming_block(const cryptonote::blobdata& block_blob, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true) { return true; } bool handle_incoming_block(const cryptonote::blobdata& block_blob, const cryptonote::block *block, cryptonote::block_verification_context& bvc, bool update_miner_blocktemplate = true) { return true; }
void pause_mine(){} void pause_mine(){}
void resume_mine(){} void resume_mine(){}
bool on_idle(){return true;} bool on_idle(){return true;}
@ -65,7 +65,7 @@ public:
cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); } cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); }
bool get_test_drop_download() const {return true;} bool get_test_drop_download() const {return true;}
bool get_test_drop_download_height() const {return true;} bool get_test_drop_download_height() const {return true;}
bool prepare_handle_incoming_blocks(const std::vector<cryptonote::block_complete_entry> &blocks) { return true; } bool prepare_handle_incoming_blocks(const std::vector<cryptonote::block_complete_entry> &blocks_entry, std::vector<cryptonote::block> &blocks) { return true; }
bool cleanup_handle_incoming_blocks(bool force_sync = false) { return true; } bool cleanup_handle_incoming_blocks(bool force_sync = false) { return true; }
uint64_t get_target_blockchain_height() const { return 1; } uint64_t get_target_blockchain_height() const { return 1; }
size_t get_block_sync_size(uint64_t height) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; } size_t get_block_sync_size(uint64_t height) const { return BLOCKS_SYNCHRONIZING_DEFAULT_COUNT; }

View File

@ -163,17 +163,17 @@ protected:
block bl; block bl;
blobdata bd = h2b(i); blobdata bd = h2b(i);
parse_and_validate_block_from_blob(bd, bl); parse_and_validate_block_from_blob(bd, bl);
m_blocks.push_back(bl); m_blocks.push_back(std::make_pair(bl, bd));
} }
for (auto& i : t_transactions) for (auto& i : t_transactions)
{ {
std::vector<transaction> txs; std::vector<std::pair<transaction, blobdata>> txs;
for (auto& j : i) for (auto& j : i)
{ {
transaction tx; transaction tx;
blobdata bd = h2b(j); blobdata bd = h2b(j);
parse_and_validate_tx_from_blob(bd, tx); parse_and_validate_tx_from_blob(bd, tx);
txs.push_back(tx); txs.push_back(std::make_pair(tx, bd));
} }
m_txs.push_back(txs); m_txs.push_back(txs);
} }
@ -187,8 +187,8 @@ protected:
BlockchainDB* m_db; BlockchainDB* m_db;
HardFork m_hardfork; HardFork m_hardfork;
std::string m_prefix; std::string m_prefix;
std::vector<block> m_blocks; std::vector<std::pair<block, blobdata>> m_blocks;
std::vector<std::vector<transaction> > m_txs; std::vector<std::vector<std::pair<transaction, blobdata>>> m_txs;
std::vector<std::string> m_filenames; std::vector<std::string> m_filenames;
void init_hard_fork() void init_hard_fork()
@ -283,19 +283,19 @@ TYPED_TEST(BlockchainDBTest, AddBlock)
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[1], t_sizes[1], t_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1])); ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[1], t_sizes[1], t_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1]));
block b; block b;
ASSERT_TRUE(this->m_db->block_exists(get_block_hash(this->m_blocks[0]))); ASSERT_TRUE(this->m_db->block_exists(get_block_hash(this->m_blocks[0].first)));
ASSERT_NO_THROW(b = this->m_db->get_block(get_block_hash(this->m_blocks[0]))); ASSERT_NO_THROW(b = this->m_db->get_block(get_block_hash(this->m_blocks[0].first)));
ASSERT_TRUE(compare_blocks(this->m_blocks[0], b)); ASSERT_TRUE(compare_blocks(this->m_blocks[0].first, b));
ASSERT_NO_THROW(b = this->m_db->get_block_from_height(0)); ASSERT_NO_THROW(b = this->m_db->get_block_from_height(0));
ASSERT_TRUE(compare_blocks(this->m_blocks[0], b)); ASSERT_TRUE(compare_blocks(this->m_blocks[0].first, b));
// assert that we can't add the same block twice // assert that we can't add the same block twice
ASSERT_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0]), TX_EXISTS); ASSERT_THROW(this->m_db->add_block(this->m_blocks[0], t_sizes[0], t_sizes[0], t_diffs[0], t_coins[0], this->m_txs[0]), TX_EXISTS);
for (auto& h : this->m_blocks[0].tx_hashes) for (auto& h : this->m_blocks[0].first.tx_hashes)
{ {
transaction tx; transaction tx;
ASSERT_TRUE(this->m_db->tx_exists(h)); ASSERT_TRUE(this->m_db->tx_exists(h));
@ -327,21 +327,21 @@ TYPED_TEST(BlockchainDBTest, RetrieveBlockData)
ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[1], t_sizes[1], t_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1])); ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[1], t_sizes[1], t_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1]));
ASSERT_EQ(t_diffs[1] - t_diffs[0], this->m_db->get_block_difficulty(1)); ASSERT_EQ(t_diffs[1] - t_diffs[0], this->m_db->get_block_difficulty(1));
ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0]), this->m_db->get_block_hash_from_height(0)); ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0].first), this->m_db->get_block_hash_from_height(0));
std::vector<block> blks; std::vector<block> blks;
ASSERT_NO_THROW(blks = this->m_db->get_blocks_range(0, 1)); ASSERT_NO_THROW(blks = this->m_db->get_blocks_range(0, 1));
ASSERT_EQ(2, blks.size()); ASSERT_EQ(2, blks.size());
ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0]), get_block_hash(blks[0])); ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0].first), get_block_hash(blks[0]));
ASSERT_HASH_EQ(get_block_hash(this->m_blocks[1]), get_block_hash(blks[1])); ASSERT_HASH_EQ(get_block_hash(this->m_blocks[1].first), get_block_hash(blks[1]));
std::vector<crypto::hash> hashes; std::vector<crypto::hash> hashes;
ASSERT_NO_THROW(hashes = this->m_db->get_hashes_range(0, 1)); ASSERT_NO_THROW(hashes = this->m_db->get_hashes_range(0, 1));
ASSERT_EQ(2, hashes.size()); ASSERT_EQ(2, hashes.size());
ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0]), hashes[0]); ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0].first), hashes[0]);
ASSERT_HASH_EQ(get_block_hash(this->m_blocks[1]), hashes[1]); ASSERT_HASH_EQ(get_block_hash(this->m_blocks[1].first), hashes[1]);
} }
} // anonymous namespace } // anonymous namespace

View File

@ -64,11 +64,13 @@ public:
virtual uint64_t height() const override { return blocks.size(); } virtual uint64_t height() const override { return blocks.size(); }
virtual size_t get_block_weight(const uint64_t &h) const override { return blocks[h].weight; } virtual size_t get_block_weight(const uint64_t &h) const override { return blocks[h].weight; }
virtual uint64_t get_block_long_term_weight(const uint64_t &h) const override { return blocks[h].long_term_weight; } virtual uint64_t get_block_long_term_weight(const uint64_t &h) const override { return blocks[h].long_term_weight; }
virtual crypto::hash top_block_hash() const override { virtual crypto::hash top_block_hash(uint64_t *block_height = NULL) const override {
uint64_t h = height(); uint64_t h = height();
crypto::hash top = crypto::null_hash; crypto::hash top = crypto::null_hash;
if (h) if (h)
*(uint64_t*)&top = h - 1; *(uint64_t*)&top = h - 1;
if (block_height)
*block_height = h - 1;
return top; return top;
} }
virtual void pop_block(cryptonote::block &blk, std::vector<cryptonote::transaction> &txs) override { blocks.pop_back(); } virtual void pop_block(cryptonote::block &blk, std::vector<cryptonote::transaction> &txs) override { blocks.pop_back(); }
@ -123,7 +125,7 @@ TEST(long_term_block_weight, identical_before_fork)
{ {
size_t w = h < CRYPTONOTE_REWARD_BLOCKS_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit(); size_t w = h < CRYPTONOTE_REWARD_BLOCKS_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
} }
for (uint64_t h = 0; h < 10 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h) for (uint64_t h = 0; h < 10 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
@ -140,7 +142,7 @@ TEST(long_term_block_weight, identical_after_fork_before_long_term_window)
{ {
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit(); size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
} }
for (uint64_t h = 0; h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h) for (uint64_t h = 0; h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h)
@ -157,7 +159,7 @@ TEST(long_term_block_weight, ceiling_at_30000000)
{ {
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit(); size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
} }
ASSERT_EQ(bc->get_current_cumulative_block_weight_median(), 15000000); ASSERT_EQ(bc->get_current_cumulative_block_weight_median(), 15000000);
@ -172,7 +174,7 @@ TEST(long_term_block_weight, multi_pop)
{ {
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit(); size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
} }
@ -183,7 +185,7 @@ TEST(long_term_block_weight, multi_pop)
{ {
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit(); size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
} }
@ -207,7 +209,7 @@ TEST(long_term_block_weight, multiple_updates)
{ {
size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit(); size_t w = h < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
const uint64_t effective_median = bc->get_current_cumulative_block_weight_median(); const uint64_t effective_median = bc->get_current_cumulative_block_weight_median();
const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit(); const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit();
@ -231,7 +233,7 @@ TEST(long_term_block_weight, pop_invariant_max)
{ {
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit(); size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
} }
@ -259,7 +261,7 @@ TEST(long_term_block_weight, pop_invariant_max)
{ {
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit(); size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, bc->get_db().height(), bc->get_db().height(), {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
} }
@ -279,7 +281,7 @@ TEST(long_term_block_weight, pop_invariant_random)
{ {
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit(); size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
} }
@ -314,7 +316,7 @@ TEST(long_term_block_weight, pop_invariant_random)
uint32_t r = lcg(); uint32_t r = lcg();
size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : (r % bc->get_current_cumulative_block_weight_limit()); size_t w = bc->get_db().height() < TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : (r % bc->get_current_cumulative_block_weight_limit());
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, bc->get_db().height(), bc->get_db().height(), {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit()); ASSERT_TRUE(bc->update_next_cumulative_weight_limit());
const uint64_t effective_median = bc->get_current_cumulative_block_weight_median(); const uint64_t effective_median = bc->get_current_cumulative_block_weight_median();
const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit(); const uint64_t effective_limit = bc->get_current_cumulative_block_weight_limit();
@ -342,7 +344,7 @@ TEST(long_term_block_weight, long_growth_spike_and_drop)
{ {
size_t w = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5; size_t w = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight)); ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
} }
ASSERT_EQ(long_term_effective_median_block_weight, 300000); ASSERT_EQ(long_term_effective_median_block_weight, 300000);
@ -354,7 +356,7 @@ TEST(long_term_block_weight, long_growth_spike_and_drop)
float t = h / float(365 * 720 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW / 100000); float t = h / float(365 * 720 * TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW / 100000);
size_t w = 300000 + t * 30000; size_t w = 300000 + t * 30000;
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight)); ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
} }
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07); ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);
@ -365,7 +367,7 @@ TEST(long_term_block_weight, long_growth_spike_and_drop)
{ {
size_t w = bc->get_current_cumulative_block_weight_limit(); size_t w = bc->get_current_cumulative_block_weight_limit();
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight)); ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
} }
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07); ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);
@ -376,7 +378,7 @@ TEST(long_term_block_weight, long_growth_spike_and_drop)
{ {
size_t w = bc->get_current_cumulative_block_weight_median() * .25; size_t w = bc->get_current_cumulative_block_weight_median() * .25;
uint64_t ltw = bc->get_next_long_term_block_weight(w); uint64_t ltw = bc->get_next_long_term_block_weight(w);
bc->get_db().add_block(cryptonote::block(), w, ltw, h, h, {}); bc->get_db().add_block(std::make_pair(cryptonote::block(), ""), w, ltw, h, h, {});
ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight)); ASSERT_TRUE(bc->update_next_cumulative_weight_limit(&long_term_effective_median_block_weight));
} }
ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07); ASSERT_GT(long_term_effective_median_block_weight, 300000 * 1.07);