Skip to content

Commit

Permalink
Stacks 2.05: Add Epoch to Cost Estimate Key (#2923)
Browse files Browse the repository at this point in the history
* added bunch of things

* moving the stuff

* test compiles

* added a test

* fixed typo

* added two tests

* updated code/tests in stacks-node

* replaced indexed conn with unindexed one
  • Loading branch information
gregorycoppola committed Nov 16, 2021
1 parent f38fe32 commit 30fd6bb
Show file tree
Hide file tree
Showing 14 changed files with 422 additions and 69 deletions.
7 changes: 5 additions & 2 deletions src/chainstate/coordinator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -776,8 +776,11 @@ impl<
.index_conn()
.get_stacks_epoch_by_epoch_id(&block_receipt.evaluated_epoch)
.expect("Could not find a stacks epoch.");
estimator
.notify_block(&block_receipt.tx_receipts, &stacks_epoch.block_limit);
estimator.notify_block(
&block_receipt.tx_receipts,
&stacks_epoch.block_limit,
&stacks_epoch.epoch_id,
);
}

if let Some(ref mut estimator) = self.fee_estimator {
Expand Down
31 changes: 29 additions & 2 deletions src/chainstate/stacks/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,10 +472,11 @@ impl<'a> StacksMicroblockBuilder<'a> {
let deadline = get_epoch_time_ms() + (self.settings.max_miner_time_ms as u128);

mem_pool.reset_last_known_nonces()?;
let stacks_epoch_id = clarity_tx.get_epoch();
let block_limit = clarity_tx
.block_limit()
.expect("No block limit found for clarity_tx.");
mem_pool.estimate_tx_rates(100, &block_limit)?;
mem_pool.estimate_tx_rates(100, &block_limit, &stacks_epoch_id)?;

debug!(
"Microblock transaction selection begins (child of {}), bytes so far: {}",
Expand Down Expand Up @@ -516,6 +517,7 @@ impl<'a> StacksMicroblockBuilder<'a> {
&mempool_tx.tx.payload,
&receipt.execution_cost,
&block_limit,
&stacks_epoch_id,
) {
warn!("Error updating estimator";
"txid" => %mempool_tx.metadata.txid,
Expand Down Expand Up @@ -1534,6 +1536,8 @@ impl StacksBlockBuilder {
let (mut epoch_tx, confirmed_mblock_cost) =
builder.epoch_begin(&mut chainstate, burn_dbconn)?;

let stacks_epoch_id = epoch_tx.get_epoch();

let block_limit = epoch_tx
.block_limit()
.expect("Failed to obtain block limit from miner's block connection");
Expand All @@ -1542,7 +1546,7 @@ impl StacksBlockBuilder {

mempool.reset_last_known_nonces()?;

mempool.estimate_tx_rates(100, &block_limit)?;
mempool.estimate_tx_rates(100, &block_limit, &stacks_epoch_id)?;

let mut considered = HashSet::new(); // txids of all transactions we looked at
let mut mined_origin_nonces: HashMap<StacksAddress, u64> = HashMap::new(); // map addrs of mined transaction origins to the nonces we used
Expand Down Expand Up @@ -1614,6 +1618,7 @@ impl StacksBlockBuilder {
&txinfo.tx.payload,
&tx_receipt.execution_cost,
&block_limit,
&stacks_epoch_id,
) {
warn!("Error updating estimator";
"txid" => %txinfo.metadata.txid,
Expand Down Expand Up @@ -6660,6 +6665,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -6800,6 +6806,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -6937,6 +6944,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand All @@ -6961,6 +6969,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -7664,6 +7673,7 @@ pub mod test {
&tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -7867,6 +7877,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

Expand All @@ -7887,6 +7898,7 @@ pub mod test {
&contract_tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

Expand All @@ -7906,6 +7918,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

Expand Down Expand Up @@ -8060,6 +8073,7 @@ pub mod test {
&contract_tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -8217,6 +8231,7 @@ pub mod test {
&contract_tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -8352,6 +8367,7 @@ pub mod test {
&parent_header_hash,
contract_tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

Expand All @@ -8378,6 +8394,7 @@ pub mod test {
&parent_header_hash,
contract_tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

Expand Down Expand Up @@ -8723,6 +8740,7 @@ pub mod test {
&parent_header_hash,
contract_tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

Expand Down Expand Up @@ -8750,6 +8768,7 @@ pub mod test {
&parent_header_hash,
contract_tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

Expand Down Expand Up @@ -8785,6 +8804,7 @@ pub mod test {
&parent_header_hash,
contract_tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

Expand Down Expand Up @@ -8812,6 +8832,7 @@ pub mod test {
&parent_header_hash,
contract_tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

Expand Down Expand Up @@ -9078,6 +9099,7 @@ pub mod test {
&parent_header_hash,
tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -9409,6 +9431,7 @@ pub mod test {
&parent_header_hash,
tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -9483,6 +9506,7 @@ pub mod test {
&parent_header_hash,
tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -9514,6 +9538,7 @@ pub mod test {
&parent_header_hash,
tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -9890,6 +9915,7 @@ pub mod test {
&tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap()
}
Expand All @@ -9914,6 +9940,7 @@ pub mod test {
&tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap()
}
Expand Down
7 changes: 7 additions & 0 deletions src/core/mempool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ use chainstate::stacks::{
Error as ChainstateError, StacksTransaction,
};
use core::ExecutionCost;
use core::StacksEpochId;
use core::FIRST_BURNCHAIN_CONSENSUS_HASH;
use core::FIRST_STACKS_BLOCK_HASH;
use monitoring::increment_stx_mempool_gc;
Expand Down Expand Up @@ -663,6 +664,7 @@ impl MemPoolDB {
&mut self,
max_updates: u32,
block_limit: &ExecutionCost,
stacks_epoch_id: &StacksEpochId,
) -> Result<u32, db_error> {
let sql_tx = tx_begin_immediate(&mut self.db)?;
let txs: Vec<MemPoolTxInfo> = query_rows(
Expand All @@ -679,6 +681,7 @@ impl MemPoolDB {
self.cost_estimator.as_ref(),
self.metric.as_ref(),
block_limit,
stacks_epoch_id,
);
let fee_rate_f64 = match estimator_result {
Ok(x) => Some(x),
Expand Down Expand Up @@ -1234,12 +1237,14 @@ impl MemPoolDB {
tx: &StacksTransaction,
event_observer: Option<&dyn MemPoolEventDispatcher>,
block_limit: &ExecutionCost,
stacks_epoch_id: &StacksEpochId,
) -> Result<(), MemPoolRejection> {
let estimator_result = cost_estimates::estimate_fee_rate(
tx,
self.cost_estimator.as_ref(),
self.metric.as_ref(),
block_limit,
stacks_epoch_id,
);

let mut mempool_tx = self.tx_begin().map_err(MemPoolRejection::DBError)?;
Expand Down Expand Up @@ -1279,6 +1284,7 @@ impl MemPoolDB {
block_hash: &BlockHeaderHash,
tx_bytes: Vec<u8>,
block_limit: &ExecutionCost,
stacks_epoch_id: &StacksEpochId,
) -> Result<(), MemPoolRejection> {
let tx = StacksTransaction::consensus_deserialize(&mut &tx_bytes[..])
.map_err(MemPoolRejection::DeserializationFailure)?;
Expand All @@ -1288,6 +1294,7 @@ impl MemPoolDB {
self.cost_estimator.as_ref(),
self.metric.as_ref(),
block_limit,
stacks_epoch_id,
);

let mut mempool_tx = self.tx_begin().map_err(MemPoolRejection::DBError)?;
Expand Down
41 changes: 33 additions & 8 deletions src/cost_estimates/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub mod pessimistic;
pub mod tests;

use crate::chainstate::stacks::StacksTransaction;
use core::StacksEpochId;

use self::metrics::CostMetric;
pub use self::pessimistic::PessimisticEstimator;
Expand Down Expand Up @@ -106,8 +107,9 @@ pub fn estimate_fee_rate<CE: CostEstimator + ?Sized, CM: CostMetric + ?Sized>(
estimator: &CE,
metric: &CM,
block_limit: &ExecutionCost,
stacks_epoch_id: &StacksEpochId,
) -> Result<f64, EstimatorError> {
let cost_estimate = estimator.estimate_cost(&tx.payload)?;
let cost_estimate = estimator.estimate_cost(&tx.payload, stacks_epoch_id)?;
let metric_estimate = metric.from_cost_and_len(&cost_estimate, block_limit, tx.tx_len());
Ok(tx.get_tx_fee() as f64 / metric_estimate as f64)
}
Expand All @@ -128,19 +130,29 @@ pub trait CostEstimator: Send {
tx: &TransactionPayload,
actual_cost: &ExecutionCost,
block_limit: &ExecutionCost,
evaluated_epoch: &StacksEpochId,
) -> Result<(), EstimatorError>;

/// This method is used by a stacks-node to obtain an estimate for a given transaction payload.
/// If the estimator cannot provide an accurate estimate for a given payload, it should return
/// `EstimatorError::NoEstimateAvailable`
fn estimate_cost(&self, tx: &TransactionPayload) -> Result<ExecutionCost, EstimatorError>;
fn estimate_cost(
&self,
tx: &TransactionPayload,
evaluated_epoch: &StacksEpochId,
) -> Result<ExecutionCost, EstimatorError>;

/// This method is invoked by the `stacks-node` to notify the estimator of all the transaction
/// receipts in a given block.
///
/// A default implementation is provided to implementing structs that processes the transaction
/// receipts by feeding them into `CostEstimator::notify_event()`
fn notify_block(&mut self, receipts: &[StacksTransactionReceipt], block_limit: &ExecutionCost) {
fn notify_block(
&mut self,
receipts: &[StacksTransactionReceipt],
block_limit: &ExecutionCost,
stacks_epoch_id: &StacksEpochId,
) {
// iterate over receipts, and for all the tx receipts, notify the event
for current_receipt in receipts.iter() {
let current_txid = match current_receipt.transaction {
Expand All @@ -152,9 +164,12 @@ pub trait CostEstimator: Send {
TransactionOrigin::Stacks(ref tx) => &tx.payload,
};

if let Err(e) =
self.notify_event(tx_payload, &current_receipt.execution_cost, block_limit)
{
if let Err(e) = self.notify_event(
tx_payload,
&current_receipt.execution_cost,
block_limit,
stacks_epoch_id,
) {
info!("CostEstimator failed to process event";
"txid" => %current_txid,
"error" => %e,
Expand Down Expand Up @@ -225,11 +240,16 @@ impl CostEstimator for () {
_tx: &TransactionPayload,
_actual_cost: &ExecutionCost,
_block_limit: &ExecutionCost,
_evaluated_epoch: &StacksEpochId,
) -> Result<(), EstimatorError> {
Ok(())
}

fn estimate_cost(&self, _tx: &TransactionPayload) -> Result<ExecutionCost, EstimatorError> {
fn estimate_cost(
&self,
_tx: &TransactionPayload,
_evaluated_epoch: &StacksEpochId,
) -> Result<ExecutionCost, EstimatorError> {
Err(EstimatorError::NoEstimateAvailable)
}
}
Expand Down Expand Up @@ -261,11 +281,16 @@ impl CostEstimator for UnitEstimator {
_tx: &TransactionPayload,
_actual_cost: &ExecutionCost,
_block_limit: &ExecutionCost,
_evaluated_epoch: &StacksEpochId,
) -> Result<(), EstimatorError> {
Ok(())
}

fn estimate_cost(&self, _tx: &TransactionPayload) -> Result<ExecutionCost, EstimatorError> {
fn estimate_cost(
&self,
_tx: &TransactionPayload,
_evaluated_epoch: &StacksEpochId,
) -> Result<ExecutionCost, EstimatorError> {
Ok(ExecutionCost {
write_length: 1,
write_count: 1,
Expand Down
Loading

0 comments on commit 30fd6bb

Please sign in to comment.