aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_core
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2020-12-18 15:56:54 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2021-11-01 20:56:38 +0000
commitbbe3b276b882af644139d9e35e016eb6ec9298fd (patch)
treefc5f12c79e8da459e5702479eb13dab726159726 /src/cryptonote_core
parentMerge pull request #7989 (diff)
downloadmonero-bbe3b276b882af644139d9e35e016eb6ec9298fd.tar.xz
tx_pool: full tx revalidation on fork boundaries
avoids mining txes after a fork that are invalid by this fork's rules, but were valid by the previous fork rules at the time they were verified and added to the txpool.
Diffstat (limited to 'src/cryptonote_core')
-rw-r--r--src/cryptonote_core/blockchain.cpp21
-rw-r--r--src/cryptonote_core/tx_pool.cpp88
2 files changed, 64 insertions, 45 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 33407bf95..34031fb7c 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -588,6 +588,7 @@ block Blockchain::pop_block_from_blockchain()
CHECK_AND_ASSERT_THROW_MES(m_db->height() > 1, "Cannot pop the genesis block");
+ const uint8_t previous_hf_version = get_current_hard_fork_version();
try
{
m_db->pop_block(popped_block, popped_txs);
@@ -650,6 +651,13 @@ block Blockchain::pop_block_from_blockchain()
m_tx_pool.on_blockchain_dec(top_block_height, top_block_hash);
invalidate_block_template_cache();
+ const uint8_t new_hf_version = get_current_hard_fork_version();
+ if (new_hf_version != previous_hf_version)
+ {
+ MINFO("Validating txpool for v" << (unsigned)new_hf_version);
+ m_tx_pool.validate(new_hf_version);
+ }
+
return popped_block;
}
//------------------------------------------------------------------
@@ -4392,6 +4400,19 @@ leave:
get_difficulty_for_next_block(); // just to cache it
invalidate_block_template_cache();
+ const uint8_t new_hf_version = get_current_hard_fork_version();
+ if (new_hf_version != hf_version)
+ {
+ // the genesis block is added before everything's setup, and the txpool is empty
+ // when we start from scratch, so we skip this
+ const bool is_genesis_block = new_height == 1;
+ if (!is_genesis_block)
+ {
+ MGINFO("Validating txpool for v" << (unsigned)new_hf_version);
+ m_tx_pool.validate(new_hf_version);
+ }
+ }
+
send_miner_notifications(id, already_generated_coins);
for (const auto& notifier: m_block_notifiers)
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 84605d6f5..5629db3e6 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -1568,61 +1568,59 @@ namespace cryptonote
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
- size_t tx_weight_limit = get_transaction_weight_limit(version);
- std::unordered_set<crypto::hash> remove;
- m_txpool_weight = 0;
- m_blockchain.for_all_txpool_txes([this, &remove, tx_weight_limit](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref*) {
- m_txpool_weight += meta.weight;
- if (meta.weight > tx_weight_limit) {
- LOG_PRINT_L1("Transaction " << txid << " is too big (" << meta.weight << " bytes), removing it from pool");
- remove.insert(txid);
- }
- else if (m_blockchain.have_tx(txid)) {
- LOG_PRINT_L1("Transaction " << txid << " is in the blockchain, removing it from pool");
- remove.insert(txid);
- }
+ MINFO("Validating txpool contents for v" << (unsigned)version);
+
+ LockedTXN lock(m_blockchain.get_db());
+
+ struct tx_entry_t
+ {
+ crypto::hash txid;
+ txpool_tx_meta_t meta;
+ };
+
+ // get all txids
+ std::vector<tx_entry_t> txes;
+ m_blockchain.for_all_txpool_txes([this, &txes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata_ref*) {
+ if (!meta.pruned) // skip pruned txes
+ txes.push_back({txid, meta});
return true;
}, false, relay_category::all);
- size_t n_removed = 0;
- if (!remove.empty())
+ // take them all out and add them back in, some might fail
+ size_t added = 0;
+ for (auto &e: txes)
{
- LockedTXN lock(m_blockchain.get_db());
- for (const crypto::hash &txid: remove)
+ try
{
- try
- {
- cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
- cryptonote::transaction tx;
- if (!parse_and_validate_tx_from_blob(txblob, tx)) // remove pruned ones on startup, they're meant to be temporary
- {
- MERROR("Failed to parse tx from txpool");
- continue;
- }
- // remove tx from db first
- m_blockchain.remove_txpool_tx(txid);
- m_txpool_weight -= get_transaction_weight(tx, txblob.size());
- remove_transaction_keyimages(tx, txid);
- auto sorted_it = find_tx_in_sorted_container(txid);
- if (sorted_it == m_txs_by_fee_and_receive_time.end())
- {
- LOG_PRINT_L1("Removing tx " << txid << " from tx pool, but it was not found in the sorted txs container!");
- }
- else
- {
- m_txs_by_fee_and_receive_time.erase(sorted_it);
- }
- ++n_removed;
- }
- catch (const std::exception &e)
+ size_t weight;
+ uint64_t fee;
+ cryptonote::transaction tx;
+ cryptonote::blobdata blob;
+ bool relayed, do_not_relay, double_spend_seen, pruned;
+ if (!take_tx(e.txid, tx, blob, weight, fee, relayed, do_not_relay, double_spend_seen, pruned))
+ MERROR("Failed to get tx " << e.txid << " from txpool for re-validation");
+
+ cryptonote::tx_verification_context tvc{};
+ relay_method tx_relay = e.meta.get_relay_method();
+ if (!add_tx(tx, e.txid, blob, e.meta.weight, tvc, tx_relay, relayed, version))
{
- MERROR("Failed to remove invalid tx from pool");
- // continue
+ MINFO("Failed to re-validate tx " << e.txid << " for v" << (unsigned)version << ", dropped");
+ continue;
}
+ m_blockchain.update_txpool_tx(e.txid, e.meta);
+ ++added;
+ }
+ catch (const std::exception &e)
+ {
+ MERROR("Failed to re-validate tx from pool");
+ continue;
}
- lock.commit();
}
+
+ lock.commit();
+
+ const size_t n_removed = txes.size() - added;
if (n_removed > 0)
++m_cookie;
return n_removed;