Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stacks 2.05: Add Epoch to Cost Estimate Key #2923

Merged
merged 8 commits into from
Nov 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/chainstate/coordinator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,8 +774,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 @@ -470,10 +470,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 @@ -514,6 +515,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 @@ -1492,6 +1494,8 @@ impl StacksBlockBuilder {

let mut epoch_tx = 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 @@ -1500,7 +1504,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 @@ -1572,6 +1576,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 @@ -6588,6 +6593,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -6728,6 +6734,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -6865,6 +6872,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand All @@ -6889,6 +6897,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -7036,6 +7045,7 @@ pub mod test {
&tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -7238,6 +7248,7 @@ pub mod test {
&stx_transfer,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

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

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

Expand Down Expand Up @@ -7431,6 +7444,7 @@ pub mod test {
&contract_tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -7588,6 +7602,7 @@ pub mod test {
&contract_tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -7723,6 +7738,7 @@ pub mod test {
&parent_header_hash,
contract_tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();

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

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

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

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

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

Expand Down Expand Up @@ -8449,6 +8470,7 @@ pub mod test {
&parent_header_hash,
tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -8780,6 +8802,7 @@ pub mod test {
&parent_header_hash,
tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -8854,6 +8877,7 @@ pub mod test {
&parent_header_hash,
tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -8885,6 +8909,7 @@ pub mod test {
&parent_header_hash,
tx_bytes,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap();
}
Expand Down Expand Up @@ -9260,6 +9285,7 @@ pub mod test {
&tx,
None,
&ExecutionCost::max_value(),
&StacksEpochId::Epoch20,
)
.unwrap()
}
Expand All @@ -9284,6 +9310,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 @@ -661,6 +662,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 @@ -677,6 +679,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 @@ -1232,12 +1235,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 @@ -1277,6 +1282,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 @@ -1286,6 +1292,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