Merge pull request #7169
bbe3b27
tx_pool: full tx revalidation on fork boundaries (moneromooo-monero)
This commit is contained in:
commit
c3b1b94453
|
@ -588,6 +588,7 @@ block Blockchain::pop_block_from_blockchain()
|
||||||
|
|
||||||
CHECK_AND_ASSERT_THROW_MES(m_db->height() > 1, "Cannot pop the genesis block");
|
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
|
try
|
||||||
{
|
{
|
||||||
m_db->pop_block(popped_block, popped_txs);
|
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);
|
m_tx_pool.on_blockchain_dec(top_block_height, top_block_hash);
|
||||||
invalidate_block_template_cache();
|
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;
|
return popped_block;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
@ -4392,6 +4400,19 @@ leave:
|
||||||
get_difficulty_for_next_block(); // just to cache it
|
get_difficulty_for_next_block(); // just to cache it
|
||||||
invalidate_block_template_cache();
|
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);
|
send_miner_notifications(id, already_generated_coins);
|
||||||
|
|
||||||
for (const auto& notifier: m_block_notifiers)
|
for (const auto& notifier: m_block_notifiers)
|
||||||
|
|
|
@ -1568,61 +1568,59 @@ namespace cryptonote
|
||||||
{
|
{
|
||||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
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;
|
MINFO("Validating txpool contents for v" << (unsigned)version);
|
||||||
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;
|
LockedTXN lock(m_blockchain.get_db());
|
||||||
if (meta.weight > tx_weight_limit) {
|
|
||||||
LOG_PRINT_L1("Transaction " << txid << " is too big (" << meta.weight << " bytes), removing it from pool");
|
struct tx_entry_t
|
||||||
remove.insert(txid);
|
{
|
||||||
}
|
crypto::hash txid;
|
||||||
else if (m_blockchain.have_tx(txid)) {
|
txpool_tx_meta_t meta;
|
||||||
LOG_PRINT_L1("Transaction " << txid << " is in the blockchain, removing it from pool");
|
};
|
||||||
remove.insert(txid);
|
|
||||||
}
|
// 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;
|
return true;
|
||||||
}, false, relay_category::all);
|
}, false, relay_category::all);
|
||||||
|
|
||||||
size_t n_removed = 0;
|
// take them all out and add them back in, some might fail
|
||||||
if (!remove.empty())
|
size_t added = 0;
|
||||||
|
for (auto &e: txes)
|
||||||
{
|
{
|
||||||
LockedTXN lock(m_blockchain.get_db());
|
try
|
||||||
for (const crypto::hash &txid: remove)
|
|
||||||
{
|
{
|
||||||
try
|
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))
|
||||||
{
|
{
|
||||||
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
|
MINFO("Failed to re-validate tx " << e.txid << " for v" << (unsigned)version << ", dropped");
|
||||||
cryptonote::transaction tx;
|
continue;
|
||||||
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)
|
|
||||||
{
|
|
||||||
MERROR("Failed to remove invalid tx from pool");
|
|
||||||
// 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)
|
if (n_removed > 0)
|
||||||
++m_cookie;
|
++m_cookie;
|
||||||
return n_removed;
|
return n_removed;
|
||||||
|
|
|
@ -106,10 +106,16 @@ static uint32_t lcg()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BlockchainAndPool
|
||||||
|
{
|
||||||
|
cryptonote::tx_memory_pool txpool;
|
||||||
|
cryptonote::Blockchain bc;
|
||||||
|
BlockchainAndPool(): txpool(bc), bc(txpool) {}
|
||||||
|
};
|
||||||
|
|
||||||
#define PREFIX_WINDOW(hf_version,window) \
|
#define PREFIX_WINDOW(hf_version,window) \
|
||||||
std::unique_ptr<cryptonote::Blockchain> bc; \
|
BlockchainAndPool bap; \
|
||||||
cryptonote::tx_memory_pool txpool(*bc); \
|
cryptonote::Blockchain *bc = &bap.bc; \
|
||||||
bc.reset(new cryptonote::Blockchain(txpool)); \
|
|
||||||
struct get_test_options { \
|
struct get_test_options { \
|
||||||
const std::pair<uint8_t, uint64_t> hard_forks[3]; \
|
const std::pair<uint8_t, uint64_t> hard_forks[3]; \
|
||||||
const cryptonote::test_options test_options = { \
|
const cryptonote::test_options test_options = { \
|
||||||
|
@ -118,8 +124,7 @@ static uint32_t lcg()
|
||||||
}; \
|
}; \
|
||||||
get_test_options(): hard_forks{std::make_pair(1, (uint64_t)0), std::make_pair((uint8_t)hf_version, (uint64_t)1), std::make_pair((uint8_t)0, (uint64_t)0)} {} \
|
get_test_options(): hard_forks{std::make_pair(1, (uint64_t)0), std::make_pair((uint8_t)hf_version, (uint64_t)1), std::make_pair((uint8_t)0, (uint64_t)0)} {} \
|
||||||
} opts; \
|
} opts; \
|
||||||
cryptonote::Blockchain *blockchain = bc.get(); \
|
bool r = bc->init(new TestDB(), cryptonote::FAKECHAIN, true, &opts.test_options, 0, NULL); \
|
||||||
bool r = blockchain->init(new TestDB(), cryptonote::FAKECHAIN, true, &opts.test_options, 0, NULL); \
|
|
||||||
ASSERT_TRUE(r)
|
ASSERT_TRUE(r)
|
||||||
|
|
||||||
#define PREFIX(hf_version) PREFIX_WINDOW(hf_version, TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW)
|
#define PREFIX(hf_version) PREFIX_WINDOW(hf_version, TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW)
|
||||||
|
|
Loading…
Reference in New Issue