Skip to content

Commit 71b4ec5

Browse files
committed
Only enforce block_spend_limit in V15 during finalization
1 parent 0700449 commit 71b4ec5

1 file changed

Lines changed: 34 additions & 43 deletions

File tree

synthesizer/src/vm/finalize.rs

Lines changed: 34 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ type AbortReason = String;
6161
type ComputeSpend = u64;
6262
/// An intermediary speculation artifact indicating whether a transaction should
6363
/// be aborted or finalized with a certain compute_spend.
64-
enum PrepareSpeculateResult {
64+
enum ShouldAbortResult {
6565
Abort(AbortReason),
6666
Finalize(ComputeSpend),
6767
}
@@ -402,7 +402,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
402402
// Accumulate per-block uniqueness checks.
403403
let mut candidate_transaction_details = CandidateTransactionDetails::<N>::default();
404404
// Accumulate per-block spend.
405-
let mut block_spend = 0;
405+
let mut block_spend = 0u64;
406406
// Determine the transaction spend limit. These unwraps are safe, see tests in consensus_heights.rs
407407
let consensus_version = N::CONSENSUS_VERSION(state.block_height()).unwrap();
408408
let transaction_spend_limit =
@@ -425,19 +425,29 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
425425
match self.should_abort_transaction(
426426
&transaction,
427427
&candidate_transaction_details,
428-
block_spend,
429428
transaction_spend_limit,
430-
block_spend_limit,
431429
consensus_version,
432430
) {
433-
PrepareSpeculateResult::Abort(abort_reason) => {
431+
ShouldAbortResult::Abort(abort_reason) => {
434432
// Store the aborted transaction.
435433
aborted.push((transaction.clone(), abort_reason));
436434
// Continue to the next transaction.
437435
continue 'outer;
438436
}
439-
PrepareSpeculateResult::Finalize(compute_spend) => {
437+
ShouldAbortResult::Finalize(compute_spend) => {
438+
// If the consensus version is >= V15, ensure that the
439+
// transaction is not exceeding block spend limits.
440440
if consensus_version >= ConsensusVersion::V15 {
441+
if let Some(block_spend_limit) = block_spend_limit {
442+
if block_spend.saturating_add(compute_spend) > block_spend_limit {
443+
aborted.push((
444+
transaction.clone(),
445+
format!("Exceeds the block spend limit with compute_spend: '{compute_spend}'"),
446+
));
447+
// Continue to the next transaction.
448+
continue 'outer;
449+
}
450+
}
441451
// Track the compute_spend used so far.
442452
block_spend = block_spend.saturating_add(compute_spend);
443453
}
@@ -937,7 +947,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
937947
finalize_result
938948
}
939949

940-
/// Returns PrepareSpeculateResult.
950+
/// Returns ShouldAbortResult.
941951
///
942952
/// The transaction will be aborted if any of the following conditions are met:
943953
/// - The transaction is producing a duplicate transition
@@ -954,14 +964,12 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
954964
&self,
955965
transaction: &Transaction<N>,
956966
candidate_transaction_details: &CandidateTransactionDetails<N>,
957-
block_spend: u64,
958967
transaction_spend_limit: u64,
959-
block_spend_limit: Option<u64>,
960968
consensus_version: ConsensusVersion,
961-
) -> PrepareSpeculateResult {
969+
) -> ShouldAbortResult {
962970
// Ensure that the transaction is not a fee transaction.
963971
if let Transaction::Fee(..) = transaction {
964-
return PrepareSpeculateResult::Abort("Fee transactions are not allowed in speculate".to_string());
972+
return ShouldAbortResult::Abort("Fee transactions are not allowed in speculate".to_string());
965973
}
966974

967975
// Ensure that:
@@ -974,11 +982,11 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
974982
if candidate_transaction_details.transition_ids.contains(transition_id)
975983
|| self.transition_store().contains_transition_id(transition_id).unwrap_or(true)
976984
{
977-
return PrepareSpeculateResult::Abort(format!("Duplicate transition {transition_id}"));
985+
return ShouldAbortResult::Abort(format!("Duplicate transition {transition_id}"));
978986
}
979987
// If the transition's program is being deployed or redeployed in this block, abort the transaction.
980988
if candidate_transaction_details.deployments.contains(transition.program_id()) {
981-
return PrepareSpeculateResult::Abort(format!(
989+
return ShouldAbortResult::Abort(format!(
982990
"Program {} is being deployed or redeployed in this block",
983991
transition.program_id()
984992
));
@@ -991,7 +999,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
991999
if candidate_transaction_details.input_ids.contains(input_id)
9921000
|| self.transition_store().contains_input_id(input_id).unwrap_or(true)
9931001
{
994-
return PrepareSpeculateResult::Abort(format!("Double-spending input {input_id}"));
1002+
return ShouldAbortResult::Abort(format!("Double-spending input {input_id}"));
9951003
}
9961004
}
9971005

@@ -1001,7 +1009,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
10011009
if candidate_transaction_details.output_ids.contains(output_id)
10021010
|| self.transition_store().contains_output_id(output_id).unwrap_or(true)
10031011
{
1004-
return PrepareSpeculateResult::Abort(format!("Duplicate output {output_id}"));
1012+
return ShouldAbortResult::Abort(format!("Duplicate output {output_id}"));
10051013
}
10061014
}
10071015

@@ -1012,7 +1020,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
10121020
if candidate_transaction_details.tpks.contains(tpk)
10131021
|| self.transition_store().contains_tpk(tpk).unwrap_or(true)
10141022
{
1015-
return PrepareSpeculateResult::Abort(format!("Duplicate transition public key {tpk}"));
1023+
return ShouldAbortResult::Abort(format!("Duplicate transition public key {tpk}"));
10161024
}
10171025
}
10181026

@@ -1021,7 +1029,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
10211029
// If any public deployment payer has already deployed in this block, abort the transaction.
10221030
if let Some(payer) = fee.payer() {
10231031
if candidate_transaction_details.deployment_payers.contains(&payer) {
1024-
return PrepareSpeculateResult::Abort(format!(
1032+
return ShouldAbortResult::Abort(format!(
10251033
"Another deployment in the block from the same public fee payer {payer}"
10261034
));
10271035
}
@@ -1030,7 +1038,7 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
10301038

10311039
// Before V15, we return without tracking any compute spend.
10321040
if consensus_version < ConsensusVersion::V15 {
1033-
PrepareSpeculateResult::Finalize(0)
1041+
ShouldAbortResult::Finalize(0)
10341042
// If the consensus version is >= V15, ensure that the transaction is not exceeding spend limits.
10351043
} else {
10361044
// Compute microcredit spend from deployment or execution cost details.
@@ -1039,37 +1047,28 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
10391047
match deployment_cost(self.process(), deployment, consensus_version) {
10401048
Ok((_, cost_details)) => deploy_compute_cost_in_microcredits(cost_details, consensus_version),
10411049
Err(e) => {
1042-
return PrepareSpeculateResult::Abort(format!(
1043-
"Failed to compute the deployment cost: {e}"
1044-
));
1050+
return ShouldAbortResult::Abort(format!("Failed to compute the deployment cost: {e}"));
10451051
}
10461052
}
10471053
}
10481054
Transaction::Execute(_, _, execution, _) => {
10491055
match execution_cost(self.process(), execution, consensus_version) {
10501056
Ok((_, cost_details)) => execute_compute_cost_in_microcredits(cost_details, consensus_version),
10511057
Err(e) => {
1052-
return PrepareSpeculateResult::Abort(format!("Failed to compute the execution cost: {e}"));
1058+
return ShouldAbortResult::Abort(format!("Failed to compute the execution cost: {e}"));
10531059
}
10541060
}
10551061
}
10561062
Transaction::Fee(..) => 0, // Fee transactions are already aborted above and don't contribute compute spend.
10571063
};
10581064

10591065
if compute_spend > transaction_spend_limit {
1060-
return PrepareSpeculateResult::Abort(format!(
1066+
return ShouldAbortResult::Abort(format!(
10611067
"Exceeds the transaction spend limit with compute_spend: '{compute_spend}'"
10621068
));
10631069
}
1064-
if let Some(block_spend_limit) = block_spend_limit {
1065-
if block_spend.saturating_add(compute_spend) > block_spend_limit {
1066-
return PrepareSpeculateResult::Abort(format!(
1067-
"Exceeds the block spend limit with compute_spend: '{compute_spend}'"
1068-
));
1069-
}
1070-
}
10711070

1072-
PrepareSpeculateResult::Finalize(compute_spend)
1071+
ShouldAbortResult::Finalize(compute_spend)
10731072
}
10741073
}
10751074

@@ -1092,34 +1091,26 @@ impl<N: Network, C: ConsensusStorage<N>> VM<N, C> {
10921091

10931092
// Accumulate per-block uniqueness checks.
10941093
let mut candidate_transaction_details = CandidateTransactionDetails::<N>::default();
1095-
// Accumulate per-block spend.
1096-
let mut block_spend = 0;
10971094
// Determine the transaction spend limit. These unwraps are safe, see tests in consensus_heights.rs
10981095
let consensus_version = N::CONSENSUS_VERSION(state.block_height()).unwrap();
10991096
let transaction_spend_limit =
11001097
consensus_config_value_by_version!(N, TRANSACTION_SPEND_LIMIT, consensus_version).unwrap();
1101-
// Determine the block spend limit.
1102-
let block_spend_limit = state.block_spend_limit();
11031098

11041099
// Abort duplicate, overspending, invalid, or disallowed transactions before verification.
11051100
for transaction in transactions.iter() {
11061101
match self.should_abort_transaction(
11071102
transaction,
11081103
&candidate_transaction_details,
1109-
block_spend,
11101104
transaction_spend_limit,
1111-
block_spend_limit,
11121105
consensus_version,
11131106
) {
1114-
PrepareSpeculateResult::Abort(abort_reason) => {
1107+
ShouldAbortResult::Abort(abort_reason) => {
11151108
// Store the aborted transaction.
11161109
aborted_transactions.push((*transaction, abort_reason));
11171110
}
1118-
PrepareSpeculateResult::Finalize(compute_spend) => {
1119-
if consensus_version >= ConsensusVersion::V15 {
1120-
// Track the compute_spend used so far.
1121-
block_spend = block_spend.saturating_add(compute_spend);
1122-
}
1111+
// We do not further track the compute spend here, to not count
1112+
// aborted transactions towards the block spend limit.
1113+
ShouldAbortResult::Finalize(_compute_spend) => {
11231114
// Track the accepted transaction details.
11241115
candidate_transaction_details.record_accepted_transaction(transaction);
11251116
// Mark the transaction ready to verify.

0 commit comments

Comments
 (0)