Skip to content

Commit

Permalink
Merge pull request #3624 from stacks-network/fix/mempool-unlocks-3623
Browse files Browse the repository at this point in the history
Fix: Incorporate unlocks in mempool admitter, #3623
  • Loading branch information
kantai authored Mar 20, 2023
2 parents d69012e + aa5f167 commit a3feafd
Show file tree
Hide file tree
Showing 14 changed files with 557 additions and 44 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to the versioning scheme outlined in the [README.md](README.md).

## [2.1.0.0.2]

This software update is a hotfix to resolve improper unlock handling
in mempool admission. This release's chainstate directory is
compatible with chainstate directories from 2.1.0.0.2.

### Fixed

- Fix mempool admission logic's improper handling of PoX unlocks. This would
cause users to get spurious `NotEnoughFunds` rejections when trying to submit
their transactions (#3623)

## [2.1.0.0.1]

### Fixed
Expand Down
5 changes: 3 additions & 2 deletions src/chainstate/stacks/db/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6975,6 +6975,7 @@ impl StacksChainState {
/// unconfirmed microblock stream trailing off of it.
pub fn will_admit_mempool_tx(
&mut self,
burn_state_db: &dyn BurnStateDB,
current_consensus_hash: &ConsensusHash,
current_block: &BlockHeaderHash,
tx: &StacksTransaction,
Expand Down Expand Up @@ -7019,7 +7020,7 @@ impl StacksChainState {

let current_tip =
StacksChainState::get_parent_index_block(current_consensus_hash, current_block);
let res = match self.with_read_only_clarity_tx(&NULL_BURN_STATE_DB, &current_tip, |conn| {
let res = match self.with_read_only_clarity_tx(burn_state_db, &current_tip, |conn| {
StacksChainState::can_include_tx(conn, &conf, has_microblock_pubk, tx, tx_size)
}) {
Some(r) => r,
Expand All @@ -7039,7 +7040,7 @@ impl StacksChainState {
{
debug!("Transaction {} is unminable in the confirmed chain tip due to nonce {} != {}; trying the unconfirmed chain tip",
&tx.txid(), mismatch_error.expected, mismatch_error.actual);
self.with_read_only_unconfirmed_clarity_tx(&NULL_BURN_STATE_DB, |conn| {
self.with_read_only_unconfirmed_clarity_tx(burn_state_db, |conn| {
StacksChainState::can_include_tx(
conn,
&conf,
Expand Down
262 changes: 262 additions & 0 deletions src/chainstate/stacks/tests/block_construction.rs

Large diffs are not rendered by default.

21 changes: 19 additions & 2 deletions src/core/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use rusqlite::NO_PARAMS;
use siphasher::sip::SipHasher; // this is SipHash-2-4

use crate::burnchains::Txid;
use crate::chainstate::burn::db::sortdb::SortitionDB;
use crate::chainstate::burn::ConsensusHash;
use crate::chainstate::stacks::{
db::blocks::MemPoolRejection, db::ClarityTx, db::StacksChainState, db::TxStreamData,
Expand Down Expand Up @@ -174,10 +175,17 @@ impl MemPoolAdmitter {
pub fn will_admit_tx(
&mut self,
chainstate: &mut StacksChainState,
sortdb: &SortitionDB,
tx: &StacksTransaction,
tx_size: u64,
) -> Result<(), MemPoolRejection> {
chainstate.will_admit_mempool_tx(&self.cur_consensus_hash, &self.cur_block, tx, tx_size)
chainstate.will_admit_mempool_tx(
&sortdb.index_conn(),
&self.cur_consensus_hash,
&self.cur_block,
tx,
tx_size,
)
}
}

Expand Down Expand Up @@ -1973,6 +1981,7 @@ impl MemPoolDB {
fn tx_submit(
mempool_tx: &mut MemPoolTx,
chainstate: &mut StacksChainState,
sortdb: &SortitionDB,
consensus_hash: &ConsensusHash,
block_hash: &BlockHeaderHash,
tx: &StacksTransaction,
Expand Down Expand Up @@ -2027,7 +2036,9 @@ impl MemPoolDB {
mempool_tx
.admitter
.set_block(&block_hash, (*consensus_hash).clone());
mempool_tx.admitter.will_admit_tx(chainstate, tx, len)?;
mempool_tx
.admitter
.will_admit_tx(chainstate, sortdb, tx, len)?;
}

MemPoolDB::try_add_tx(
Expand Down Expand Up @@ -2064,6 +2075,7 @@ impl MemPoolDB {
pub fn submit(
&mut self,
chainstate: &mut StacksChainState,
sortdb: &SortitionDB,
consensus_hash: &ConsensusHash,
block_hash: &BlockHeaderHash,
tx: &StacksTransaction,
Expand Down Expand Up @@ -2101,6 +2113,7 @@ impl MemPoolDB {
MemPoolDB::tx_submit(
&mut mempool_tx,
chainstate,
sortdb,
consensus_hash,
block_hash,
tx,
Expand All @@ -2116,6 +2129,7 @@ impl MemPoolDB {
pub fn miner_submit(
&mut self,
chainstate: &mut StacksChainState,
sortdb: &SortitionDB,
consensus_hash: &ConsensusHash,
block_hash: &BlockHeaderHash,
tx: &StacksTransaction,
Expand All @@ -2129,6 +2143,7 @@ impl MemPoolDB {
MemPoolDB::tx_submit(
&mut mempool_tx,
chainstate,
sortdb,
consensus_hash,
block_hash,
tx,
Expand All @@ -2146,6 +2161,7 @@ impl MemPoolDB {
pub fn submit_raw(
&mut self,
chainstate: &mut StacksChainState,
sortdb: &SortitionDB,
consensus_hash: &ConsensusHash,
block_hash: &BlockHeaderHash,
tx_bytes: Vec<u8>,
Expand Down Expand Up @@ -2187,6 +2203,7 @@ impl MemPoolDB {
MemPoolDB::tx_submit(
&mut mempool_tx,
chainstate,
sortdb,
consensus_hash,
block_hash,
&tx,
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1433,6 +1433,7 @@ simulating a miner.
}
let result = mempool_db.submit(
&mut chain_state,
&sort_db,
&stacks_block.consensus_hash,
&stacks_block.anchored_block_hash,
&raw_tx,
Expand Down
1 change: 1 addition & 0 deletions src/net/p2p.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5246,6 +5246,7 @@ impl PeerNetwork {

if let Err(e) = mempool.submit(
chainstate,
sortdb,
consensus_hash,
block_hash,
&tx,
Expand Down
2 changes: 2 additions & 0 deletions src/net/relay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5824,6 +5824,7 @@ pub mod test {
let versioned_contract = (*versioned_contract_opt.borrow()).clone().unwrap();
let versioned_contract_len = versioned_contract.serialize_to_vec().len();
match node.chainstate.will_admit_mempool_tx(
&sortdb.index_conn(),
&consensus_hash,
&stacks_block.block_hash(),
&versioned_contract,
Expand Down Expand Up @@ -5873,6 +5874,7 @@ pub mod test {
let versioned_contract = (*versioned_contract_opt.borrow()).clone().unwrap();
let versioned_contract_len = versioned_contract.serialize_to_vec().len();
match node.chainstate.will_admit_mempool_tx(
&sortdb.index_conn(),
&consensus_hash,
&stacks_block.block_hash(),
&versioned_contract,
Expand Down
1 change: 1 addition & 0 deletions src/net/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2093,6 +2093,7 @@ impl ConversationHttp {
} else {
match mempool.submit(
chainstate,
sortdb,
&consensus_hash,
&block_hash,
&tx,
Expand Down
3 changes: 3 additions & 0 deletions testnet/stacks-node/src/neon_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1594,6 +1594,7 @@ impl BlockMinerThread {
fn load_and_vet_parent_microblocks(
&mut self,
chain_state: &mut StacksChainState,
sortdb: &SortitionDB,
mem_pool: &mut MemPoolDB,
parent_block_info: &mut ParentStacksBlockInfo,
) -> Option<Vec<StacksMicroblock>> {
Expand Down Expand Up @@ -1662,6 +1663,7 @@ impl BlockMinerThread {
// anchored block.
if let Err(e) = mem_pool.miner_submit(
chain_state,
sortdb,
&parent_consensus_hash,
&stacks_parent_header.anchored_header.block_hash(),
&poison_microblock_tx,
Expand Down Expand Up @@ -1889,6 +1891,7 @@ impl BlockMinerThread {
// target it to the microblock tail in parent_block_info
let microblocks_opt = self.load_and_vet_parent_microblocks(
&mut chain_state,
&burn_db,
&mut mem_pool,
&mut parent_block_info,
);
Expand Down
14 changes: 14 additions & 0 deletions testnet/stacks-node/src/tenure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use super::{BurnchainTip, Config};
use std::thread;
use std::time::{Duration, Instant};

#[cfg(test)]
use stacks::burnchains::PoxConstants;
#[cfg(test)]
use stacks::chainstate::burn::db::sortdb::SortitionDB;
use stacks::chainstate::burn::db::sortdb::SortitionDBConn;
use stacks::chainstate::stacks::db::StacksChainState;
use stacks::chainstate::stacks::{
Expand Down Expand Up @@ -123,4 +127,14 @@ impl<'a> Tenure {
.unwrap();
chain_state
}

#[cfg(test)]
pub fn open_fake_sortdb(&self) -> SortitionDB {
SortitionDB::open(
&self.config.get_burn_db_file_path(),
true,
PoxConstants::testnet_default(),
)
.unwrap()
}
}
12 changes: 7 additions & 5 deletions testnet/stacks-node/src/tests/bitcoin_regtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,8 @@ fn bitcoind_integration(segwit_flag: bool) {
// Use tenure's hook for submitting transactions
run_loop.callbacks.on_new_tenure(|round, _burnchain_tip, chain_tip, tenure| {
let mut chainstate_copy = tenure.open_chainstate();
let sortdb = tenure.open_fake_sortdb();

match round {
1 => {
// On round 1, publish the KV contract
Expand All @@ -391,7 +393,7 @@ fn bitcoind_integration(segwit_flag: bool) {
// ./blockstack-cli --testnet publish 043ff5004e3d695060fa48ac94c96049b8c14ef441c50a184a6a3875d2a000f3 0 0 store /tmp/out.clar
let header_hash = chain_tip.block.block_hash();
let consensus_hash = chain_tip.metadata.consensus_hash;
tenure.mem_pool.submit_raw(&mut chainstate_copy, &consensus_hash, &header_hash, PUBLISH_CONTRACT.to_owned(), &ExecutionCost::max_value(),
tenure.mem_pool.submit_raw(&mut chainstate_copy, &sortdb, &consensus_hash, &header_hash, PUBLISH_CONTRACT.to_owned(), &ExecutionCost::max_value(),
&StacksEpochId::Epoch20,).unwrap();
},
2 => {
Expand All @@ -400,7 +402,7 @@ fn bitcoind_integration(segwit_flag: bool) {
let header_hash = chain_tip.block.block_hash();
let consensus_hash = chain_tip.metadata.consensus_hash;
let get_foo = "8080000000040021a3c334fc0ee50359353799e8b2605ac6be1fe40000000000000001000000000000000a0100b7ff8b6c20c427b4f4f09c1ad7e50027e2b076b2ddc0ab55e64ef5ea3771dd4763a79bc5a2b1a79b72ce03dd146ccf24b84942d675a815819a8b85aa8065dfaa030200000000021a21a3c334fc0ee50359353799e8b2605ac6be1fe40573746f7265096765742d76616c7565000000010d00000003666f6f";
tenure.mem_pool.submit_raw(&mut chainstate_copy, &consensus_hash, &header_hash,hex_bytes(get_foo).unwrap().to_vec(), &ExecutionCost::max_value(),
tenure.mem_pool.submit_raw(&mut chainstate_copy, &sortdb, &consensus_hash, &header_hash,hex_bytes(get_foo).unwrap().to_vec(), &ExecutionCost::max_value(),
&StacksEpochId::Epoch20,).unwrap();
},
3 => {
Expand All @@ -409,7 +411,7 @@ fn bitcoind_integration(segwit_flag: bool) {
let header_hash = chain_tip.block.block_hash();
let consensus_hash = chain_tip.metadata.consensus_hash;
let set_foo_bar = "8080000000040021a3c334fc0ee50359353799e8b2605ac6be1fe40000000000000002000000000000000a010142a01caf6a32b367664869182f0ebc174122a5a980937ba259d44cc3ebd280e769a53dd3913c8006ead680a6e1c98099fcd509ce94b0a4e90d9f4603b101922d030200000000021a21a3c334fc0ee50359353799e8b2605ac6be1fe40573746f7265097365742d76616c7565000000020d00000003666f6f0d00000003626172";
tenure.mem_pool.submit_raw(&mut chainstate_copy, &consensus_hash, &header_hash,hex_bytes(set_foo_bar).unwrap().to_vec(), &ExecutionCost::max_value(),
tenure.mem_pool.submit_raw(&mut chainstate_copy, &sortdb, &consensus_hash, &header_hash,hex_bytes(set_foo_bar).unwrap().to_vec(), &ExecutionCost::max_value(),
&StacksEpochId::Epoch20,).unwrap();
},
4 => {
Expand All @@ -418,7 +420,7 @@ fn bitcoind_integration(segwit_flag: bool) {
let header_hash = chain_tip.block.block_hash();
let consensus_hash = chain_tip.metadata.consensus_hash;
let get_foo = "8080000000040021a3c334fc0ee50359353799e8b2605ac6be1fe40000000000000003000000000000000a010046c2c1c345231443fef9a1f64fccfef3e1deacc342b2ab5f97612bb3742aa799038b20aea456789aca6b883e52f84a31adfee0bc2079b740464877af8f2f87d2030200000000021a21a3c334fc0ee50359353799e8b2605ac6be1fe40573746f7265096765742d76616c7565000000010d00000003666f6f";
tenure.mem_pool.submit_raw(&mut chainstate_copy, &consensus_hash, &header_hash,hex_bytes(get_foo).unwrap().to_vec(), &ExecutionCost::max_value(),
tenure.mem_pool.submit_raw(&mut chainstate_copy, &sortdb, &consensus_hash, &header_hash,hex_bytes(get_foo).unwrap().to_vec(), &ExecutionCost::max_value(),
&StacksEpochId::Epoch20,).unwrap();
},
5 => {
Expand All @@ -427,7 +429,7 @@ fn bitcoind_integration(segwit_flag: bool) {
let header_hash = chain_tip.block.block_hash();
let consensus_hash = chain_tip.metadata.consensus_hash;
let transfer_1000_stx = "80800000000400b71a091b4b8b7661a661c620966ab6573bc2dcd30000000000000000000000000000000a0000393810832bacd44cfc4024980876135de6b95429bdb610d5ce96a92c9ee9bfd81ec77ea0f1748c8515fc9a1589e51d8b92bf028e3e84ade1249682c05271d5b803020000000000051a525b8a36ef8a73548cd0940c248d3b71ecf4a45100000000000003e800000000000000000000000000000000000000000000000000000000000000000000";
tenure.mem_pool.submit_raw(&mut chainstate_copy, &consensus_hash, &header_hash,hex_bytes(transfer_1000_stx).unwrap().to_vec(), &ExecutionCost::max_value(),
tenure.mem_pool.submit_raw(&mut chainstate_copy, &sortdb, &consensus_hash, &header_hash,hex_bytes(transfer_1000_stx).unwrap().to_vec(), &ExecutionCost::max_value(),
&StacksEpochId::Epoch20,).unwrap();
},
_ => {}
Expand Down
Loading

0 comments on commit a3feafd

Please sign in to comment.