Toccata transient mass activation and mempool policy refinement#995
Toccata transient mass activation and mempool policy refinement#995michaelsutton wants to merge 14 commits into
Conversation
Add validate_transaction_template_limits as a post-consensus mempool admission check. It rejects txs that cannot fit in a block template under the current delayed mempool limits, before standardness-in-context and RBF eviction. Use raw per-dimension limits for clearer errors: compute, transient, storage, and gas. Keep mempool_block_mass_limits in Config alongside derived cofactors, so selectors/RBF still use normalized weights while admission checks raw fit. Clean standardness tests by removing stale mass/gas cases and decoupling relay fee arithmetic from the removed standard mass constant. Extend Toccata tests to cover delayed transient admission and gas rejection even when non-standard txs are allowed.
base the standard relay fee floor on max(compute, transient) so transient block-space usage has a minimum cost, move fee check out of the loop so it's checked once and not per input and add context-standardness coverage for fee and input script checks.
Set the classic P2SH sigop standardness cap to match the previous 100k compute-mass allowance, and document why compute mass remains the real execution bound.
Remove the redundant is_unspendable branch from dust classification: standardness already rejects non-standard SPKs before dust, and standard SPK classes are spendable.
Drop the relay-fee dust threshold from mempool standardness and remove the mining dust helper. KIP9 storage mass already prices UTXO growth at the system level.
| fn check_transaction_signature_scripts_in_header_context(&self, tx: &Transaction, block_daa_score: u64) -> TxResult<()> { | ||
| let max_signature_script_len = self.max_signature_script_len.get(block_daa_score); | ||
| if let Some(i) = tx.inputs.iter().position(|input| input.signature_script.len() > max_signature_script_len) { | ||
| return Err(TxRuleError::TooBigSignatureScript(i, max_signature_script_len)); | ||
| } | ||
|
|
||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
You should add the intent of the validation as a comment in this function.
The name check_transaction_signature_scripts_in_header_context doesn't suggest it will only check length but signature scripts as a whole (so perhaps this may check length and something else). The implementation only checks for length.
There was a problem hiding this comment.
it's more like: "do what ever you can do to check_transaction_signature_scripts_in_header_context"
cf transaction_in_isolation where it's simply called check_transaction_signature_scripts
Split template-limit validation into isolation and context phases so gas, compute and transient limits are rejected before consensus in-context validation. Keep storage checks after contextual mass is populated and cover the ordering in Toccata transient mass activation tests.
Use the real contextual storage mass calculation in Toccata mempool tests and add a tiny-output case that rejects with RejectStorageMass after consensus in-context validation.
Separate duplicate detection from isolation standardness and rename the local standardness helpers to std_in_isolation/std_in_context. Reuse the same transaction-id checks before and after consensus validation to make the concurrency recheck semantics explicit.
Base the minimum relay fee on max(compute, normalized transient) using stable post-activation cofactors, so activation only changes limits, not unit pricing. Split insufficient-fee errors by dominant mass dimension. Change devnet/simnet pre-activation transient limits so that devnet/simnet tests and runs trigger the activation case.
Assert that mempool mass cofactors keep the same reference across activation, and document the selector assumption when using the post-activation reference.
1219408 to
404eb44
Compare
| &self, | ||
| transaction: &MutableTransaction, | ||
| rbf_policy: RbfPolicy, | ||
| _virtual_daa_score: u64, |
| fn get_double_spend_feerate(&self, double_spend: &DoubleSpend) -> RuleResult<f64> { | ||
| let owner = self.transaction_pool.get_double_spend_owner(double_spend)?; | ||
| match owner.mtx.calculated_feerate(&self.config.block_mass_cofactors) { | ||
| let cofactors = self.config.mempool_mass_cofactors.get(owner.added_at_daa_score); |
There was a problem hiding this comment.
nit, but doesn't it make more sense to use virtual_daa_score?
| owner.mtx.calculated_feerate(&self.config.block_mass_cofactors), | ||
| ) { | ||
| let transaction_cofactors = self.config.mempool_mass_cofactors.get(virtual_daa_score); | ||
| let owner_cofactors = self.config.mempool_mass_cofactors.get(owner.added_at_daa_score); |
There was a problem hiding this comment.
nit, but doesn't it make more sense to use virtual_daa_score?
|
|
||
| // Create a tx with transient mass over the block limit | ||
| txx.payload = vec![0; (config.params.block_mass_limits.transient / TRANSIENT_BYTE_TO_MASS_FACTOR + 100) as usize]; | ||
| txx.payload = vec![0; (config.params.block_mass_limits().after().transient / TRANSIENT_BYTE_TO_MASS_FACTOR + 100) as usize]; |
There was a problem hiding this comment.
Why do we use .after() if toccata is not activated on devnet? (Same question for the rest of the test)
| Test { | ||
| name: "Transaction gas exceeds the per-lane limit", | ||
| mtx: new_mtx( | ||
| Transaction::new( | ||
| TX_VERSION, | ||
| vec![dummy_tx_input.clone()], | ||
| vec![dummy_tx_out.clone()], | ||
| 0, | ||
| SUBNETWORK_ID_NATIVE, | ||
| DEFAULT_GAS_PER_LANE_LIMIT + 1, | ||
| vec![], | ||
| ), | ||
| 1000, | ||
| ), | ||
| is_standard: false, | ||
| }, | ||
| Test { | ||
| name: "Transaction size is too large", | ||
| mtx: new_mtx( | ||
| Transaction::new( | ||
| TX_VERSION, | ||
| vec![dummy_tx_input.clone()], | ||
| vec![TransactionOutput::new( | ||
| 0u64, | ||
| ScriptPublicKey::new( |
There was a problem hiding this comment.
Do we want to move these tests somewhere else? Maybe to MiningManager.validate_and_insert_transaction?
| Ok(()) | ||
| } | ||
|
|
||
| fn check_transaction_signature_scripts_in_header_context(&self, tx: &Transaction, block_daa_score: u64) -> TxResult<()> { |
There was a problem hiding this comment.
Add a TODO(post-toccata) to remove it
Implements the Toccata transient mass activation, including forked block mass limits and delayed mempool adoption of the relaxed transient limit so pre-activation and near-boundary transactions remain safely conservative.
Also polishes mempool policy around the activation: