From 592abaed502dab575f870d207b4cbefad5324ae2 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Fri, 8 Nov 2024 20:30:37 +0000 Subject: [PATCH 1/7] Remove inclusion fee from gas settings. --- .../src/core/libraries/ConstantsGen.sol | 25 +++++----- .../enqueued_call_data_validator.nr | 4 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 2 +- .../src/base/private_base_rollup.nr | 3 +- .../crates/types/src/abis/gas_settings.nr | 19 ++------ .../crates/types/src/constants.nr | 3 +- .../types/src/transaction/tx_request.nr | 4 +- .../circuit-types/src/test/factories.ts | 8 ++-- yarn-project/circuits.js/src/constants.gen.ts | 25 +++++----- .../__snapshots__/tx_request.test.ts.snap | 2 +- .../circuits.js/src/structs/gas_settings.ts | 46 ++++--------------- .../src/structs/tx_request.test.ts | 2 +- yarn-project/cli-wallet/src/cmds/cancel_tx.ts | 2 +- yarn-project/cli-wallet/src/cmds/send.ts | 1 - .../cli-wallet/src/utils/options/fees.ts | 17 ++----- .../end-to-end/src/e2e_fees/failures.test.ts | 1 - .../src/type_conversion.ts | 2 - .../src/block_builder/light.test.ts | 3 -- .../src/tx_validator/gas_validator.test.ts | 19 +++----- 19 files changed, 62 insertions(+), 126 deletions(-) diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index ba1a1e96261..2eb54b0ec29 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -116,7 +116,6 @@ library Constants { uint256 internal constant DEFAULT_TEARDOWN_GAS_LIMIT = 12000000; uint256 internal constant MAX_L2_GAS_PER_ENQUEUED_CALL = 12000000; uint256 internal constant DEFAULT_MAX_FEE_PER_GAS = 10; - uint256 internal constant DEFAULT_INCLUSION_FEE = 0; uint256 internal constant DA_BYTES_PER_FIELD = 32; uint256 internal constant DA_GAS_PER_BYTE = 16; uint256 internal constant FIXED_DA_GAS = 512; @@ -160,7 +159,7 @@ library Constants { uint256 internal constant AZTEC_ADDRESS_LENGTH = 1; uint256 internal constant GAS_FEES_LENGTH = 2; uint256 internal constant GAS_LENGTH = 2; - uint256 internal constant GAS_SETTINGS_LENGTH = 7; + uint256 internal constant GAS_SETTINGS_LENGTH = 6; uint256 internal constant CALL_CONTEXT_LENGTH = 4; uint256 internal constant CONTENT_COMMITMENT_LENGTH = 4; uint256 internal constant CONTRACT_INSTANCE_LENGTH = 16; @@ -199,13 +198,13 @@ library Constants { uint256 internal constant ROLLUP_VALIDATION_REQUESTS_LENGTH = 2; uint256 internal constant STATE_REFERENCE_LENGTH = 8; uint256 internal constant TREE_SNAPSHOTS_LENGTH = 8; - uint256 internal constant TX_CONTEXT_LENGTH = 9; - uint256 internal constant TX_REQUEST_LENGTH = 13; + uint256 internal constant TX_CONTEXT_LENGTH = 8; + uint256 internal constant TX_REQUEST_LENGTH = 12; uint256 internal constant TOTAL_FEES_LENGTH = 1; uint256 internal constant HEADER_LENGTH = 24; - uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 500; + uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 499; uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 866; - uint256 internal constant PRIVATE_CONTEXT_INPUTS_LENGTH = 38; + uint256 internal constant PRIVATE_CONTEXT_INPUTS_LENGTH = 37; uint256 internal constant PUBLIC_CONTEXT_INPUTS_LENGTH = 41; uint256 internal constant FEE_RECIPIENT_LENGTH = 2; uint256 internal constant AGGREGATION_OBJECT_LENGTH = 16; @@ -216,19 +215,19 @@ library Constants { uint256 internal constant PUBLIC_VALIDATION_REQUESTS_LENGTH = 834; uint256 internal constant PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 3; uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = 547; - uint256 internal constant TX_CONSTANT_DATA_LENGTH = 35; - uint256 internal constant COMBINED_CONSTANT_DATA_LENGTH = 44; + uint256 internal constant TX_CONSTANT_DATA_LENGTH = 34; + uint256 internal constant COMBINED_CONSTANT_DATA_LENGTH = 43; uint256 internal constant PRIVATE_ACCUMULATED_DATA_LENGTH = 1064; - uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1878; + uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1877; uint256 internal constant PUBLIC_ACCUMULATED_DATA_LENGTH = 1023; uint256 internal constant NUM_PUBLIC_ACCUMULATED_DATA_ARRAYS = 8; uint256 internal constant PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 578; uint256 internal constant PRIVATE_TO_AVM_ACCUMULATED_DATA_LENGTH = 160; uint256 internal constant NUM_PRIVATE_TO_AVM_ACCUMULATED_DATA_ARRAYS = 3; - uint256 internal constant PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1199; - uint256 internal constant PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2932; - uint256 internal constant VM_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2341; - uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 601; + uint256 internal constant PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1198; + uint256 internal constant PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2931; + uint256 internal constant VM_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2340; + uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 600; uint256 internal constant CONSTANT_ROLLUP_DATA_LENGTH = 13; uint256 internal constant BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = 30; uint256 internal constant BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 90; diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/enqueued_call_data_validator.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/enqueued_call_data_validator.nr index e09e427bfeb..abf8c15edf6 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/enqueued_call_data_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/enqueued_call_data_validator.nr @@ -117,9 +117,7 @@ impl EnqueuedCallDataValidator { + previous_kernel.end_non_revertible.gas_used + teardown_gas; let block_gas_fees = self.enqueued_call.data.constants.global_variables.gas_fees; - let inclusion_fee = previous_kernel.constants.tx_context.gas_settings.inclusion_fee; - let computed_transaction_fee = - total_gas_used.compute_fee(block_gas_fees) + inclusion_fee; + let computed_transaction_fee = total_gas_used.compute_fee(block_gas_fees); assert( transaction_fee == computed_transaction_fee, "Transaction fee on teardown phase does not match expected value", diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index b63e3376986..b04375b1df3 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -1445,7 +1445,7 @@ mod tests { builder.fee_payer_fee_juice_balance_pre_existing_public_data_index = Option::some(1); // Set values for computing exact tx_fee - builder.kernel_data.tx_context.gas_settings.inclusion_fee = tx_fee; + builder.transaction_fee = tx_fee; // Set expected protocol data update builder.protocol_public_data_writes.push(( diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr index 0d557a7cf9c..bf4c31a6fee 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr @@ -42,8 +42,7 @@ impl PrivateBaseRollupInputs { fn compute_transaction_fee(self) -> Field { let gas_fees = self.constants.global_variables.gas_fees; let data = self.tube_data.public_inputs; - let inclusion_fee = data.constants.tx_context.gas_settings.inclusion_fee; - inclusion_fee + data.end.gas_used.compute_fee(gas_fees) + data.end.gas_used.compute_fee(gas_fees) } pub fn execute(self) -> BaseOrMergeRollupPublicInputs { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/gas_settings.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/gas_settings.nr index bf31b75ac47..a222eb0215f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/gas_settings.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/gas_settings.nr @@ -1,8 +1,7 @@ use crate::{ abis::{gas::Gas, gas_fees::GasFees}, constants::{ - DEFAULT_GAS_LIMIT, DEFAULT_INCLUSION_FEE, DEFAULT_MAX_FEE_PER_GAS, - DEFAULT_TEARDOWN_GAS_LIMIT, GAS_SETTINGS_LENGTH, + DEFAULT_GAS_LIMIT, DEFAULT_MAX_FEE_PER_GAS, DEFAULT_TEARDOWN_GAS_LIMIT, GAS_SETTINGS_LENGTH, }, traits::{Deserialize, Empty, Serialize}, utils::reader::Reader, @@ -12,17 +11,11 @@ pub struct GasSettings { gas_limits: Gas, teardown_gas_limits: Gas, max_fees_per_gas: GasFees, - inclusion_fee: Field, } impl GasSettings { - pub fn new( - gas_limits: Gas, - teardown_gas_limits: Gas, - max_fees_per_gas: GasFees, - inclusion_fee: Field, - ) -> Self { - Self { gas_limits, teardown_gas_limits, max_fees_per_gas, inclusion_fee } + pub fn new(gas_limits: Gas, teardown_gas_limits: Gas, max_fees_per_gas: GasFees) -> Self { + Self { gas_limits, teardown_gas_limits, max_fees_per_gas } } pub fn default() -> Self { @@ -30,7 +23,6 @@ impl GasSettings { Gas::new(DEFAULT_GAS_LIMIT, DEFAULT_GAS_LIMIT), Gas::new(DEFAULT_TEARDOWN_GAS_LIMIT, DEFAULT_TEARDOWN_GAS_LIMIT), GasFees::new(DEFAULT_MAX_FEE_PER_GAS, DEFAULT_MAX_FEE_PER_GAS), - DEFAULT_INCLUSION_FEE, ) } } @@ -40,13 +32,12 @@ impl Eq for GasSettings { (self.gas_limits == other.gas_limits) & (self.teardown_gas_limits == other.teardown_gas_limits) & (self.max_fees_per_gas == other.max_fees_per_gas) - & (self.inclusion_fee == other.inclusion_fee) } } impl Empty for GasSettings { fn empty() -> Self { - GasSettings::new(Gas::empty(), Gas::empty(), GasFees::empty(), 0) + GasSettings::new(Gas::empty(), Gas::empty(), GasFees::empty()) } } @@ -57,7 +48,6 @@ impl Serialize for GasSettings { serialized.extend_from_array(self.gas_limits.serialize()); serialized.extend_from_array(self.teardown_gas_limits.serialize()); serialized.extend_from_array(self.max_fees_per_gas.serialize()); - serialized.push(self.inclusion_fee); serialized.storage } @@ -70,7 +60,6 @@ impl Deserialize for GasSettings { reader.read_struct(Gas::deserialize), reader.read_struct(Gas::deserialize), reader.read_struct(GasFees::deserialize), - reader.read(), ) } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index c1881a4675b..3e60e8e9247 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -179,7 +179,6 @@ pub global DEFAULT_GAS_LIMIT: u32 = 1_000_000_000; pub global DEFAULT_TEARDOWN_GAS_LIMIT: u32 = 12_000_000; pub global MAX_L2_GAS_PER_ENQUEUED_CALL: u32 = 12_000_000; pub global DEFAULT_MAX_FEE_PER_GAS: Field = 10; -pub global DEFAULT_INCLUSION_FEE: Field = 0; pub global DA_BYTES_PER_FIELD: u32 = 32; pub global DA_GAS_PER_BYTE: u32 = 16; // pays for preamble information in TX Effects @@ -253,7 +252,7 @@ pub global DEFAULT_TPK_M_Y = 0x2039907fe37f08d10739255141bb066c506a12f7d1e8dfec2 pub global AZTEC_ADDRESS_LENGTH: u32 = 1; pub global GAS_FEES_LENGTH: u32 = 2; pub global GAS_LENGTH: u32 = 2; -pub global GAS_SETTINGS_LENGTH: u32 = GAS_LENGTH * 2 + GAS_FEES_LENGTH + /* inclusion_fee */ 1; +pub global GAS_SETTINGS_LENGTH: u32 = GAS_LENGTH * 2 + GAS_FEES_LENGTH; pub global CALL_CONTEXT_LENGTH: u32 = 4; pub global CONTENT_COMMITMENT_LENGTH: u32 = 4; pub global CONTRACT_INSTANCE_LENGTH: u32 = 16; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr index aad7f1db2ff..3e17851cda8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr @@ -93,7 +93,7 @@ mod tests { #[test] fn compute_hash() { - let gas_settings = GasSettings::new(Gas::new(2, 2), Gas::new(1, 1), GasFees::new(3, 3), 10); + let gas_settings = GasSettings::new(Gas::new(2, 2), Gas::new(1, 1), GasFees::new(3, 3)); let tx_request = TxRequest { origin: AztecAddress::from_field(1), args_hash: 3, @@ -105,7 +105,7 @@ mod tests { }; // Value from tx_request.test.ts "compute hash" test let test_data_tx_request_hash = - 0x289d3f85f463f3449e2204433b860574d351e9fbd97a01a722239fdd9ce3ce9b; + 0x1b15ac8432c3c35718075a277d86f11263f057e2325afa208d6b19e37ff59a8d; assert(tx_request.hash() == test_data_tx_request_hash); } } diff --git a/yarn-project/circuit-types/src/test/factories.ts b/yarn-project/circuit-types/src/test/factories.ts index e183779e0e7..98f10b3ecaf 100644 --- a/yarn-project/circuit-types/src/test/factories.ts +++ b/yarn-project/circuit-types/src/test/factories.ts @@ -9,6 +9,8 @@ import { AvmCircuitInputs, AvmCircuitPublicInputs, AvmExecutionHints, + FIXED_DA_GAS, + FIXED_L2_GAS, Fr, Gas, GasSettings, @@ -81,9 +83,9 @@ export function makeBloatedProcessedTx({ // Private-only tx has no public data writes. data.publicDataWrites.forEach((_, i) => (data.publicDataWrites[i] = PublicDataWrite.empty())); - // Make the gasUsed empty so that transaction fee is simply the inclusion fee. - data.gasUsed = Gas.empty(); - const transactionFee = gasSettings.inclusionFee; + // No side effects were created in mockTx. The default gasUsed is the tx overhead. + data.gasUsed = Gas.from({ daGas: FIXED_DA_GAS, l2Gas: FIXED_L2_GAS }); + const transactionFee = data.gasUsed.computeFee(globalVariables.gasFees); clearLogs(data); diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 4ce28482488..5c4dc7f9b67 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -102,7 +102,6 @@ export const DEFAULT_GAS_LIMIT = 1000000000; export const DEFAULT_TEARDOWN_GAS_LIMIT = 12000000; export const MAX_L2_GAS_PER_ENQUEUED_CALL = 12000000; export const DEFAULT_MAX_FEE_PER_GAS = 10; -export const DEFAULT_INCLUSION_FEE = 0; export const DA_BYTES_PER_FIELD = 32; export const DA_GAS_PER_BYTE = 16; export const FIXED_DA_GAS = 512; @@ -138,7 +137,7 @@ export const DEFAULT_TPK_M_Y = 1457571873670220605010242502922942621563166447116 export const AZTEC_ADDRESS_LENGTH = 1; export const GAS_FEES_LENGTH = 2; export const GAS_LENGTH = 2; -export const GAS_SETTINGS_LENGTH = 7; +export const GAS_SETTINGS_LENGTH = 6; export const CALL_CONTEXT_LENGTH = 4; export const CONTENT_COMMITMENT_LENGTH = 4; export const CONTRACT_INSTANCE_LENGTH = 16; @@ -177,13 +176,13 @@ export const PUBLIC_INNER_CALL_REQUEST_LENGTH = 13; export const ROLLUP_VALIDATION_REQUESTS_LENGTH = 2; export const STATE_REFERENCE_LENGTH = 8; export const TREE_SNAPSHOTS_LENGTH = 8; -export const TX_CONTEXT_LENGTH = 9; -export const TX_REQUEST_LENGTH = 13; +export const TX_CONTEXT_LENGTH = 8; +export const TX_REQUEST_LENGTH = 12; export const TOTAL_FEES_LENGTH = 1; export const HEADER_LENGTH = 24; -export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 500; +export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 499; export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 866; -export const PRIVATE_CONTEXT_INPUTS_LENGTH = 38; +export const PRIVATE_CONTEXT_INPUTS_LENGTH = 37; export const PUBLIC_CONTEXT_INPUTS_LENGTH = 41; export const FEE_RECIPIENT_LENGTH = 2; export const AGGREGATION_OBJECT_LENGTH = 16; @@ -194,20 +193,20 @@ export const NUM_PUBLIC_VALIDATION_REQUEST_ARRAYS = 5; export const PUBLIC_VALIDATION_REQUESTS_LENGTH = 834; export const PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 3; export const COMBINED_ACCUMULATED_DATA_LENGTH = 547; -export const TX_CONSTANT_DATA_LENGTH = 35; -export const COMBINED_CONSTANT_DATA_LENGTH = 44; +export const TX_CONSTANT_DATA_LENGTH = 34; +export const COMBINED_CONSTANT_DATA_LENGTH = 43; export const PRIVATE_ACCUMULATED_DATA_LENGTH = 1064; -export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1878; +export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1877; export const PUBLIC_ACCUMULATED_DATA_LENGTH = 1023; export const NUM_PUBLIC_ACCUMULATED_DATA_ARRAYS = 8; export const PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 578; export const PRIVATE_TO_AVM_ACCUMULATED_DATA_LENGTH = 160; export const NUM_PRIVATE_TO_AVM_ACCUMULATED_DATA_ARRAYS = 3; export const AVM_ACCUMULATED_DATA_LENGTH = 318; -export const PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1199; -export const PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2932; -export const VM_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2341; -export const KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 601; +export const PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1198; +export const PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2931; +export const VM_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2340; +export const KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 600; export const CONSTANT_ROLLUP_DATA_LENGTH = 13; export const BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = 30; export const BLOCK_ROOT_OR_BLOCK_MERGE_PUBLIC_INPUTS_LENGTH = 90; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap index cb781f1df87..89e87fba81d 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TxRequest compute hash 1`] = `"0x289d3f85f463f3449e2204433b860574d351e9fbd97a01a722239fdd9ce3ce9b"`; +exports[`TxRequest compute hash 1`] = `"0x1b15ac8432c3c35718075a277d86f11263f057e2325afa208d6b19e37ff59a8d"`; diff --git a/yarn-project/circuits.js/src/structs/gas_settings.ts b/yarn-project/circuits.js/src/structs/gas_settings.ts index 8c2b6860efc..5aea15de631 100644 --- a/yarn-project/circuits.js/src/structs/gas_settings.ts +++ b/yarn-project/circuits.js/src/structs/gas_settings.ts @@ -5,7 +5,6 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { DEFAULT_GAS_LIMIT, - DEFAULT_INCLUSION_FEE, DEFAULT_MAX_FEE_PER_GAS, DEFAULT_TEARDOWN_GAS_LIMIT, GAS_SETTINGS_LENGTH, @@ -19,34 +18,22 @@ export class GasSettings { public readonly gasLimits: Gas, public readonly teardownGasLimits: Gas, public readonly maxFeesPerGas: GasFees, - public readonly inclusionFee: Fr, ) {} getSize(): number { return this.toBuffer().length; } - static from(args: { - gasLimits: FieldsOf; - teardownGasLimits: FieldsOf; - maxFeesPerGas: FieldsOf; - inclusionFee: Fr; - }) { + static from(args: { gasLimits: FieldsOf; teardownGasLimits: FieldsOf; maxFeesPerGas: FieldsOf }) { return new GasSettings( Gas.from(args.gasLimits), Gas.from(args.teardownGasLimits), GasFees.from(args.maxFeesPerGas), - args.inclusionFee, ); } clone() { - return new GasSettings( - this.gasLimits.clone(), - this.teardownGasLimits.clone(), - this.maxFeesPerGas.clone(), - this.inclusionFee, - ); + return new GasSettings(this.gasLimits.clone(), this.teardownGasLimits.clone(), this.maxFeesPerGas.clone()); } /** Returns the maximum fee to be paid according to gas limits and max fees set. */ @@ -58,12 +45,12 @@ export class GasSettings { .mul(new Fr(this.gasLimits.get(dimension))) .add(acc), Fr.ZERO, - ).add(this.inclusionFee); + ); } /** Zero-value gas settings. */ static empty() { - return new GasSettings(Gas.empty(), Gas.empty(), GasFees.empty(), Fr.ZERO); + return new GasSettings(Gas.empty(), Gas.empty(), GasFees.empty()); } /** Default gas settings to use when user has not provided them. */ @@ -72,7 +59,6 @@ export class GasSettings { gasLimits: { l2Gas: DEFAULT_GAS_LIMIT, daGas: DEFAULT_GAS_LIMIT }, teardownGasLimits: { l2Gas: DEFAULT_TEARDOWN_GAS_LIMIT, daGas: DEFAULT_TEARDOWN_GAS_LIMIT }, maxFeesPerGas: { feePerL2Gas: new Fr(DEFAULT_MAX_FEE_PER_GAS), feePerDaGas: new Fr(DEFAULT_MAX_FEE_PER_GAS) }, - inclusionFee: new Fr(DEFAULT_INCLUSION_FEE), ...compact(overrides), }); } @@ -88,31 +74,20 @@ export class GasSettings { } isEmpty() { - return ( - this.gasLimits.isEmpty() && - this.teardownGasLimits.isEmpty() && - this.maxFeesPerGas.isEmpty() && - this.inclusionFee.isZero() - ); + return this.gasLimits.isEmpty() && this.teardownGasLimits.isEmpty() && this.maxFeesPerGas.isEmpty(); } equals(other: GasSettings) { return ( this.gasLimits.equals(other.gasLimits) && this.teardownGasLimits.equals(other.teardownGasLimits) && - this.maxFeesPerGas.equals(other.maxFeesPerGas) && - this.inclusionFee.equals(other.inclusionFee) + this.maxFeesPerGas.equals(other.maxFeesPerGas) ); } static fromBuffer(buffer: Buffer | BufferReader): GasSettings { const reader = BufferReader.asReader(buffer); - return new GasSettings( - reader.readObject(Gas), - reader.readObject(Gas), - reader.readObject(GasFees), - reader.readObject(Fr), - ); + return new GasSettings(reader.readObject(Gas), reader.readObject(Gas), reader.readObject(GasFees)); } toBuffer() { @@ -121,12 +96,7 @@ export class GasSettings { static fromFields(fields: Fr[] | FieldReader): GasSettings { const reader = FieldReader.asReader(fields); - return new GasSettings( - reader.readObject(Gas), - reader.readObject(Gas), - reader.readObject(GasFees), - reader.readField(), - ); + return new GasSettings(reader.readObject(Gas), reader.readObject(Gas), reader.readObject(GasFees)); } toFields(): Fr[] { diff --git a/yarn-project/circuits.js/src/structs/tx_request.test.ts b/yarn-project/circuits.js/src/structs/tx_request.test.ts index b7ef15246a3..8c97cd8e0f4 100644 --- a/yarn-project/circuits.js/src/structs/tx_request.test.ts +++ b/yarn-project/circuits.js/src/structs/tx_request.test.ts @@ -34,7 +34,7 @@ describe('TxRequest', () => { }); it('compute hash', () => { - const gasSettings = new GasSettings(new Gas(2, 2), new Gas(1, 1), new GasFees(3, 3), new Fr(10)); + const gasSettings = new GasSettings(new Gas(2, 2), new Gas(1, 1), new GasFees(3, 3)); const txRequest = TxRequest.from({ origin: AztecAddress.fromBigInt(1n), functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), /*isPrivate=*/ true), diff --git a/yarn-project/cli-wallet/src/cmds/cancel_tx.ts b/yarn-project/cli-wallet/src/cmds/cancel_tx.ts index 220caa0913e..a37d76235d5 100644 --- a/yarn-project/cli-wallet/src/cmds/cancel_tx.ts +++ b/yarn-project/cli-wallet/src/cmds/cancel_tx.ts @@ -25,7 +25,7 @@ export async function cancelTx( gasSettings, }; - gasSettings.inclusionFee.mul(new Fr(2)); + // TODO(#9805): Increase max_priority_fee_per_gas. const txRequest = await wallet.createTxExecutionRequest({ calls: [], diff --git a/yarn-project/cli-wallet/src/cmds/send.ts b/yarn-project/cli-wallet/src/cmds/send.ts index 55872802cc0..fa6af43fa93 100644 --- a/yarn-project/cli-wallet/src/cmds/send.ts +++ b/yarn-project/cli-wallet/src/cmds/send.ts @@ -52,7 +52,6 @@ export async function send( const gasSettings = GasSettings.from({ ...gasLimits, maxFeesPerGas: feeOpts.gasSettings.maxFeesPerGas, - inclusionFee: feeOpts.gasSettings.inclusionFee, }); return { txHash, diff --git a/yarn-project/cli-wallet/src/utils/options/fees.ts b/yarn-project/cli-wallet/src/utils/options/fees.ts index 7e28e8823a8..00226cfe64b 100644 --- a/yarn-project/cli-wallet/src/utils/options/fees.ts +++ b/yarn-project/cli-wallet/src/utils/options/fees.ts @@ -19,7 +19,6 @@ import { aliasedAddressParser } from './index.js'; export type CliFeeArgs = { estimateGasOnly: boolean; - inclusionFee?: bigint; gasLimits?: string; payment?: string; estimateGas?: boolean; @@ -36,9 +35,8 @@ export function printGasEstimates( gasEstimates: Pick, log: LogFn, ) { - const inclusionFee = feeOpts.gasSettings.inclusionFee; - log(`Maximum total tx fee: ${getEstimatedCost(gasEstimates, inclusionFee, GasSettings.default().maxFeesPerGas)}`); - log(`Estimated total tx fee: ${getEstimatedCost(gasEstimates, inclusionFee, GasFees.default())}`); + log(`Maximum total tx fee: ${getEstimatedCost(gasEstimates, GasSettings.default().maxFeesPerGas)}`); + log(`Estimated total tx fee: ${getEstimatedCost(gasEstimates, GasFees.default())}`); log(`Estimated gas usage: ${formatGasEstimate(gasEstimates)}`); } @@ -46,12 +44,8 @@ function formatGasEstimate(estimate: Pick, - inclusionFee: Fr, - fees: GasFees, -) { - return GasSettings.from({ ...GasSettings.default(), ...estimate, inclusionFee, maxFeesPerGas: fees }) +function getEstimatedCost(estimate: Pick, fees: GasFees) { + return GasSettings.from({ ...GasSettings.default(), ...estimate, maxFeesPerGas: fees }) .getFeeLimit() .toBigInt(); } @@ -93,13 +87,12 @@ export class FeeOpts implements IFeeOpts { static fromCli(args: CliFeeArgs, log: LogFn, db?: WalletDB) { const estimateOnly = args.estimateGasOnly; - if (!args.inclusionFee && !args.gasLimits && !args.payment) { + if (!args.gasLimits && !args.payment) { return new NoFeeOpts(estimateOnly); } const gasSettings = GasSettings.from({ ...GasSettings.default(), ...(args.gasLimits ? parseGasLimits(args.gasLimits) : {}), - ...(args.inclusionFee ? { inclusionFee: new Fr(args.inclusionFee) } : {}), maxFeesPerGas: GasFees.default(), }); return new FeeOpts( diff --git a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts index de795199b97..389c7392b4a 100644 --- a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts @@ -262,7 +262,6 @@ describe('e2e_fees failures', () => { const badGas = GasSettings.from({ gasLimits: gasSettings.gasLimits, - inclusionFee: gasSettings.inclusionFee, maxFeesPerGas: gasSettings.maxFeesPerGas, teardownGasLimits: Gas.empty(), }); diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 4d4a5bc4c89..e612e5413ef 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -532,7 +532,6 @@ export function mapGasSettingsFromNoir(gasSettings: GasSettingsNoir): GasSetting mapGasFromNoir(gasSettings.gas_limits), mapGasFromNoir(gasSettings.teardown_gas_limits), mapGasFeesFromNoir(gasSettings.max_fees_per_gas), - mapFieldFromNoir(gasSettings.inclusion_fee), ); } @@ -541,7 +540,6 @@ export function mapGasSettingsToNoir(gasSettings: GasSettings): GasSettingsNoir gas_limits: mapGasToNoir(gasSettings.gasLimits), teardown_gas_limits: mapGasToNoir(gasSettings.teardownGasLimits), max_fees_per_gas: mapGasFeesToNoir(gasSettings.maxFeesPerGas), - inclusion_fee: mapFieldToNoir(gasSettings.inclusionFee), }; } diff --git a/yarn-project/sequencer-client/src/block_builder/light.test.ts b/yarn-project/sequencer-client/src/block_builder/light.test.ts index e4a636f2e00..a09eb9579dd 100644 --- a/yarn-project/sequencer-client/src/block_builder/light.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/light.test.ts @@ -13,7 +13,6 @@ import { BaseParityInputs, BlockRootRollupInputs, Fr, - GasSettings, type GlobalVariables, L1_TO_L2_MSG_SUBTREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, @@ -182,13 +181,11 @@ describe('LightBlockBuilder', () => { expect(header).toEqual(expectedHeader); }); - // Makes a tx with a non-zero inclusion fee for testing const makeTx = (i: number) => makeBloatedProcessedTx({ header: fork.getInitialHeader(), chainId: globals.chainId, version: globals.version, - gasSettings: GasSettings.default({ inclusionFee: new Fr(i + 1) }), vkTreeRoot, protocolContractTreeRoot, seed: i + 1, diff --git a/yarn-project/sequencer-client/src/tx_validator/gas_validator.test.ts b/yarn-project/sequencer-client/src/tx_validator/gas_validator.test.ts index 9ba6ea80930..86cb9e9877c 100644 --- a/yarn-project/sequencer-client/src/tx_validator/gas_validator.test.ts +++ b/yarn-project/sequencer-client/src/tx_validator/gas_validator.test.ts @@ -26,20 +26,15 @@ describe('GasTxValidator', () => { let tx: Tx; let payer: AztecAddress; let expectedBalanceSlot: Fr; - - const TX_FEE = 100n; + let feeLimit = 0n; beforeEach(() => { tx = mockTx(1, { numberOfNonRevertiblePublicCallRequests: 2 }); tx.data.feePayer = AztecAddress.random(); - tx.data.constants.txContext.gasSettings = GasSettings.from({ - ...GasSettings.empty(), - inclusionFee: new Fr(TX_FEE), - }); + tx.data.constants.txContext.gasSettings = GasSettings.default(); payer = tx.data.feePayer; expectedBalanceSlot = poseidon2Hash([FeeJuiceContract.storage.balances.slot, payer]); - - expect(tx.data.constants.txContext.gasSettings.getFeeLimit()).toEqual(new Fr(TX_FEE)); + feeLimit = tx.data.constants.txContext.gasSettings.getFeeLimit().toBigInt(); }); const mockBalance = (balance: bigint) => { @@ -61,12 +56,12 @@ describe('GasTxValidator', () => { }; it('allows fee paying txs if fee payer has enough balance', async () => { - mockBalance(TX_FEE); + mockBalance(feeLimit); await expectValidateSuccess(tx); }); it('allows fee paying txs if fee payer claims enough balance during setup', async () => { - mockBalance(TX_FEE - 1n); + mockBalance(feeLimit - 1n); const selector = FunctionSelector.fromSignature('_increase_public_balance((Field),Field)'); patchNonRevertibleFn(tx, 0, { address: ProtocolContractAddress.FeeJuice, @@ -78,7 +73,7 @@ describe('GasTxValidator', () => { }); it('rejects txs if fee payer has not enough balance', async () => { - mockBalance(TX_FEE - 1n); + mockBalance(feeLimit - 1n); await expectValidateFail(tx); }); @@ -87,7 +82,7 @@ describe('GasTxValidator', () => { }); it('rejects txs if fee payer claims balance outside setup', async () => { - mockBalance(TX_FEE - 1n); + mockBalance(feeLimit - 1n); patchRevertibleFn(tx, 0, { selector: FunctionSelector.fromSignature('_increase_public_balance((Field),Field)'), args: [payer, new Fr(1n)], From 28c8e4476fcfd9e427a0ce342e24d240cd58f80f Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 11 Nov 2024 15:40:30 +0000 Subject: [PATCH 2/7] Estimate gas and fee in enqueued call processor. --- .../enqueued_call_data_validator.nr | 127 --- .../public-kernel-lib/src/components/mod.nr | 1 - .../public_kernel_output_composer.nr | 11 - .../src/public_kernel_merge.nr | 11 +- .../circuit-types/src/tx/processed_tx.ts | 2 +- yarn-project/circuits.js/src/structs/gas.ts | 6 - .../circuits.js/src/structs/gas_settings.ts | 17 +- .../private_to_public_accumulated_data.ts | 16 +- .../src/e2e_fees/gas_estimation.test.ts | 51 +- .../src/protocol_contract_data.ts | 14 +- .../src/tx_validator/gas_validator.ts | 4 +- .../src/tx_validator/phases_validator.ts | 4 +- yarn-project/simulator/src/mocks/fixtures.ts | 2 +- .../src/public/enqueued_call_simulator.ts | 26 +- .../public/enqueued_calls_processor.test.ts | 883 +++++++++--------- .../src/public/enqueued_calls_processor.ts | 195 ++-- .../src/public/public_processor.test.ts | 468 ++++------ .../simulator/src/public/public_processor.ts | 39 +- .../src/public/public_processor_metrics.ts | 6 +- yarn-project/txe/src/oracle/txe_oracle.ts | 4 +- 20 files changed, 787 insertions(+), 1100 deletions(-) delete mode 100644 noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/enqueued_call_data_validator.nr diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/enqueued_call_data_validator.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/enqueued_call_data_validator.nr deleted file mode 100644 index abf8c15edf6..00000000000 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/enqueued_call_data_validator.nr +++ /dev/null @@ -1,127 +0,0 @@ -use crate::public_kernel_phase::PublicKernelPhase; -use dep::types::{ - abis::{ - accumulated_data::PublicAccumulatedDataArrayLengths, enqueued_call_data::EnqueuedCallData, - kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, - public_call_request::PublicCallRequest, - validation_requests::PublicValidationRequestArrayLengths, - }, - constants::MAX_L2_GAS_PER_ENQUEUED_CALL, - utils::arrays::array_length, -}; - -pub struct EnqueuedCallDataValidator { - enqueued_call: EnqueuedCallData, - phase: u8, -} - -impl EnqueuedCallDataValidator { - pub fn new(enqueued_call: EnqueuedCallData, phase: u8) -> Self { - EnqueuedCallDataValidator { enqueued_call, phase } - } - - pub fn validate(self) { - self.validate_revert_flag() - } - - pub fn validate_against_previous_kernel( - self, - previous_kernel: PublicKernelCircuitPublicInputs, - ) { - self.validate_global_variables(previous_kernel); - self.validate_against_call_request(previous_kernel); - self.validate_start_gas(previous_kernel); - self.validate_transaction_fee(previous_kernel); - } - - fn validate_revert_flag(self) { - if self.phase == PublicKernelPhase.SETUP { - assert_eq(self.enqueued_call.data.reverted, false, "Public call cannot be reverted"); - } - } - - fn validate_global_variables(self, previous_kernel: PublicKernelCircuitPublicInputs) { - let prev_global_variables = previous_kernel.constants.global_variables; - if !prev_global_variables.is_empty() { - // It's empty when the previous kernel is from private_kernel_tail_to_pubic. - let enqueued_call_globals = self.enqueued_call.data.constants.global_variables; - assert_eq( - enqueued_call_globals, - prev_global_variables, - "Global variables injected into the public call do not match constants", - ); - } - } - - fn validate_against_call_request(self, previous_kernel: PublicKernelCircuitPublicInputs) { - let call_request = if self.phase == PublicKernelPhase.SETUP { - let call_stack = previous_kernel.end_non_revertible.public_call_stack; - call_stack[array_length(call_stack) - 1] - } else if self.phase == PublicKernelPhase.APP_LOGIC { - let call_stack = previous_kernel.end.public_call_stack; - call_stack[array_length(call_stack) - 1] - } else if self.phase == PublicKernelPhase.TEARDOWN { - previous_kernel.public_teardown_call_request - } else { - assert(false, "Unknown phase"); - PublicCallRequest::empty() - }; - - assert( - self.enqueued_call.data.call_request == call_request, - "enqueued call does not match item at the top of the call stack", - ); - } - - // Validates that the start gas injected into the vm circuit matches the remaining gas. - fn validate_start_gas(self, previous_kernel: PublicKernelCircuitPublicInputs) { - let enqueued_call_start_gas = self.enqueued_call.data.start_gas_left; - // NOTE: the AVM circuit will fail to generate a proof if its "start gas" is > MAX_L2_GAS_PER_ENQUEUED_CALL, - // so the kernel never allocates more than that maximum to one enqueued call. - if self.phase != PublicKernelPhase.TEARDOWN { - // An enqueued call's start gas is the remaining gas left in the transaction after the previous kernel. - let tx_gas_limits = previous_kernel.constants.tx_context.gas_settings.gas_limits; - let mut computed_start_gas = tx_gas_limits.sub(previous_kernel.end.gas_used).sub( - previous_kernel.end_non_revertible.gas_used, - ); - // Keep L2 gas below max - computed_start_gas.l2_gas = - std::cmp::min(computed_start_gas.l2_gas, MAX_L2_GAS_PER_ENQUEUED_CALL); - assert_eq( - enqueued_call_start_gas, - computed_start_gas, - "Start gas for enqueued call does not match transaction gas left (with MAX_L2_GAS_PER_ENQUEUED_CALL applied)", - ); - } else { - let mut teardown_gas_limit = - previous_kernel.constants.tx_context.gas_settings.teardown_gas_limits; - // Keep L2 gas below max - teardown_gas_limit.l2_gas = - std::cmp::min(teardown_gas_limit.l2_gas, MAX_L2_GAS_PER_ENQUEUED_CALL); - assert_eq( - enqueued_call_start_gas, - teardown_gas_limit, - "Start gas for enqueued call does not match teardown gas allocation (with MAX_L2_GAS_PER_ENQUEUED_CALL applied)", - ); - } - } - - fn validate_transaction_fee(self, previous_kernel: PublicKernelCircuitPublicInputs) { - let transaction_fee = self.enqueued_call.data.transaction_fee; - if self.phase != PublicKernelPhase.TEARDOWN { - assert_eq(transaction_fee, 0, "Transaction fee must be zero on setup and app phases"); - } else { - let teardown_gas = - previous_kernel.constants.tx_context.gas_settings.teardown_gas_limits; - let total_gas_used = previous_kernel.end.gas_used - + previous_kernel.end_non_revertible.gas_used - + teardown_gas; - let block_gas_fees = self.enqueued_call.data.constants.global_variables.gas_fees; - let computed_transaction_fee = total_gas_used.compute_fee(block_gas_fees); - assert( - transaction_fee == computed_transaction_fee, - "Transaction fee on teardown phase does not match expected value", - ); - } - } -} diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/mod.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/mod.nr index ffaa2d88a5c..fbccb685e14 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/mod.nr @@ -1,3 +1,2 @@ -mod enqueued_call_data_validator; mod public_kernel_output_composer; mod public_tail_output_composer; diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer.nr index 0c982cd789d..bb35add7cf7 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_kernel_output_composer.nr @@ -49,7 +49,6 @@ impl PublicKernelOutputComposer { self.propagate_validation_requests(enqueued_call); self.propagate_accumulated_data(enqueued_call, phase); self.propagate_end_side_effect_counter(enqueued_call); - self.update_gas_used(enqueued_call, phase); *self } @@ -154,14 +153,4 @@ impl PublicKernelOutputComposer { fn propagate_end_side_effect_counter(&mut self, enqueued_call: VMCircuitPublicInputs) { self.output_builder.end_side_effect_counter = enqueued_call.end_side_effect_counter; } - - fn update_gas_used(&mut self, enqueued_call: VMCircuitPublicInputs, phase: u8) { - let call_gas_used = enqueued_call.accumulated_data.gas_used; - if phase == PublicKernelPhase.SETUP { - self.output_builder.end_non_revertible.gas_used += call_gas_used; - } - if phase == PublicKernelPhase.APP_LOGIC { - self.output_builder.end.gas_used += call_gas_used; - } - } } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_merge.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_merge.nr index 34bf781b17a..72213f0b032 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_merge.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_merge.nr @@ -1,8 +1,5 @@ use crate::{ - components::{ - enqueued_call_data_validator::EnqueuedCallDataValidator, - public_kernel_output_composer::PublicKernelOutputComposer, - }, + components::public_kernel_output_composer::PublicKernelOutputComposer, public_kernel_phase::PublicKernelPhase, }; use dep::types::abis::{ @@ -34,12 +31,6 @@ impl PublicKernelMergeCircuitPrivateInputs { fn execute(self) -> PublicKernelCircuitPublicInputs { let phase = self.get_phase(); - let enqueued_call_data_validator = - EnqueuedCallDataValidator::new(self.enqueued_call, phase); - enqueued_call_data_validator.validate_against_previous_kernel( - self.previous_kernel.public_inputs, - ); - PublicKernelOutputComposer::new_from_previous_kernel(self.previous_kernel.public_inputs) .remove_top_call_request(phase) .propagate_from_enqueued_call(self.enqueued_call.data, phase) diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index 80c9cb665c9..7265cda02fa 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -15,7 +15,7 @@ import { siloL2ToL1Message } from '@aztec/circuits.js/hash'; import { type GasUsed } from './gas_used.js'; -export enum PublicKernelPhase { +export enum TxExecutionPhase { SETUP, APP_LOGIC, TEARDOWN, diff --git a/yarn-project/circuits.js/src/structs/gas.ts b/yarn-project/circuits.js/src/structs/gas.ts index 7e1f7469492..b8e77ad4a9a 100644 --- a/yarn-project/circuits.js/src/structs/gas.ts +++ b/yarn-project/circuits.js/src/structs/gas.ts @@ -4,7 +4,6 @@ import { type FieldsOf } from '@aztec/foundation/types'; import { inspect } from 'util'; -import { MAX_L2_GAS_PER_ENQUEUED_CALL } from '../constants.gen.js'; import { type GasFees } from './gas_fees.js'; import { type UInt32 } from './shared.js'; @@ -35,11 +34,6 @@ export class Gas { return new Gas(0, 0); } - /** Returns large enough gas amounts for testing purposes. */ - static test() { - return new Gas(1e9, MAX_L2_GAS_PER_ENQUEUED_CALL); - } - isEmpty() { return this.daGas === 0 && this.l2Gas === 0; } diff --git a/yarn-project/circuits.js/src/structs/gas_settings.ts b/yarn-project/circuits.js/src/structs/gas_settings.ts index 5aea15de631..65952d91dbe 100644 --- a/yarn-project/circuits.js/src/structs/gas_settings.ts +++ b/yarn-project/circuits.js/src/structs/gas_settings.ts @@ -110,21 +110,6 @@ export class GasSettings { } static getFields(fields: FieldsOf) { - return [fields.gasLimits, fields.teardownGasLimits, fields.maxFeesPerGas, fields.inclusionFee] as const; - } - - /** Returns total gas limits. */ - getLimits(): Gas { - return this.gasLimits; - } - - /** Returns how much gas is available for execution of setup and app phases (ie total limit minus teardown). */ - getInitialAvailable(): Gas { - return this.gasLimits.sub(this.teardownGasLimits); - } - - /** Returns how much gas is available for execution of teardown phase. */ - getTeardownLimits(): Gas { - return this.teardownGasLimits; + return [fields.gasLimits, fields.teardownGasLimits, fields.maxFeesPerGas] as const; } } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts index 0573ec8d875..6db4c8979ae 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts @@ -21,14 +21,14 @@ import { PublicCallRequest } from '../public_call_request.js'; export class PrivateToPublicAccumulatedData { constructor( - public readonly noteHashes: Tuple, - public readonly nullifiers: Tuple, - public readonly l2ToL1Msgs: Tuple, - public readonly noteEncryptedLogsHashes: Tuple, - public readonly encryptedLogsHashes: Tuple, - public readonly unencryptedLogsHashes: Tuple, - public readonly publicCallRequests: Tuple, - public readonly gasUsed: Gas, + public noteHashes: Tuple, + public nullifiers: Tuple, + public l2ToL1Msgs: Tuple, + public noteEncryptedLogsHashes: Tuple, + public encryptedLogsHashes: Tuple, + public unencryptedLogsHashes: Tuple, + public publicCallRequests: Tuple, + public gasUsed: Gas, ) {} getSize() { diff --git a/yarn-project/end-to-end/src/e2e_fees/gas_estimation.test.ts b/yarn-project/end-to-end/src/e2e_fees/gas_estimation.test.ts index 6ace7c6333e..862bdc387cb 100644 --- a/yarn-project/end-to-end/src/e2e_fees/gas_estimation.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/gas_estimation.test.ts @@ -5,7 +5,7 @@ import { type FeePaymentMethod, PublicFeePaymentMethod, } from '@aztec/aztec.js'; -import { GasFees, type GasSettings } from '@aztec/circuits.js'; +import { Gas, GasFees, type GasSettings } from '@aztec/circuits.js'; import { type Logger } from '@aztec/foundation/log'; import { TokenContract as BananaCoin, type FPCContract } from '@aztec/noir-contracts.js'; @@ -52,18 +52,24 @@ describe('e2e_fees gas_estimation', () => { ), ); - const getFeeFromEstimatedGas = (estimatedGas: Pick) => - gasSettings.inclusionFee - .add(estimatedGas.gasLimits.computeFee(GasFees.default())) - .add(estimatedGas.teardownGasLimits.computeFee(GasFees.default())) - .toBigInt(); - const logGasEstimate = (estimatedGas: Pick) => logger.info(`Estimated gas at`, { gasLimits: inspect(estimatedGas.gasLimits), teardownGasLimits: inspect(estimatedGas.teardownGasLimits), }); + const expectGreaterFeeFromEstimatedGas = ( + estimatedGas: Pick, + actualFee: bigint, + ) => { + const feeFromEstimatedGas = estimatedGas.gasLimits.computeFee(GasFees.default()).toBigInt(); + + // The actual fee should be under the estimate, since we add 10% by default to the estimated gas (see aztec.js/src/contract/get_gas_limits.ts). + const adjustedForFloatingPoint = new Gas(1, 1).computeFee(GasFees.default()).toBigInt(); + expect(feeFromEstimatedGas).toBeLessThanOrEqual((actualFee * 110n) / 100n + adjustedForFloatingPoint); + expect(feeFromEstimatedGas).toBeGreaterThan(actualFee); + }; + it('estimates gas with Fee Juice payment method', async () => { const paymentMethod = new FeeJuicePaymentMethod(aliceAddress); const estimatedGas = await makeTransferRequest().estimateGas({ fee: { gasSettings, paymentMethod } }); @@ -72,19 +78,15 @@ describe('e2e_fees gas_estimation', () => { const [withEstimate, withoutEstimate] = await sendTransfers(paymentMethod); const actualFee = withEstimate.transactionFee!; - // Estimation should yield that teardown has no cost, so should send the tx with zero for teardown - expect(actualFee + teardownFixedFee).toEqual(withoutEstimate.transactionFee!); + // Tx has no teardown cost, so both fees should just reflect the actual gas cost. + expect(actualFee).toEqual(withoutEstimate.transactionFee!); // Check that estimated gas for teardown are zero expect(estimatedGas.teardownGasLimits.l2Gas).toEqual(0); expect(estimatedGas.teardownGasLimits.daGas).toEqual(0); // Check that the estimate was close to the actual gas used by recomputing the tx fee from it - const feeFromEstimatedGas = getFeeFromEstimatedGas(estimatedGas); - - // The actual fee should be under the estimate, but not too much - expect(feeFromEstimatedGas).toBeLessThan(actualFee * 2n); - expect(feeFromEstimatedGas).toBeGreaterThanOrEqual(actualFee); + expectGreaterFeeFromEstimatedGas(estimatedGas, actualFee); }); it('estimates gas with public payment method', async () => { @@ -95,20 +97,19 @@ describe('e2e_fees gas_estimation', () => { const [withEstimate, withoutEstimate] = await sendTransfers(paymentMethod); const actualFee = withEstimate.transactionFee!; + // Actual teardown gas used is less than the limits. + expect(estimatedGas.teardownGasLimits.l2Gas).toBeLessThan(gasSettings.teardownGasLimits.l2Gas); + expect(estimatedGas.teardownGasLimits.daGas).toBeLessThan(gasSettings.teardownGasLimits.daGas); + // Estimation should yield that teardown has reduced cost, but is not zero expect(withEstimate.transactionFee!).toBeLessThan(withoutEstimate.transactionFee!); - expect(withEstimate.transactionFee! + teardownFixedFee).toBeGreaterThan(withoutEstimate.transactionFee!); + expect(withEstimate.transactionFee!).toBeGreaterThan(withoutEstimate.transactionFee! - teardownFixedFee); // Check that estimated gas for teardown are not zero since we're doing work there expect(estimatedGas.teardownGasLimits.l2Gas).toBeGreaterThan(0); // Check that the estimate was close to the actual gas used by recomputing the tx fee from it - const feeFromEstimatedGas = getFeeFromEstimatedGas(estimatedGas); - - // The actual fee should be under the estimate, but not too much - // TODO(palla/gas): 3x is too much, find out why we cannot bring this down to 2x - expect(feeFromEstimatedGas).toBeLessThan(actualFee * 3n); - expect(feeFromEstimatedGas).toBeGreaterThanOrEqual(actualFee); + expectGreaterFeeFromEstimatedGas(estimatedGas, actualFee); }); it('estimates gas for public contract initialization with Fee Juice payment method', async () => { @@ -129,17 +130,13 @@ describe('e2e_fees gas_estimation', () => { // Estimation should yield that teardown has no cost, so should send the tx with zero for teardown const actualFee = withEstimate.transactionFee!; - expect(actualFee + teardownFixedFee).toEqual(withoutEstimate.transactionFee!); + expect(actualFee).toEqual(withoutEstimate.transactionFee!); // Check that estimated gas for teardown are zero expect(estimatedGas.teardownGasLimits.l2Gas).toEqual(0); expect(estimatedGas.teardownGasLimits.daGas).toEqual(0); // Check that the estimate was close to the actual gas used by recomputing the tx fee from it - const feeFromEstimatedGas = getFeeFromEstimatedGas(estimatedGas); - - // The actual fee should be under the estimate, but not too much - expect(feeFromEstimatedGas).toBeLessThan(actualFee * 2n); - expect(feeFromEstimatedGas).toBeGreaterThanOrEqual(actualFee); + expectGreaterFeeFromEstimatedGas(estimatedGas, actualFee); }); }); diff --git a/yarn-project/protocol-contracts/src/protocol_contract_data.ts b/yarn-project/protocol-contracts/src/protocol_contract_data.ts index f529cc87b32..ef2ee721900 100644 --- a/yarn-project/protocol-contracts/src/protocol_contract_data.ts +++ b/yarn-project/protocol-contracts/src/protocol_contract_data.ts @@ -50,14 +50,14 @@ export const ProtocolContractAddress: Record }; export const ProtocolContractLeaf = { - AuthRegistry: Fr.fromString('0x295f52c40413b660d817ceea60d07154322a035d28d18927b2ca84e8ec3b2115'), - ContractInstanceDeployer: Fr.fromString('0x00113ad28d270a493266484d733f73a56b98c74b4e2cdf9fc040b5d3a6560f2d'), - ContractClassRegisterer: Fr.fromString('0x1d591819cccc4031cc18a7865321c54f6344ae42a205782874d1f72648df2034'), - MultiCallEntrypoint: Fr.fromString('0x20a2e7e882045d27b3aa9e36188b8e45483b3c11652d4a46406699e5eb4efa9b'), - FeeJuice: Fr.fromString('0x2ed38c200a958d2364c9a8c6f7475cb53e75f602bb7a873b81668c5e431baeb7'), - Router: Fr.fromString('0x22ec69dd15cc4f9d7272fa362aa86212797ff2c73f33975f78f9d0289322d401'), + AuthRegistry: Fr.fromString('0x0e85b3514938c3b0e0dbde3e0166112fbdf8be52d785d7f16343ff8811a6aa61'), + ContractInstanceDeployer: Fr.fromString('0x01058a68733f2faef2e88d5f68119205ea278d24ff1580b6eadb786612d9fe1f'), + ContractClassRegisterer: Fr.fromString('0x05974f2c180fea4efc59300e797651d291d12a0d3e06ab42d311fbc9081a9c77'), + MultiCallEntrypoint: Fr.fromString('0x2af59baec3ef89c8b260ce3a25c3914ba8eca26c630263cd55effc5d4b094645'), + FeeJuice: Fr.fromString('0x1e6566e9888d8a90b57b65e6c1213465aa3f99ce6e78f00c9ad1ae9b44a87269'), + Router: Fr.fromString('0x2cceafcc64b7cac13036654ef4659796a6989c16a222095033f3c069dd8584f8'), }; export const protocolContractTreeRoot = Fr.fromString( - '0x2ba7b6e2fca56bb4abd15d3ef75ff0fb84c9c41588f9d0947068051297d59b67', + '0x03af2136fa5e00fc3ad4dfdd880cd13d28b5fd2dec5f06e47cb91b3613c28178', ); diff --git a/yarn-project/sequencer-client/src/tx_validator/gas_validator.ts b/yarn-project/sequencer-client/src/tx_validator/gas_validator.ts index 7d4683f0226..9154ed15310 100644 --- a/yarn-project/sequencer-client/src/tx_validator/gas_validator.ts +++ b/yarn-project/sequencer-client/src/tx_validator/gas_validator.ts @@ -1,4 +1,4 @@ -import { PublicKernelPhase, type Tx, type TxValidator } from '@aztec/circuit-types'; +import { type Tx, TxExecutionPhase, type TxValidator } from '@aztec/circuit-types'; import { type AztecAddress, type Fr, FunctionSelector } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { EnqueuedCallsProcessor, computeFeePayerBalanceStorageSlot } from '@aztec/simulator'; @@ -58,7 +58,7 @@ export class GasTxValidator implements TxValidator { ); // If there is a claim in this tx that increases the fee payer balance in Fee Juice, add it to balance - const setupFns = EnqueuedCallsProcessor.getExecutionRequestsByPhase(tx, PublicKernelPhase.SETUP); + const setupFns = EnqueuedCallsProcessor.getExecutionRequestsByPhase(tx, TxExecutionPhase.SETUP); const claimFunctionCall = setupFns.find( fn => fn.callContext.contractAddress.equals(this.#feeJuiceAddress) && diff --git a/yarn-project/sequencer-client/src/tx_validator/phases_validator.ts b/yarn-project/sequencer-client/src/tx_validator/phases_validator.ts index ccc8931e731..813c382a6a6 100644 --- a/yarn-project/sequencer-client/src/tx_validator/phases_validator.ts +++ b/yarn-project/sequencer-client/src/tx_validator/phases_validator.ts @@ -1,8 +1,8 @@ import { type AllowedElement, type PublicExecutionRequest, - PublicKernelPhase, Tx, + TxExecutionPhase, type TxValidator, } from '@aztec/circuit-types'; import { type ContractDataSource } from '@aztec/circuits.js'; @@ -45,7 +45,7 @@ export class PhasesTxValidator implements TxValidator { return true; } - const setupFns = EnqueuedCallsProcessor.getExecutionRequestsByPhase(tx, PublicKernelPhase.SETUP); + const setupFns = EnqueuedCallsProcessor.getExecutionRequestsByPhase(tx, TxExecutionPhase.SETUP); for (const setupFn of setupFns) { if (!(await this.isOnAllowList(setupFn, this.setupAllowList))) { this.#log.warn( diff --git a/yarn-project/simulator/src/mocks/fixtures.ts b/yarn-project/simulator/src/mocks/fixtures.ts index 76f7fdc7d03..9a267e689bd 100644 --- a/yarn-project/simulator/src/mocks/fixtures.ts +++ b/yarn-project/simulator/src/mocks/fixtures.ts @@ -51,7 +51,7 @@ export class PublicExecutionResultBuilder { build(overrides: Partial = {}): EnqueuedPublicCallExecutionResult { return { - endGasLeft: Gas.test(), + endGasLeft: new Gas(0, 0), endSideEffectCounter: Fr.ZERO, returnValues: padArrayEnd(this._returnValues, Fr.ZERO, 4), // TODO(#5450) Need to use the proper return values here reverted: this._reverted, diff --git a/yarn-project/simulator/src/public/enqueued_call_simulator.ts b/yarn-project/simulator/src/public/enqueued_call_simulator.ts index e49fbd1ca00..62b48402d3f 100644 --- a/yarn-project/simulator/src/public/enqueued_call_simulator.ts +++ b/yarn-project/simulator/src/public/enqueued_call_simulator.ts @@ -4,7 +4,6 @@ import { NestedProcessReturnValues, ProvingRequestType, type PublicExecutionRequest, - type PublicKernelPhase, type SimulationError, UnencryptedFunctionL2Logs, } from '@aztec/circuit-types'; @@ -12,6 +11,7 @@ import { AvmCircuitInputs, AvmCircuitPublicInputs, AztecAddress, + type CombinedConstantData, ContractStorageRead, ContractStorageUpdateRequest, Fr, @@ -37,7 +37,6 @@ import { type PublicCallRequest, PublicCircuitPublicInputs, PublicInnerCallRequest, - type PublicKernelCircuitPublicInputs, ReadRequest, RevertCode, TreeLeafReadRequest, @@ -83,7 +82,7 @@ export type EnqueuedCallResult = { newUnencryptedLogs: UnencryptedFunctionL2Logs; /** Return values of simulating complete callstack */ returnValues: NestedProcessReturnValues; - /** Gas used during the execution this enqueued call */ + /** Gas used during the execution of this enqueued call */ gasUsed: Gas; /** Did call revert? */ reverted: boolean; @@ -107,10 +106,9 @@ export class EnqueuedCallSimulator { async simulate( callRequest: PublicCallRequest, executionRequest: PublicExecutionRequest, - previousPublicKernelOutput: PublicKernelCircuitPublicInputs, + constants: CombinedConstantData, availableGas: Gas, transactionFee: Fr, - phase: PublicKernelPhase, stateManager: AvmPersistableStateManager, ): Promise { // Gas allocated to an enqueued call can be different from the available gas @@ -119,7 +117,6 @@ export class EnqueuedCallSimulator { /*daGas=*/ availableGas.daGas, /*l2Gas=*/ Math.min(availableGas.l2Gas, MAX_L2_GAS_PER_ENQUEUED_CALL), ); - const _pendingNullifiers = this.getSiloedPendingNullifiers(previousPublicKernelOutput); const result = (await this.publicExecutor.simulate( stateManager, @@ -158,11 +155,6 @@ export class EnqueuedCallSimulator { avmProvingRequest = emptyAvmProvingRequest(); } - // If this is the first enqueued call in public, constants will be empty - // because private kernel does not expose them. - const constants = previousPublicKernelOutput.constants.clone(); - constants.globalVariables = this.globalVariables; - // TODO(dbanks12): Since AVM circuit will be at the level of all enqueued calls in a TX, // this public inputs generation will move up to the enqueued calls processor. const vmCircuitPublicInputs = stateManager.trace.toVMCircuitPublicInputs( @@ -187,11 +179,6 @@ export class EnqueuedCallSimulator { }; } - /** Returns all pending private and public nullifiers. */ - private getSiloedPendingNullifiers(ko: PublicKernelCircuitPublicInputs) { - return [...ko.end.nullifiers, ...ko.endNonRevertibleData.nullifiers].filter(n => !n.isEmpty()); - } - private async getPublicCircuitPublicInputs(result: PublicFunctionCallResult) { const publicDataTreeInfo = await this.db.getTreeInfo(MerkleTreeId.PUBLIC_DATA_TREE); this.historicalHeader.state.partial.publicDataTree.root = Fr.fromBuffer(publicDataTreeInfo.root); @@ -278,11 +265,4 @@ export class EnqueuedCallSimulator { revertCode: result.reverted ? RevertCode.APP_LOGIC_REVERTED : RevertCode.OK, }); } - - private getBytecodeHash(_result: PublicFunctionCallResult) { - // TODO: Determine how to calculate bytecode hash. Circuits just check it isn't zero for now. - // See https://github.com/AztecProtocol/aztec3-packages/issues/378 - const bytecodeHash = new Fr(1n); - return Promise.resolve(bytecodeHash); - } } diff --git a/yarn-project/simulator/src/public/enqueued_calls_processor.test.ts b/yarn-project/simulator/src/public/enqueued_calls_processor.test.ts index 4c188249a5b..6622c06322b 100644 --- a/yarn-project/simulator/src/public/enqueued_calls_processor.test.ts +++ b/yarn-project/simulator/src/public/enqueued_calls_processor.test.ts @@ -1,8 +1,8 @@ import { type MerkleTreeWriteOperations, - PublicKernelPhase, SimulationError, type TreeInfo, + TxExecutionPhase, mockTx, } from '@aztec/circuit-types'; import { @@ -16,20 +16,17 @@ import { Header, PUBLIC_DATA_TREE_HEIGHT, PartialStateReference, - PrivateToPublicAccumulatedDataBuilder, PublicDataTreeLeafPreimage, PublicDataWrite, RevertCode, StateReference, + countAccumulatedItems, } from '@aztec/circuits.js'; -import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; +import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/circuits.js/hash'; import { fr } from '@aztec/circuits.js/testing'; -import { arrayNonEmptyLength } from '@aztec/foundation/collection'; -import { type FieldsOf } from '@aztec/foundation/types'; import { openTmpStore } from '@aztec/kv-store/utils'; import { type AppendOnlyTree, Poseidon, StandardTree, newTree } from '@aztec/merkle-tree'; -import { jest } from '@jest/globals'; import { type MockProxy, mock } from 'jest-mock-extended'; import { type AvmPersistableStateManager } from '../avm/journal/journal.js'; @@ -43,6 +40,19 @@ import { RealPublicKernelCircuitSimulator } from './public_kernel.js'; import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; describe('enqueued_calls_processor', () => { + // Gas settings. + const gasFees = GasFees.from({ feePerDaGas: new Fr(2), feePerL2Gas: new Fr(3) }); + const gasLimits = Gas.from({ daGas: 100, l2Gas: 150 }); + const teardownGasLimits = Gas.from({ daGas: 20, l2Gas: 30 }); + const maxFeesPerGas = gasFees; + + // gasUsed for the tx after private execution. + const txPrivateNonRevertibleGasUsed = Gas.from({ daGas: 13, l2Gas: 17 }); + const txPrivateRevertibleGasUsed = Gas.from({ daGas: 7, l2Gas: 11 }); + + // gasUsed for each enqueued call. + const enqueuedCallGasUsed = new Gas(12, 34); + let db: MockProxy; let publicExecutor: MockProxy; let publicKernel: PublicKernelCircuitSimulator; @@ -53,12 +63,74 @@ describe('enqueued_calls_processor', () => { let processor: EnqueuedCallsProcessor; + const mockTxWithPublicCalls = ({ + numberOfSetupCalls = 0, + numberOfAppLogicCalls = 0, + hasPublicTeardownCall = false, + }: { + numberOfSetupCalls?: number; + numberOfAppLogicCalls?: number; + hasPublicTeardownCall?: boolean; + }) => { + const tx = mockTx(1, { + numberOfNonRevertiblePublicCallRequests: numberOfSetupCalls, + numberOfRevertiblePublicCallRequests: numberOfAppLogicCalls, + hasPublicTeardownCallRequest: hasPublicTeardownCall, + }); + tx.data.constants.txContext.gasSettings = GasSettings.from({ gasLimits, teardownGasLimits, maxFeesPerGas }); + + tx.data.forPublic!.nonRevertibleAccumulatedData.nullifiers[0] = new Fr(7777); + tx.data.forPublic!.nonRevertibleAccumulatedData.nullifiers[1] = new Fr(8888); + tx.data.forPublic!.nonRevertibleAccumulatedData.gasUsed = txPrivateNonRevertibleGasUsed; + + tx.data.forPublic!.revertibleAccumulatedData.nullifiers[0] = new Fr(9999); + tx.data.forPublic!.revertibleAccumulatedData.gasUsed = txPrivateRevertibleGasUsed; + + return tx; + }; + + const mockPublicExecutor = ( + mockedSimulatorExecutions: ((stateManager: AvmPersistableStateManager) => Promise)[], + ) => { + for (const executeSimulator of mockedSimulatorExecutions) { + publicExecutor.simulate.mockImplementationOnce( + async (stateManager: AvmPersistableStateManager, _executionResult, _globalVariables, allocatedGas) => { + const builder = await executeSimulator(stateManager); + return builder.build({ + endGasLeft: allocatedGas.sub(enqueuedCallGasUsed), + }); + }, + ); + } + }; + + const expectAvailableGasForCalls = (availableGases: Gas[]) => { + expect(publicExecutor.simulate).toHaveBeenCalledTimes(availableGases.length); + availableGases.forEach((availableGas, i) => { + expect(publicExecutor.simulate).toHaveBeenNthCalledWith( + i + 1, + expect.anything(), // AvmPersistableStateManager + expect.anything(), // publicExecutionRequest + expect.anything(), // globalVariables + Gas.from(availableGas), + expect.anything(), // txFee + ); + }); + }; + beforeEach(async () => { db = mock(); - publicExecutor = mock(); worldStateDB = mock(); root = Buffer.alloc(32, 5); + publicExecutor = mock(); + publicExecutor.simulate.mockImplementation((_stateManager, _executionResult, _globalVariables, allocatedGas) => { + const result = PublicExecutionResultBuilder.empty().build({ + endGasLeft: allocatedGas.sub(enqueuedCallGasUsed), + }); + return Promise.resolve(result); + }); + publicDataTree = await newTree( StandardTree, openTmpStore(), @@ -92,589 +164,476 @@ describe('enqueued_calls_processor', () => { db, publicExecutor, publicKernel, - GlobalVariables.from({ ...GlobalVariables.empty(), gasFees: GasFees.default() }), + GlobalVariables.from({ ...GlobalVariables.empty(), gasFees }), Header.empty(), worldStateDB, /*realAvmProvingRequest=*/ false, ); }); - it('runs a tx with enqueued public calls', async function () { - const tx = mockTx(1, { - numberOfNonRevertiblePublicCallRequests: 0, - numberOfRevertiblePublicCallRequests: 2, - hasLogs: true, + it('runs a tx with enqueued public calls in setup phase only', async () => { + const tx = mockTxWithPublicCalls({ + numberOfSetupCalls: 2, }); - publicExecutor.simulate.mockImplementation(_stateManager => { - const result = PublicExecutionResultBuilder.empty().build(); - return Promise.resolve(result); - }); - - const tailSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTail'); - const txResult = await processor.process(tx); - expect(txResult.processedPhases).toHaveLength(1); - expect(txResult.processedPhases[0]).toEqual(expect.objectContaining({ revertReason: undefined })); + expect(txResult.processedPhases).toEqual([ + expect.objectContaining({ phase: TxExecutionPhase.SETUP, revertReason: undefined }), + ]); expect(txResult.revertCode).toEqual(RevertCode.OK); expect(txResult.revertReason).toBe(undefined); - expect(tailSpy).toHaveBeenCalledTimes(1); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(2); + const expectedPrivateGasUsed = txPrivateNonRevertibleGasUsed.add(txPrivateRevertibleGasUsed); + const expectedPublicGasUsed = enqueuedCallGasUsed.mul(2); // For 2 setup calls. + const expectedTotalGas = expectedPrivateGasUsed.add(expectedPublicGasUsed); + expect(txResult.gasUsed).toEqual({ + totalGas: expectedTotalGas, + teardownGas: Gas.empty(), + }); + + const availableGasForFirstSetup = gasLimits.sub(txPrivateNonRevertibleGasUsed); + const availableGasForSecondSetup = availableGasForFirstSetup.sub(enqueuedCallGasUsed); + expectAvailableGasForCalls([availableGasForFirstSetup, availableGasForSecondSetup]); + + const output = txResult.avmProvingRequest!.inputs.output; - const outputs = txResult.avmProvingRequest!.inputs.output.accumulatedData; - // we keep the non-revertible logs - expect(arrayNonEmptyLength(outputs.unencryptedLogsHashes, l => l.logHash.isEmpty())).toBe(2); + const expectedTxFee = expectedTotalGas.computeFee(gasFees); + expect(output.transactionFee).toEqual(expectedTxFee); + + // We keep all data. + expect(countAccumulatedItems(output.accumulatedData.nullifiers)).toBe(3); }); - it('includes a transaction that reverts in teardown', async function () { - const tx = mockTx(1, { - hasLogs: true, - numberOfNonRevertiblePublicCallRequests: 1, - numberOfRevertiblePublicCallRequests: 1, - hasPublicTeardownCallRequest: true, + it('runs a tx with enqueued public calls in app logic phase only', async () => { + const tx = mockTxWithPublicCalls({ + numberOfAppLogicCalls: 2, }); - const nonRevertibleRequests = tx.getNonRevertiblePublicExecutionRequests(); - const revertibleRequests = tx.getRevertiblePublicExecutionRequests(); + const txResult = await processor.process(tx); - const teardownGas = tx.data.constants.txContext.gasSettings.getTeardownLimits(); + expect(txResult.processedPhases).toEqual([ + expect.objectContaining({ phase: TxExecutionPhase.APP_LOGIC, revertReason: undefined }), + ]); + expect(txResult.revertCode).toEqual(RevertCode.OK); + expect(txResult.revertReason).toBe(undefined); - const nestedContractAddress = AztecAddress.fromBigInt(112233n); - const contractSlotA = fr(0x100); - const contractSlotB = fr(0x150); - const contractSlotC = fr(0x200); + const expectedPrivateGasUsed = txPrivateNonRevertibleGasUsed.add(txPrivateRevertibleGasUsed); + const expectedPublicGasUsed = enqueuedCallGasUsed.mul(2); // For 2 app logic calls. + const expectedTotalGas = expectedPrivateGasUsed.add(expectedPublicGasUsed); + expect(txResult.gasUsed).toEqual({ + totalGas: expectedTotalGas, + teardownGas: Gas.empty(), + }); - const teardownFailure = new SimulationError('Simulation Failed in teardown', []); - const simulatorResults: EnqueuedPublicCallExecutionResult[] = [ - // Setup - PublicExecutionResultBuilder.empty().build(), - // App Logic - PublicExecutionResultBuilder.empty().build(), - // Teardown - PublicExecutionResultBuilder.empty().withReverted(teardownFailure).build({ endGasLeft: teardownGas }), - ]; - const mockedSimulatorExecutions = [ - // SETUP - (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(nonRevertibleRequests[0].callContext.contractAddress, contractSlotA, fr(0x101)); - stateManager.writeStorage(nestedContractAddress, contractSlotA, fr(0x102)); - stateManager.writeStorage(nestedContractAddress, contractSlotB, fr(0x151)); - return Promise.resolve(simulatorResults[0]); - }, - // APP LOGIC - (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(revertibleRequests[0].callContext.contractAddress, contractSlotB, fr(0x152)); - stateManager.writeStorage(revertibleRequests[0].callContext.contractAddress, contractSlotC, fr(0x201)); - return Promise.resolve(simulatorResults[1]); - }, - (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x202)); - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x202)); - return Promise.resolve(simulatorResults[2]); - }, - ]; + const availableGasForFirstAppLogic = gasLimits.sub(expectedPrivateGasUsed); + const availableGasForSecondAppLogic = availableGasForFirstAppLogic.sub(enqueuedCallGasUsed); + expectAvailableGasForCalls([availableGasForFirstAppLogic, availableGasForSecondAppLogic]); - for (const executeSimulator of mockedSimulatorExecutions) { - publicExecutor.simulate.mockImplementationOnce( - (stateManager: AvmPersistableStateManager): Promise => { - return executeSimulator(stateManager); - }, - ); - } + const output = txResult.avmProvingRequest!.inputs.output; - const tailSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTail'); + const expectedTxFee = expectedTotalGas.computeFee(gasFees); + expect(output.transactionFee).toEqual(expectedTxFee); - const txResult = await processor.process(tx); + // We keep all data. + expect(countAccumulatedItems(output.accumulatedData.nullifiers)).toBe(3); + }); - expect(txResult.processedPhases).toHaveLength(3); - expect(txResult.processedPhases[0]).toEqual(expect.objectContaining({ revertReason: undefined })); - expect(txResult.processedPhases[1]).toEqual(expect.objectContaining({ revertReason: undefined })); - expect(txResult.processedPhases[2]).toEqual(expect.objectContaining({ revertReason: teardownFailure })); - expect(txResult.revertReason).toBe(teardownFailure); + it('runs a tx with enqueued public calls in teardown phase only', async () => { + const tx = mockTxWithPublicCalls({ + hasPublicTeardownCall: true, + }); - expect(tailSpy).toHaveBeenCalledTimes(1); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); + const txResult = await processor.process(tx); - const outputs = txResult.avmProvingRequest!.inputs.output.accumulatedData; - const numPublicDataWrites = 3; - expect(arrayNonEmptyLength(outputs.publicDataWrites, PublicDataWrite.isEmpty)).toBe(numPublicDataWrites); - expect(outputs.publicDataWrites.slice(0, numPublicDataWrites)).toEqual([ - new PublicDataWrite( - computePublicDataTreeLeafSlot(nonRevertibleRequests[0].callContext.contractAddress, contractSlotA), - fr(0x101), - ), - new PublicDataWrite(computePublicDataTreeLeafSlot(nestedContractAddress, contractSlotA), fr(0x102)), - new PublicDataWrite(computePublicDataTreeLeafSlot(nestedContractAddress, contractSlotB), fr(0x151)), + expect(txResult.processedPhases).toEqual([ + expect.objectContaining({ phase: TxExecutionPhase.TEARDOWN, revertReason: undefined }), ]); + expect(txResult.revertCode).toEqual(RevertCode.OK); + expect(txResult.revertReason).toBe(undefined); + + const expectedPrivateGasUsed = txPrivateNonRevertibleGasUsed.add(txPrivateRevertibleGasUsed); + const expectedTeardownGasUsed = enqueuedCallGasUsed; + const expectedTotalGas = expectedPrivateGasUsed.add(expectedTeardownGasUsed); + expect(txResult.gasUsed).toEqual({ + totalGas: expectedTotalGas, + teardownGas: expectedTeardownGasUsed, + }); + + expectAvailableGasForCalls([teardownGasLimits]); + + const output = txResult.avmProvingRequest!.inputs.output; - // we keep the non-revertible logs - expect(arrayNonEmptyLength(outputs.unencryptedLogsHashes, l => l.logHash.isEmpty())).toBe(1); + const expectedTotalGasForFee = expectedTotalGas.sub(expectedTeardownGasUsed).add(teardownGasLimits); + const expectedTxFee = expectedTotalGasForFee.computeFee(gasFees); + expect(output.transactionFee).toEqual(expectedTxFee); + + // We keep all data. + expect(countAccumulatedItems(output.accumulatedData.nullifiers)).toBe(3); }); - it('fails a transaction that reverts in setup', async function () { - const tx = mockTx(1, { - numberOfNonRevertiblePublicCallRequests: 1, - numberOfRevertiblePublicCallRequests: 1, - hasPublicTeardownCallRequest: true, + it('runs a tx with all phases', async () => { + const tx = mockTxWithPublicCalls({ + numberOfSetupCalls: 2, + numberOfAppLogicCalls: 1, + hasPublicTeardownCall: true, }); - const nonRevertibleRequests = tx.getNonRevertiblePublicExecutionRequests(); + const txResult = await processor.process(tx); - const nestedContractAddress = AztecAddress.fromBigInt(112233n); - const contractSlotA = fr(0x100); - const contractSlotB = fr(0x150); - const contractSlotC = fr(0x200); + expect(txResult.processedPhases).toHaveLength(3); + expect(txResult.processedPhases).toEqual([ + expect.objectContaining({ phase: TxExecutionPhase.SETUP, revertReason: undefined }), + expect.objectContaining({ phase: TxExecutionPhase.APP_LOGIC, revertReason: undefined }), + expect.objectContaining({ phase: TxExecutionPhase.TEARDOWN, revertReason: undefined }), + ]); + expect(txResult.revertCode).toEqual(RevertCode.OK); + expect(txResult.revertReason).toBe(undefined); - const setupFailureMsg = 'Simulation Failed in setup'; - const setupFailure = new SimulationError(setupFailureMsg, []); - const simulatorResults: EnqueuedPublicCallExecutionResult[] = [ - // Setup - PublicExecutionResultBuilder.empty().withReverted(setupFailure).build(), - // App Logic - PublicExecutionResultBuilder.empty().build(), - // Teardown - PublicExecutionResultBuilder.empty().build(), - ]; - const mockedSimulatorExecutions = [ - // SETUP - (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(nonRevertibleRequests[0].callContext.contractAddress, contractSlotA, fr(0x101)); - stateManager.writeStorage(nestedContractAddress, contractSlotA, fr(0x102)); - stateManager.writeStorage(nestedContractAddress, contractSlotB, fr(0x151)); - return Promise.resolve(simulatorResults[0]); - }, - // APP LOGIC - (_stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - return Promise.resolve(simulatorResults[1]); - }, - (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x202)); - return Promise.resolve(simulatorResults[2]); - }, - ]; + const expectedPrivateGasUsed = txPrivateNonRevertibleGasUsed.add(txPrivateRevertibleGasUsed); + const expectedPublicGasUsed = enqueuedCallGasUsed.mul(3); // 2 for setup and 1 for app logic. + const expectedTeardownGasUsed = enqueuedCallGasUsed; + const expectedTotalGas = expectedPrivateGasUsed.add(expectedPublicGasUsed).add(expectedTeardownGasUsed); + expect(txResult.gasUsed).toEqual({ + totalGas: expectedTotalGas, + teardownGas: expectedTeardownGasUsed, + }); - for (const executeSimulator of mockedSimulatorExecutions) { - publicExecutor.simulate.mockImplementationOnce( - (stateManager: AvmPersistableStateManager): Promise => { - return executeSimulator(stateManager); - }, - ); - } + // Check that each enqueued call is allocated the correct amount of gas. + const availableGasForFirstSetup = gasLimits.sub(teardownGasLimits).sub(txPrivateNonRevertibleGasUsed); + const availableGasForSecondSetup = availableGasForFirstSetup.sub(enqueuedCallGasUsed); + const availableGasForAppLogic = availableGasForSecondSetup.sub(txPrivateRevertibleGasUsed).sub(enqueuedCallGasUsed); + expectAvailableGasForCalls([ + availableGasForFirstSetup, + availableGasForSecondSetup, + availableGasForAppLogic, + teardownGasLimits, + ]); - const tailSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTail'); + const output = txResult.avmProvingRequest!.inputs.output; - await expect(processor.process(tx)).rejects.toThrow(setupFailureMsg); + const expectedTotalGasForFee = expectedTotalGas.sub(expectedTeardownGasUsed).add(teardownGasLimits); + const expectedTxFee = expectedTotalGasForFee.computeFee(gasFees); + expect(output.transactionFee).toEqual(expectedTxFee); - expect(tailSpy).toHaveBeenCalledTimes(0); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(1); + // We keep all data. + expect(countAccumulatedItems(output.accumulatedData.nullifiers)).toBe(3); }); - it('rolls back app logic db updates on failed public execution, but persists setup', async function () { - const tx = mockTx(1, { - hasLogs: true, - numberOfNonRevertiblePublicCallRequests: 1, - numberOfRevertiblePublicCallRequests: 1, - hasPublicTeardownCallRequest: true, + it('deduplicates public data writes', async function () { + const tx = mockTxWithPublicCalls({ + numberOfSetupCalls: 1, + numberOfAppLogicCalls: 1, + hasPublicTeardownCall: true, }); - const nonRevertibleRequests = tx.getNonRevertiblePublicExecutionRequests(); - - const teardownGas = tx.data.constants.txContext.gasSettings.getTeardownLimits(); + const revertibleRequests = tx.getRevertiblePublicExecutionRequests(); - const nestedContractAddress = AztecAddress.fromBigInt(112233n); + const contractAddress = revertibleRequests[0].callContext.contractAddress; const contractSlotA = fr(0x100); const contractSlotB = fr(0x150); const contractSlotC = fr(0x200); - const contractSlotD = fr(0x250); - const contractSlotE = fr(0x300); - const contractSlotF = fr(0x350); - - const appLogicFailure = new SimulationError('Simulation Failed in app logic', []); - const simulatorResults: EnqueuedPublicCallExecutionResult[] = [ - // Setup - PublicExecutionResultBuilder.empty().build(), - // App Logic - PublicExecutionResultBuilder.empty().withReverted(appLogicFailure).build(), - // Teardown - PublicExecutionResultBuilder.empty().build({ endGasLeft: teardownGas }), - ]; const mockedSimulatorExecutions = [ // SETUP - (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(nonRevertibleRequests[0].callContext.contractAddress, contractSlotA, fr(0x101)); - return Promise.resolve(simulatorResults[0]); + async (_stateManager: AvmPersistableStateManager) => { + // Nothing happened in setup phase. }, // APP LOGIC - (stateManager: AvmPersistableStateManager) => { + async (stateManager: AvmPersistableStateManager) => { // mock storage writes on the state manager - stateManager.writeStorage(nestedContractAddress, contractSlotA, fr(0x102)); - stateManager.writeStorage(nestedContractAddress, contractSlotB, fr(0x151)); - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x200)); - return Promise.resolve(simulatorResults[1]); + stateManager.writeStorage(contractAddress, contractSlotA, fr(0x101)); + stateManager.writeStorage(contractAddress, contractSlotB, fr(0x151)); + await stateManager.readStorage(contractAddress, contractSlotA); }, - (stateManager: AvmPersistableStateManager) => { + async (stateManager: AvmPersistableStateManager) => { // mock storage writes on the state manager - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x201)); - stateManager.writeStorage(nestedContractAddress, contractSlotD, fr(0x251)); - stateManager.writeStorage(nestedContractAddress, contractSlotE, fr(0x301)); - stateManager.writeStorage(nestedContractAddress, contractSlotF, fr(0x351)); - return Promise.resolve(simulatorResults[2]); + stateManager.writeStorage(contractAddress, contractSlotA, fr(0x103)); + stateManager.writeStorage(contractAddress, contractSlotC, fr(0x201)); + await stateManager.readStorage(contractAddress, contractSlotA); + stateManager.writeStorage(contractAddress, contractSlotC, fr(0x102)); + stateManager.writeStorage(contractAddress, contractSlotC, fr(0x152)); + await stateManager.readStorage(contractAddress, contractSlotA); }, ]; for (const executeSimulator of mockedSimulatorExecutions) { publicExecutor.simulate.mockImplementationOnce( - (stateManager: AvmPersistableStateManager): Promise => { - return executeSimulator(stateManager); + async ( + stateManager: AvmPersistableStateManager, + _executionResult, + _globalVariables, + allocatedGas, + ): Promise => { + await executeSimulator(stateManager); + const result = PublicExecutionResultBuilder.empty().build({ + endGasLeft: allocatedGas.sub(enqueuedCallGasUsed), + }); + return Promise.resolve(result); }, ); } - const tailSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTail'); - const txResult = await processor.process(tx); expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); - expect(txResult.processedPhases).toHaveLength(3); - expect(txResult.processedPhases[0]).toEqual(expect.objectContaining({ revertReason: undefined })); - expect(txResult.processedPhases[1]).toEqual(expect.objectContaining({ revertReason: appLogicFailure })); - expect(txResult.processedPhases[2]).toEqual(expect.objectContaining({ revertReason: undefined })); - // tx reports app logic failure - expect(txResult.revertReason).toBe(appLogicFailure); - - expect(tailSpy).toHaveBeenCalledTimes(1); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); + const output = txResult.avmProvingRequest!.inputs.output; - const outputs = txResult.avmProvingRequest!.inputs.output.accumulatedData; - const numPublicDataWrites = 5; - expect(arrayNonEmptyLength(outputs.publicDataWrites, PublicDataWrite.isEmpty)).toBe(numPublicDataWrites); - expect(outputs.publicDataWrites.slice(0, numPublicDataWrites)).toEqual([ - new PublicDataWrite( - computePublicDataTreeLeafSlot(nonRevertibleRequests[0].callContext.contractAddress, contractSlotA), - fr(0x101), - ), - new PublicDataWrite(computePublicDataTreeLeafSlot(nestedContractAddress, contractSlotC), fr(0x201)), - new PublicDataWrite(computePublicDataTreeLeafSlot(nestedContractAddress, contractSlotD), fr(0x251)), - new PublicDataWrite(computePublicDataTreeLeafSlot(nestedContractAddress, contractSlotE), fr(0x301)), - new PublicDataWrite(computePublicDataTreeLeafSlot(nestedContractAddress, contractSlotF), fr(0x351)), + const numPublicDataWrites = 3; + expect(countAccumulatedItems(output.accumulatedData.publicDataWrites)).toBe(numPublicDataWrites); + expect(output.accumulatedData.publicDataWrites.slice(0, numPublicDataWrites)).toEqual([ + // squashed + // new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotA), fr(0x101)), + new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotB), fr(0x151)), + new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotA), fr(0x103)), + // squashed + // new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotC), fr(0x201)), + // new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotC), fr(0x102)), + new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotC), fr(0x152)), ]); - - // we keep the non-revertible logs - expect(arrayNonEmptyLength(outputs.unencryptedLogsHashes, l => l.logHash.isEmpty())).toBe(1); }); - it('includes a transaction that reverts in app logic and teardown', async function () { + it('fails a transaction that reverts in setup', async function () { const tx = mockTx(1, { - hasLogs: true, numberOfNonRevertiblePublicCallRequests: 1, numberOfRevertiblePublicCallRequests: 1, hasPublicTeardownCallRequest: true, }); - const nonRevertibleRequests = tx.getNonRevertiblePublicExecutionRequests(); - const revertibleRequests = tx.getRevertiblePublicExecutionRequests(); + const setupFailureMsg = 'Simulation Failed in setup'; + const setupFailure = new SimulationError(setupFailureMsg, []); + publicExecutor.simulate.mockResolvedValueOnce( + PublicExecutionResultBuilder.empty().withReverted(setupFailure).build(), + ); - const teardownGas = tx.data.constants.txContext.gasSettings.getTeardownLimits(); + await expect(processor.process(tx)).rejects.toThrow(setupFailureMsg); - const nestedContractAddress = AztecAddress.fromBigInt(112233n); - const contractSlotA = fr(0x100); - const contractSlotB = fr(0x150); - const contractSlotC = fr(0x200); + expect(publicExecutor.simulate).toHaveBeenCalledTimes(1); + }); + + it('includes a transaction that reverts in app logic', async function () { + const tx = mockTxWithPublicCalls({ + numberOfSetupCalls: 1, + numberOfAppLogicCalls: 1, + hasPublicTeardownCall: true, + }); const appLogicFailure = new SimulationError('Simulation Failed in app logic', []); - const teardownFailure = new SimulationError('Simulation Failed in teardown', []); - const simulatorResults: EnqueuedPublicCallExecutionResult[] = [ - // Setup - PublicExecutionResultBuilder.empty().build(), - // App Logic - PublicExecutionResultBuilder.empty().withReverted(appLogicFailure).build(), - // Teardown - PublicExecutionResultBuilder.empty().withReverted(teardownFailure).build({ endGasLeft: teardownGas }), - ]; - const mockedSimulatorExecutions = [ + const contractAddress = AztecAddress.fromBigInt(112233n); + mockPublicExecutor([ // SETUP - (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(nonRevertibleRequests[0].callContext.contractAddress, contractSlotA, fr(0x101)); - stateManager.writeStorage(nestedContractAddress, contractSlotA, fr(0x102)); - stateManager.writeStorage(nestedContractAddress, contractSlotB, fr(0x151)); - return Promise.resolve(simulatorResults[0]); + async (stateManager: AvmPersistableStateManager) => { + // mock nullifiers on the state manager + await stateManager.writeNullifier(contractAddress, new Fr(1)); + return PublicExecutionResultBuilder.empty(); }, // APP LOGIC - (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(revertibleRequests[0].callContext.contractAddress, contractSlotB, fr(0x152)); - stateManager.writeStorage(revertibleRequests[0].callContext.contractAddress, contractSlotC, fr(0x204)); - return Promise.resolve(simulatorResults[1]); + async (stateManager: AvmPersistableStateManager) => { + // mock nullifiers the state manager + await stateManager.writeNullifier(contractAddress, new Fr(2)); + await stateManager.writeNullifier(contractAddress, new Fr(3)); + return PublicExecutionResultBuilder.empty().withReverted(appLogicFailure); }, - (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x202)); - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x202)); - return Promise.resolve(simulatorResults[2]); + async (stateManager: AvmPersistableStateManager) => { + // mock nullifiers the state manager + await stateManager.writeNullifier(contractAddress, new Fr(4)); + return PublicExecutionResultBuilder.empty(); }, - ]; - - for (const executeSimulator of mockedSimulatorExecutions) { - publicExecutor.simulate.mockImplementationOnce( - (stateManager: AvmPersistableStateManager): Promise => { - return executeSimulator(stateManager); - }, - ); - } - - const tailSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTail'); + ]); const txResult = await processor.process(tx); expect(txResult.processedPhases).toHaveLength(3); - expect(txResult.processedPhases[0]).toEqual(expect.objectContaining({ revertReason: undefined })); - expect(txResult.processedPhases[1]).toEqual(expect.objectContaining({ revertReason: appLogicFailure })); - expect(txResult.processedPhases[2]).toEqual(expect.objectContaining({ revertReason: teardownFailure })); - expect(txResult.revertCode).toEqual(RevertCode.BOTH_REVERTED); + expect(txResult.processedPhases).toEqual([ + expect.objectContaining({ phase: TxExecutionPhase.SETUP, revertReason: undefined }), + expect.objectContaining({ phase: TxExecutionPhase.APP_LOGIC, revertReason: appLogicFailure }), + expect.objectContaining({ phase: TxExecutionPhase.TEARDOWN, revertReason: undefined }), + ]); + expect(txResult.revertCode).toEqual(RevertCode.APP_LOGIC_REVERTED); // tx reports app logic failure expect(txResult.revertReason).toBe(appLogicFailure); - expect(tailSpy).toHaveBeenCalledTimes(1); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); - - const outputs = txResult.avmProvingRequest!.inputs.output.accumulatedData; - const numPublicDataWrites = 3; - expect(arrayNonEmptyLength(outputs.publicDataWrites, PublicDataWrite.isEmpty)).toBe(numPublicDataWrites); - expect(outputs.publicDataWrites.slice(0, numPublicDataWrites)).toEqual([ - new PublicDataWrite( - computePublicDataTreeLeafSlot(nonRevertibleRequests[0].callContext.contractAddress, contractSlotA), - fr(0x101), - ), - new PublicDataWrite(computePublicDataTreeLeafSlot(nestedContractAddress, contractSlotA), fr(0x102)), - new PublicDataWrite(computePublicDataTreeLeafSlot(nestedContractAddress, contractSlotB), fr(0x151)), - ]); - - // we keep the non-revertible logs - expect(arrayNonEmptyLength(outputs.unencryptedLogsHashes, l => l.logHash.isEmpty())).toBe(1); - }); - - it('runs a tx with all phases', async function () { - const tx = mockTx(1, { - numberOfNonRevertiblePublicCallRequests: 1, - numberOfRevertiblePublicCallRequests: 1, - hasPublicTeardownCallRequest: true, + const expectedSetupGas = txPrivateNonRevertibleGasUsed.add(enqueuedCallGasUsed); + const { l2Gas: appLogicL2Gas } = txPrivateRevertibleGasUsed.add(enqueuedCallGasUsed); + // All data emitted from app logic were discarded. daGas set to 0. + const expectedAppLogicGas = Gas.from({ daGas: 0, l2Gas: appLogicL2Gas }); + const expectedTeardownGasUsed = enqueuedCallGasUsed; + const expectedTotalGas = expectedSetupGas.add(expectedAppLogicGas).add(expectedTeardownGasUsed); + expect(txResult.gasUsed).toEqual({ + totalGas: expectedTotalGas, + teardownGas: expectedTeardownGasUsed, }); - const revertibleRequests = tx.getRevertiblePublicExecutionRequests(); + const availableGasForSetup = gasLimits.sub(teardownGasLimits).sub(txPrivateNonRevertibleGasUsed); + const allocatedAppLogicGas = availableGasForSetup.sub(txPrivateRevertibleGasUsed).sub(enqueuedCallGasUsed); + expectAvailableGasForCalls([availableGasForSetup, allocatedAppLogicGas, teardownGasLimits]); - // Keep gas numbers MAX_L2_GAS_PER_ENQUEUED_CALL or the logic below has to get weird - const gasLimits = Gas.from({ l2Gas: 1e6, daGas: 1e6 }); - const teardownGasLimits = Gas.from({ l2Gas: 1e5, daGas: 1e5 }); - tx.data.constants.txContext.gasSettings = GasSettings.from({ - gasLimits: gasLimits, - teardownGasLimits, - inclusionFee: new Fr(1e4), - maxFeesPerGas: { feePerDaGas: new Fr(10), feePerL2Gas: new Fr(10) }, - }); + const output = txResult.avmProvingRequest!.inputs.output; - const privateNonRevertibleGasUsed = Gas.from({ l2Gas: 20 }); - const privateRevertibleGasUsed = Gas.from({ l2Gas: 30 }); - tx.data.forPublic!.revertibleAccumulatedData = PrivateToPublicAccumulatedDataBuilder.fromPublicAccumulatedData( - tx.data.forPublic!.revertibleAccumulatedData, - ) - .withGasUsed(privateRevertibleGasUsed) - .build(); - tx.data.forPublic!.nonRevertibleAccumulatedData = PrivateToPublicAccumulatedDataBuilder.fromPublicAccumulatedData( - tx.data.forPublic!.nonRevertibleAccumulatedData, - ) - .withGasUsed(privateNonRevertibleGasUsed) - .build(); + const expectedTotalGasForFee = expectedTotalGas.sub(expectedTeardownGasUsed).add(teardownGasLimits); + const expectedTxFee = expectedTotalGasForFee.computeFee(gasFees); + expect(output.transactionFee).toEqual(expectedTxFee); + + // we keep the non-revertible data. + expect(countAccumulatedItems(output.accumulatedData.nullifiers)).toBe(4); + expect(output.accumulatedData.nullifiers.slice(0, 4)).toEqual([ + new Fr(7777), + new Fr(8888), + siloNullifier(contractAddress, new Fr(1)), + siloNullifier(contractAddress, new Fr(4)), + ]); + }); - const contractAddress = revertibleRequests[0].callContext.contractAddress; - const nestedContractAddress = contractAddress; // same contract - const contractSlotA = fr(0x100); - const contractSlotB = fr(0x150); - const contractSlotC = fr(0x200); + it('includes a transaction that reverts in teardown', async function () { + const tx = mockTxWithPublicCalls({ + numberOfSetupCalls: 1, + numberOfAppLogicCalls: 1, + hasPublicTeardownCall: true, + }); - // Keep gas numbers below MAX_L2_GAS_PER_ENQUEUED_CALL or we need - // to separately compute available start gas and "effective" start gas - // for each enqueued call after applying that max. - const privateGasUsed = tx.data.forPublic!.nonRevertibleAccumulatedData.gasUsed.add( - tx.data.forPublic!.revertibleAccumulatedData.gasUsed, - ); - const initialGas = gasLimits.sub(privateGasUsed); - const setupGasUsed = Gas.from({ l2Gas: 1e4 }); - const appGasUsed = Gas.from({ l2Gas: 2e4, daGas: 2e4 }); - const teardownGasUsed = Gas.from({ l2Gas: 3e4, daGas: 3e4 }); - const afterSetupGas = initialGas.sub(setupGasUsed); - const afterAppGas = afterSetupGas.sub(appGasUsed); - const afterTeardownGas = teardownGasLimits.sub(teardownGasUsed); - - // Gas used for computing fees is different to the total gas consumed. - // For computing fees, the teardownGasLimits specified in the gasSettings is used instead of the actual gas in the teardown phase. - const feeGasUsed = privateGasUsed.add(setupGasUsed).add(appGasUsed).add(teardownGasLimits); - // Inclusion fee plus block gas fees times fee gas used - const expectedTxFee = - tx.data.constants.txContext.gasSettings.inclusionFee.toNumber() + - feeGasUsed.l2Gas * GasFees.default().feePerL2Gas.toNumber() + - feeGasUsed.daGas * GasFees.default().feePerDaGas.toNumber(); - - const simulatorResults: EnqueuedPublicCallExecutionResult[] = [ - // Setup - PublicExecutionResultBuilder.empty().build({ - // starts with initialGas, ends with - endGasLeft: afterSetupGas, - }), - - // App Logic - PublicExecutionResultBuilder.empty().build({ - // starts with afterSetupGas, ends with - endGasLeft: afterAppGas, - }), - - // Teardown - PublicExecutionResultBuilder.empty().build({ - // starts with tearDownGas, ends with - endGasLeft: afterTeardownGas, - }), - ]; + const teardownFailure = new SimulationError('Simulation Failed in teardown', []); - const mockedSimulatorExecutions = [ + const contractAddress = AztecAddress.fromBigInt(112233n); + mockPublicExecutor([ // SETUP - (_stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - return Promise.resolve(simulatorResults[0]); + async (stateManager: AvmPersistableStateManager) => { + // mock nullifiers on the state manager + await stateManager.writeNullifier(contractAddress, new Fr(1)); + return PublicExecutionResultBuilder.empty(); }, // APP LOGIC async (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(contractAddress, contractSlotA, fr(0x101)); - stateManager.writeStorage(contractAddress, contractSlotB, fr(0x151)); - await stateManager.readStorage(contractAddress, contractSlotA); - return Promise.resolve(simulatorResults[1]); + // mock nullifiers on the state manager + await stateManager.writeNullifier(contractAddress, new Fr(2)); + await stateManager.writeNullifier(contractAddress, new Fr(3)); + return PublicExecutionResultBuilder.empty(); }, async (stateManager: AvmPersistableStateManager) => { - // mock storage writes on the state manager - stateManager.writeStorage(nestedContractAddress, contractSlotA, fr(0x103)); - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x201)); - await stateManager.readStorage(nestedContractAddress, contractSlotA); - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x102)); - stateManager.writeStorage(nestedContractAddress, contractSlotC, fr(0x152)); - await stateManager.readStorage(nestedContractAddress, contractSlotA); - return Promise.resolve(simulatorResults[2]); + // mock nullifiers on the state manager + await stateManager.writeNullifier(contractAddress, new Fr(4)); + return PublicExecutionResultBuilder.empty().withReverted(teardownFailure); }, - ]; - - for (const executeSimulator of mockedSimulatorExecutions) { - publicExecutor.simulate.mockImplementationOnce( - (stateManager: AvmPersistableStateManager): Promise => { - return executeSimulator(stateManager); - }, - ); - } - - const tailSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTail'); + ]); const txResult = await processor.process(tx); - expect(txResult.processedPhases).toHaveLength(3); - expect(txResult.processedPhases[0]).toEqual(expect.objectContaining({ revertReason: undefined })); - expect(txResult.processedPhases[1]).toEqual(expect.objectContaining({ revertReason: undefined })); - expect(txResult.processedPhases[2]).toEqual(expect.objectContaining({ revertReason: undefined })); + expect(txResult.processedPhases).toEqual([ + expect.objectContaining({ phase: TxExecutionPhase.SETUP, revertReason: undefined }), + expect.objectContaining({ phase: TxExecutionPhase.APP_LOGIC, revertReason: undefined }), + expect.objectContaining({ phase: TxExecutionPhase.TEARDOWN, revertReason: teardownFailure }), + ]); + expect(txResult.revertCode).toEqual(RevertCode.TEARDOWN_REVERTED); + expect(txResult.revertReason).toBe(teardownFailure); + + const expectedSetupGas = txPrivateNonRevertibleGasUsed.add(enqueuedCallGasUsed); + const expectedAppLogicGas = txPrivateRevertibleGasUsed.add(enqueuedCallGasUsed); + const { l2Gas: teardownL2Gas } = enqueuedCallGasUsed; + // All data emitted from teardown were discarded. daGas set to 0. + const expectedTeardownGasUsed = Gas.from({ daGas: 0, l2Gas: teardownL2Gas }); + const expectedTotalGas = expectedSetupGas.add(expectedAppLogicGas).add(expectedTeardownGasUsed); expect(txResult.gasUsed).toEqual({ - [PublicKernelPhase.SETUP]: setupGasUsed, - [PublicKernelPhase.APP_LOGIC]: appGasUsed, - [PublicKernelPhase.TEARDOWN]: teardownGasUsed, + totalGas: expectedTotalGas, + teardownGas: expectedTeardownGasUsed, }); - expect(txResult.revertReason).toBe(undefined); - - expect(tailSpy).toHaveBeenCalledTimes(1); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); - - const expectedSimulateCall = (availableGas: Partial>, txFee: number) => [ - expect.anything(), // AvmPersistableStateManager - expect.anything(), // PublicExecutionRequest - expect.anything(), // GlobalVariables - Gas.from(availableGas), - new Fr(txFee), - ]; - expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); - expect(publicExecutor.simulate).toHaveBeenNthCalledWith(1, ...expectedSimulateCall(initialGas, 0)); - expect(publicExecutor.simulate).toHaveBeenNthCalledWith(2, ...expectedSimulateCall(afterSetupGas, 0)); - expect(publicExecutor.simulate).toHaveBeenNthCalledWith( - 3, - ...expectedSimulateCall(teardownGasLimits, expectedTxFee), - ); + const availableGasForSetup = gasLimits.sub(teardownGasLimits).sub(txPrivateNonRevertibleGasUsed); + const allocatedAppLogicGas = availableGasForSetup.sub(txPrivateRevertibleGasUsed).sub(enqueuedCallGasUsed); + expectAvailableGasForCalls([availableGasForSetup, allocatedAppLogicGas, teardownGasLimits]); const output = txResult.avmProvingRequest!.inputs.output; - expect(output.transactionFee.toNumber()).toEqual(expectedTxFee); - const numPublicDataWrites = 3; - expect(arrayNonEmptyLength(output.accumulatedData.publicDataWrites, PublicDataWrite.isEmpty)).toBe( - numPublicDataWrites, - ); - expect(output.accumulatedData.publicDataWrites.slice(0, numPublicDataWrites)).toEqual([ - // squashed - // new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotA), fr(0x101)), - new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotB), fr(0x151)), - new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotA), fr(0x103)), - // squashed - // new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotC), fr(0x201)), - // new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotC), fr(0x102)), - new PublicDataWrite(computePublicDataTreeLeafSlot(contractAddress, contractSlotC), fr(0x152)), + // Should still charge the full teardownGasLimits for fee even though teardown reverted. + const expectedTotalGasForFee = expectedTotalGas.sub(expectedTeardownGasUsed).add(teardownGasLimits); + const expectedTxFee = expectedTotalGasForFee.computeFee(gasFees); + expect(output.transactionFee).toEqual(expectedTxFee); + + // We keep the non-revertible data. + expect(countAccumulatedItems(output.accumulatedData.nullifiers)).toBe(3); + expect(output.accumulatedData.nullifiers.slice(0, 3)).toEqual([ + new Fr(7777), + new Fr(8888), + // new Fr(9999), // TODO: Data in app logic should be kept if teardown reverts. + siloNullifier(contractAddress, new Fr(1)), + // siloNullifier(contractAddress, new Fr(2)), + // siloNullifier(contractAddress, new Fr(2)), ]); - - expect(arrayNonEmptyLength(output.accumulatedData.unencryptedLogsHashes, l => l.logHash.isEmpty())).toBe(0); }); - it('runs a tx with only teardown', async function () { - const tx = mockTx(1, { - numberOfNonRevertiblePublicCallRequests: 0, - numberOfRevertiblePublicCallRequests: 0, - hasPublicTeardownCallRequest: true, - }); - - const gasLimits = Gas.from({ l2Gas: 1e9, daGas: 1e9 }); - const teardownGas = Gas.from({ l2Gas: 1e7, daGas: 1e7 }); - tx.data.constants.txContext.gasSettings = GasSettings.from({ - gasLimits: gasLimits, - teardownGasLimits: teardownGas, - inclusionFee: new Fr(1e4), - maxFeesPerGas: { feePerDaGas: new Fr(10), feePerL2Gas: new Fr(10) }, + it('includes a transaction that reverts in app logic and teardown', async function () { + const tx = mockTxWithPublicCalls({ + numberOfSetupCalls: 1, + numberOfAppLogicCalls: 1, + hasPublicTeardownCall: true, }); - const teardownGasUsed = Gas.from({ l2Gas: 1e6, daGas: 1e6 }); - - const simulatorResults: EnqueuedPublicCallExecutionResult[] = [ - // Teardown - PublicExecutionResultBuilder.empty().build({ - // starts with tearDownGas, ends with - endGasLeft: teardownGas.sub(teardownGasUsed), - }), - ]; - - publicExecutor.simulate.mockImplementationOnce(() => Promise.resolve(simulatorResults[0])); - - const tailSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTail'); + const appLogicFailure = new SimulationError('Simulation Failed in app logic', []); + const teardownFailure = new SimulationError('Simulation Failed in teardown', []); + const contractAddress = AztecAddress.fromBigInt(112233n); + mockPublicExecutor([ + // SETUP + async (stateManager: AvmPersistableStateManager) => { + // mock nullifiers on the state manager + await stateManager.writeNullifier(contractAddress, new Fr(1)); + return PublicExecutionResultBuilder.empty(); + }, + // APP LOGIC + async (stateManager: AvmPersistableStateManager) => { + // mock nullifiers on the state manager + await stateManager.writeNullifier(contractAddress, new Fr(2)); + await stateManager.writeNullifier(contractAddress, new Fr(3)); + return PublicExecutionResultBuilder.empty().withReverted(appLogicFailure); + }, + async (stateManager: AvmPersistableStateManager) => { + // mock nullifiers on the state manager + await stateManager.writeNullifier(contractAddress, new Fr(4)); + return PublicExecutionResultBuilder.empty().withReverted(teardownFailure); + }, + ]); const txResult = await processor.process(tx); - expect(txResult.processedPhases).toHaveLength(1); - expect(txResult.processedPhases[0]).toEqual(expect.objectContaining({ revertReason: undefined })); + expect(txResult.processedPhases).toHaveLength(3); + expect(txResult.processedPhases).toEqual([ + expect.objectContaining({ phase: TxExecutionPhase.SETUP, revertReason: undefined }), + expect.objectContaining({ phase: TxExecutionPhase.APP_LOGIC, revertReason: appLogicFailure }), + expect.objectContaining({ phase: TxExecutionPhase.TEARDOWN, revertReason: teardownFailure }), + ]); + expect(txResult.revertCode).toEqual(RevertCode.BOTH_REVERTED); + // tx reports app logic failure + expect(txResult.revertReason).toBe(appLogicFailure); + + const expectedSetupGas = txPrivateNonRevertibleGasUsed.add(enqueuedCallGasUsed); + const { l2Gas: appLogicL2Gas } = txPrivateRevertibleGasUsed.add(enqueuedCallGasUsed); + // All data emitted from app logic were discarded. daGas set to 0. + const expectedAppLogicGas = Gas.from({ daGas: 0, l2Gas: appLogicL2Gas }); + const { l2Gas: teardownL2Gas } = enqueuedCallGasUsed; + // All data emitted from teardown were discarded. daGas set to 0. + const expectedTeardownGasUsed = Gas.from({ daGas: 0, l2Gas: teardownL2Gas }); + const expectedTotalGas = expectedSetupGas.add(expectedAppLogicGas).add(expectedTeardownGasUsed); expect(txResult.gasUsed).toEqual({ - [PublicKernelPhase.TEARDOWN]: teardownGasUsed, + totalGas: expectedTotalGas, + teardownGas: expectedTeardownGasUsed, }); - expect(txResult.revertReason).toBe(undefined); - expect(tailSpy).toHaveBeenCalledTimes(1); + const availableGasForSetup = gasLimits.sub(teardownGasLimits).sub(txPrivateNonRevertibleGasUsed); + const allocatedAppLogicGas = availableGasForSetup.sub(txPrivateRevertibleGasUsed).sub(enqueuedCallGasUsed); + expectAvailableGasForCalls([availableGasForSetup, allocatedAppLogicGas, teardownGasLimits]); + + const output = txResult.avmProvingRequest!.inputs.output; + + // Should still charge the full teardownGasLimits for fee even though teardown reverted. + const expectedTotalGasForFee = expectedTotalGas.sub(expectedTeardownGasUsed).add(teardownGasLimits); + const expectedTxFee = expectedTotalGasForFee.computeFee(gasFees); + expect(output.transactionFee).toEqual(expectedTxFee); + + // we keep the non-revertible data + expect(countAccumulatedItems(output.accumulatedData.nullifiers)).toBe(3); + expect(output.accumulatedData.nullifiers.slice(0, 3)).toEqual([ + new Fr(7777), + new Fr(8888), + siloNullifier(contractAddress, new Fr(1)), + ]); }); }); diff --git a/yarn-project/simulator/src/public/enqueued_calls_processor.ts b/yarn-project/simulator/src/public/enqueued_calls_processor.ts index 918e33cb0e3..dc4bf63a502 100644 --- a/yarn-project/simulator/src/public/enqueued_calls_processor.ts +++ b/yarn-project/simulator/src/public/enqueued_calls_processor.ts @@ -1,11 +1,12 @@ import { type AvmProvingRequest, + type GasUsed, type MerkleTreeReadOperations, type NestedProcessReturnValues, type PublicExecutionRequest, - PublicKernelPhase, type SimulationError, type Tx, + TxExecutionPhase, } from '@aztec/circuit-types'; import { AvmAccumulatedData, @@ -15,6 +16,7 @@ import { EnqueuedCallData, Fr, Gas, + type GasSettings, type GlobalVariables, type Header, type KernelCircuitPublicInputs, @@ -55,10 +57,10 @@ import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simul import { PublicKernelTailSimulator } from './public_kernel_tail_simulator.js'; import { PublicSideEffectTrace } from './side_effect_trace.js'; -const PhaseIsRevertible: Record = { - [PublicKernelPhase.SETUP]: false, - [PublicKernelPhase.APP_LOGIC]: true, - [PublicKernelPhase.TEARDOWN]: true, +const PhaseIsRevertible: Record = { + [TxExecutionPhase.SETUP]: false, + [TxExecutionPhase.APP_LOGIC]: true, + [TxExecutionPhase.TEARDOWN]: true, }; type PublicPhaseResult = { @@ -67,7 +69,7 @@ type PublicPhaseResult = { publicKernelOutput: PublicKernelCircuitPublicInputs; /** Return values of simulating complete callstack */ returnValues: NestedProcessReturnValues[]; - /** Gas used during the execution this phase */ + /** Gas used during the execution of a phase, including the gas used for the data emitted in the same phase from private */ gasUsed: Gas; /** Time spent for the execution this phase */ durationMs: number; @@ -77,22 +79,21 @@ type PublicPhaseResult = { revertReason?: SimulationError; }; -type PublicPhaseGasUsed = Partial>; +type PhaseGasUsed = Record; export type ProcessedPhase = { - phase: PublicKernelPhase; + phase: TxExecutionPhase; durationMs: number; + returnValues: NestedProcessReturnValues[]; revertReason?: SimulationError; }; export type TxPublicCallsResult = { avmProvingRequest: AvmProvingRequest; - /** Return values of simulating complete callstack */ - returnValues: NestedProcessReturnValues[]; /** Gas used during the execution this tx */ - gasUsed: PublicPhaseGasUsed; - /** Revert reason, if any */ + gasUsed: GasUsed; revertCode: RevertCode; + /** Revert reason, if any */ revertReason?: SimulationError; processedPhases: ProcessedPhase[]; }; @@ -139,13 +140,13 @@ export class EnqueuedCallsProcessor { ); } - static getExecutionRequestsByPhase(tx: Tx, phase: PublicKernelPhase): PublicExecutionRequest[] { + static getExecutionRequestsByPhase(tx: Tx, phase: TxExecutionPhase): PublicExecutionRequest[] { switch (phase) { - case PublicKernelPhase.SETUP: + case TxExecutionPhase.SETUP: return tx.getNonRevertiblePublicExecutionRequests(); - case PublicKernelPhase.APP_LOGIC: + case TxExecutionPhase.APP_LOGIC: return tx.getRevertiblePublicExecutionRequests(); - case PublicKernelPhase.TEARDOWN: { + case TxExecutionPhase.TEARDOWN: { const request = tx.getPublicTeardownExecutionRequest(); return request ? [request] : []; } @@ -154,13 +155,13 @@ export class EnqueuedCallsProcessor { } } - static getCallRequestsByPhase(tx: Tx, phase: PublicKernelPhase): PublicCallRequest[] { + static getCallRequestsByPhase(tx: Tx, phase: TxExecutionPhase): PublicCallRequest[] { switch (phase) { - case PublicKernelPhase.SETUP: + case TxExecutionPhase.SETUP: return tx.data.getNonRevertiblePublicCallRequests(); - case PublicKernelPhase.APP_LOGIC: + case TxExecutionPhase.APP_LOGIC: return tx.data.getRevertiblePublicCallRequests(); - case PublicKernelPhase.TEARDOWN: { + case TxExecutionPhase.TEARDOWN: { const request = tx.data.getTeardownPublicCallRequest(); return request ? [request] : []; } @@ -172,17 +173,18 @@ export class EnqueuedCallsProcessor { async process(tx: Tx): Promise { this.log.verbose(`Processing tx ${tx.getTxHash()}`); - const phases: PublicKernelPhase[] = [ - PublicKernelPhase.SETUP, - PublicKernelPhase.APP_LOGIC, - PublicKernelPhase.TEARDOWN, - ]; + const constants = CombinedConstantData.combine(tx.data.constants, this.globalVariables); + const gasSettings = constants.txContext.gasSettings; + const phases: TxExecutionPhase[] = [TxExecutionPhase.SETUP, TxExecutionPhase.APP_LOGIC, TxExecutionPhase.TEARDOWN]; + const requireTeardown = tx.data.hasTeardownPublicCallRequest(); const processedPhases: ProcessedPhase[] = []; - const gasUsed: PublicPhaseGasUsed = {}; + let phaseGasUsed: PhaseGasUsed = { + [TxExecutionPhase.SETUP]: tx.data.forPublic!.nonRevertibleAccumulatedData.gasUsed, + [TxExecutionPhase.APP_LOGIC]: tx.data.forPublic!.revertibleAccumulatedData.gasUsed, + [TxExecutionPhase.TEARDOWN]: Gas.empty(), + }; let avmProvingRequest: AvmProvingRequest; let publicKernelOutput = this.getPublicKernelCircuitPublicInputs(tx.data); - let isFromPrivate = true; - let returnValues: NestedProcessReturnValues[] = []; let revertReason: SimulationError | undefined; const nonRevertibleNullifiersFromPrivate = publicKernelOutput.endNonRevertibleData.nullifiers @@ -218,7 +220,7 @@ export class EnqueuedCallsProcessor { for (let i = 0; i < phases.length; i++) { const phase = phases[i]; let stateManagerForPhase: AvmPersistableStateManager; - if (phase === PublicKernelPhase.SETUP) { + if (phase === TxExecutionPhase.SETUP) { // don't need to fork for setup since it's non-revertible // (if setup fails, transaction is thrown out) stateManagerForPhase = txStateManager; @@ -229,14 +231,23 @@ export class EnqueuedCallsProcessor { } const callRequests = EnqueuedCallsProcessor.getCallRequestsByPhase(tx, phase); if (callRequests.length) { + const allocatedGas = this.getAllocatedGasForPhase(gasSettings, phase, phaseGasUsed, requireTeardown); + const transactionFee = + phase !== TxExecutionPhase.TEARDOWN + ? Fr.ZERO + : this.getTransactionFee(gasSettings, phaseGasUsed, requireTeardown); + const executionRequests = EnqueuedCallsProcessor.getExecutionRequestsByPhase(tx, phase); const result = await this.processPhase( + phase, tx, + constants, callRequests, executionRequests, publicKernelOutput, - phase, - isFromPrivate, + allocatedGas, + phaseGasUsed[phase] /* initialGasUsed */, + transactionFee, stateManagerForPhase, ).catch(async err => { await this.worldStateDB.rollbackToCommit(); @@ -244,17 +255,12 @@ export class EnqueuedCallsProcessor { }); publicKernelOutput = result.publicKernelOutput; - isFromPrivate = false; // Propagate only one avmProvingRequest of a function call for now, so that we know it's still provable. // Eventually this will be the proof for the entire public call stack. avmProvingRequest = result.avmProvingRequest; - if (phase === PublicKernelPhase.APP_LOGIC) { - returnValues = result.returnValues; - } - - if (phase !== PublicKernelPhase.SETUP) { + if (phase !== TxExecutionPhase.SETUP) { txStateManager.mergeStateForPhase( stateManagerForPhase, callRequests, @@ -263,14 +269,18 @@ export class EnqueuedCallsProcessor { ); } - gasUsed[phase] = result.gasUsed; - processedPhases.push({ phase, durationMs: result.durationMs, + returnValues: result.returnValues, revertReason: result.revertReason, }); + phaseGasUsed = { + ...phaseGasUsed, + [phase]: result.gasUsed, + }; + revertReason ??= result.revertReason; } } @@ -283,12 +293,17 @@ export class EnqueuedCallsProcessor { }, ); - const transactionFee = this.getTransactionFee(tx, publicKernelOutput); + const transactionFee = this.getTransactionFee(gasSettings, phaseGasUsed, requireTeardown); avmProvingRequest!.inputs.output = this.generateAvmCircuitPublicInputs(tx, tailKernelOutput, transactionFee); + const totalGas = Object.values(phaseGasUsed).reduce((total, gas) => total.add(gas), Gas.empty()); + const gasUsed = { + totalGas, + teardownGas: phaseGasUsed[TxExecutionPhase.TEARDOWN], + }; + return { avmProvingRequest: avmProvingRequest!, - returnValues, gasUsed, processedPhases, revertCode: tailKernelOutput.revertCode, @@ -297,24 +312,32 @@ export class EnqueuedCallsProcessor { } private async processPhase( + phase: TxExecutionPhase, tx: Tx, + constants: CombinedConstantData, callRequests: PublicCallRequest[], executionRequests: PublicExecutionRequest[], previousPublicKernelOutput: PublicKernelCircuitPublicInputs, - phase: PublicKernelPhase, - isFromPrivate: boolean, + allocatedGas: Gas, + initialGasUsed: Gas, + transactionFee: Fr, txStateManager: AvmPersistableStateManager, ): Promise { - this.log.debug(`Beginning processing in phase ${PublicKernelPhase[phase]} for tx ${tx.getTxHash()}`); + this.log.debug(`Beginning processing in phase ${TxExecutionPhase[phase]} for tx ${tx.getTxHash()}`); const phaseTimer = new Timer(); const returnValues: NestedProcessReturnValues[] = []; let avmProvingRequest: AvmProvingRequest; let publicKernelOutput = previousPublicKernelOutput; - let gasUsed = Gas.empty(); + let availableGas = allocatedGas.sub(initialGasUsed); + let gasUsedInPhase = initialGasUsed; let reverted: boolean = false; let revertReason: SimulationError | undefined; - for (let i = callRequests.length - 1; i >= 0 && !revertReason; i--) { + for (let i = callRequests.length - 1; i >= 0; i--) { + if (reverted) { + break; + } + const callRequest = callRequests[i]; const executionRequest = executionRequests[i]; @@ -326,19 +349,14 @@ export class EnqueuedCallsProcessor { // if so, this should only add contracts that were deployed during private app logic. await this.worldStateDB.addNewContracts(tx); - const availableGas = this.getAvailableGas(tx, publicKernelOutput, phase); - const transactionFee = - phase !== PublicKernelPhase.TEARDOWN ? Fr.ZERO : this.getTransactionFee(tx, publicKernelOutput); - // each enqueued call starts with an incremented side effect counter const enqueuedCallStateManager = txStateManager.fork(/*incrementSideEffectCounter=*/ true); const enqueuedCallResult = await this.enqueuedCallSimulator.simulate( callRequest, executionRequest, - publicKernelOutput, + constants, availableGas, transactionFee, - phase, enqueuedCallStateManager, ); @@ -357,12 +375,16 @@ export class EnqueuedCallsProcessor { avmProvingRequest = enqueuedCallResult.avmProvingRequest; returnValues.push(enqueuedCallResult.returnValues); - gasUsed = gasUsed.add(enqueuedCallResult.gasUsed); + availableGas = availableGas.sub(enqueuedCallResult.gasUsed); + gasUsedInPhase = gasUsedInPhase.add(enqueuedCallResult.gasUsed); reverted = enqueuedCallResult.reverted; - revertReason ??= enqueuedCallResult.revertReason; + revertReason = enqueuedCallResult.revertReason; // Instead of operating on worldStateDB here, do we do AvmPersistableStateManager.revert() or return()? - if (revertReason) { + if (reverted) { + // Clear daGas as no data will be emitted. + gasUsedInPhase = Gas.from({ daGas: 0, l2Gas: gasUsedInPhase.l2Gas }); + // TODO(#6464): Should we allow emitting contracts in the private setup phase? // if so, this is removing contracts deployed in private setup // You can't submit contracts in public, so this is only relevant for private-created @@ -372,63 +394,61 @@ export class EnqueuedCallsProcessor { await this.worldStateDB.removeNewContracts(tx); tx.filterRevertedLogs(publicKernelOutput); } else { - // TODO(#6470): we should be adding contracts deployed in those logs to the publicContractsDB tx.unencryptedLogs.addFunctionLogs([enqueuedCallResult.newUnencryptedLogs]); } - const output = await this.runMergeKernelCircuit( - publicKernelOutput, - enqueuedCallResult.kernelOutput, - isFromPrivate, - ); + const output = await this.runMergeKernelCircuit(publicKernelOutput, enqueuedCallResult.kernelOutput); publicKernelOutput = output; - isFromPrivate = false; } return { avmProvingRequest: avmProvingRequest!, publicKernelOutput, durationMs: phaseTimer.ms(), - gasUsed, - returnValues: returnValues, - reverted: reverted, + gasUsed: gasUsedInPhase, + returnValues, + reverted, revertReason, }; } - private getAvailableGas( - tx: Tx, - previousPublicKernelOutput: PublicKernelCircuitPublicInputs, - phase: PublicKernelPhase, + private getAllocatedGasForPhase( + gasSettings: GasSettings, + phase: TxExecutionPhase, + phaseGasUsed: PhaseGasUsed, + requireTeardown: boolean, ) { - if (phase === PublicKernelPhase.TEARDOWN) { - return tx.data.constants.txContext.gasSettings.getTeardownLimits(); + const gasForTeardown = requireTeardown ? gasSettings.teardownGasLimits : Gas.empty(); + if (phase === TxExecutionPhase.TEARDOWN) { + return gasForTeardown; + } + + const gasForSetup = gasSettings.gasLimits.sub(gasForTeardown); + if (phase === TxExecutionPhase.SETUP) { + return gasForSetup; } else { - return tx.data.constants.txContext.gasSettings - .getLimits() // No need to subtract teardown limits since they are already included in end.gasUsed - .sub(previousPublicKernelOutput.end.gasUsed) - .sub(previousPublicKernelOutput.endNonRevertibleData.gasUsed); + const gasForAppLogic = gasForSetup.sub(phaseGasUsed[TxExecutionPhase.SETUP]); + return gasForAppLogic; } } - private getTransactionFee(tx: Tx, previousPublicKernelOutput: PublicKernelCircuitPublicInputs): Fr { - const gasSettings = tx.data.constants.txContext.gasSettings; + private getTransactionFee(gasSettings: GasSettings, phaseGasUsed: PhaseGasUsed, requireTeardown: boolean): Fr { const gasFees = this.globalVariables.gasFees; - // No need to add teardown limits since they are already included in end.gasUsed - const gasUsed = previousPublicKernelOutput.end.gasUsed - .add(previousPublicKernelOutput.endNonRevertibleData.gasUsed) - .add(gasSettings.teardownGasLimits); - const txFee = gasSettings.inclusionFee.add(gasUsed.computeFee(gasFees)); - this.log.debug(`Computed tx fee`, { txFee, gasUsed: inspect(gasUsed), gasFees: inspect(gasFees) }); + const txFee = phaseGasUsed[TxExecutionPhase.SETUP] + .add(phaseGasUsed[TxExecutionPhase.APP_LOGIC]) + .add(requireTeardown ? gasSettings.teardownGasLimits : Gas.empty()) + .computeFee(gasFees); + + this.log.debug(`Computed tx fee`, { txFee, gasUsed: inspect(phaseGasUsed), gasFees: inspect(gasFees) }); + return txFee; } private async runMergeKernelCircuit( previousOutput: PublicKernelCircuitPublicInputs, enqueuedCallData: VMCircuitPublicInputs, - isFromPrivate: boolean, ): Promise { - const previousKernel = this.getPreviousKernelData(previousOutput, isFromPrivate); + const previousKernel = this.getPreviousKernelData(previousOutput); // The proof is not used in simulation. const vmProof = makeEmptyProof(); @@ -439,10 +459,7 @@ export class EnqueuedCallsProcessor { return await this.publicKernelSimulator.publicKernelCircuitMerge(inputs); } - private getPreviousKernelData( - previousOutput: PublicKernelCircuitPublicInputs, - _isFromPrivate: boolean, - ): PublicKernelData { + private getPreviousKernelData(previousOutput: PublicKernelCircuitPublicInputs): PublicKernelData { // The proof is not used in simulation. const proof = makeEmptyRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH); diff --git a/yarn-project/simulator/src/public/public_processor.test.ts b/yarn-project/simulator/src/public/public_processor.test.ts index b8d7869f06f..99cf8f52db2 100644 --- a/yarn-project/simulator/src/public/public_processor.test.ts +++ b/yarn-project/simulator/src/public/public_processor.test.ts @@ -2,379 +2,301 @@ import { type MerkleTreeWriteOperations, type ProcessedTx, type ProcessedTxHandler, + ProvingRequestType, SimulationError, type TreeInfo, type TxValidator, mockTx, } from '@aztec/circuit-types'; import { - AppendOnlyTreeSnapshot, + AvmCircuitInputs, + type AvmCircuitPublicInputs, AztecAddress, - ClientIvcProof, Fr, + Gas, GasFees, - GasSettings, GlobalVariables, Header, - PUBLIC_DATA_TREE_HEIGHT, - PartialStateReference, - PublicDataTreeLeafPreimage, PublicDataWrite, - StateReference, + RevertCode, + countAccumulatedItems, } from '@aztec/circuits.js'; import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; -import { openTmpStore } from '@aztec/kv-store/utils'; -import { type AppendOnlyTree, Poseidon, StandardTree, newTree } from '@aztec/merkle-tree'; -import { type PublicExecutor, WASMSimulator, computeFeePayerBalanceLeafSlot } from '@aztec/simulator'; import { NoopTelemetryClient } from '@aztec/telemetry-client/noop'; import { type MockProxy, mock } from 'jest-mock-extended'; -import { PublicExecutionResultBuilder } from '../mocks/fixtures.js'; +import { type EnqueuedCallsProcessor, type TxPublicCallsResult } from './enqueued_calls_processor.js'; +import { computeFeePayerBalanceLeafSlot } from './fee_payment.js'; import { type WorldStateDB } from './public_db_sources.js'; -import { RealPublicKernelCircuitSimulator } from './public_kernel.js'; -import { type PublicKernelCircuitSimulator } from './public_kernel_circuit_simulator.js'; import { PublicProcessor } from './public_processor.js'; describe('public_processor', () => { let db: MockProxy; - let publicExecutor: MockProxy; let worldStateDB: MockProxy; + let enqueuedCallsProcessor: MockProxy; let handler: MockProxy; - let proof: ClientIvcProof; let root: Buffer; + let mockedEnqueuedCallsResult: TxPublicCallsResult; + let mockedAvmOutput: AvmCircuitPublicInputs; let processor: PublicProcessor; + const gasFees = GasFees.from({ feePerDaGas: new Fr(2), feePerL2Gas: new Fr(3) }); + const globalVariables = GlobalVariables.from({ ...GlobalVariables.empty(), gasFees }); + + const mockPrivateOnlyTx = ({ seed = 1, feePayer }: { seed?: number; feePayer?: AztecAddress } = {}) => + mockTx(seed, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 0, feePayer }); + + const mockTxWithPublicCalls = ({ seed = 1, feePayer }: { seed?: number; feePayer?: AztecAddress } = {}) => + mockTx(seed, { numberOfNonRevertiblePublicCallRequests: 1, numberOfRevertiblePublicCallRequests: 1, feePayer }); + beforeEach(() => { db = mock(); - publicExecutor = mock(); worldStateDB = mock(); + enqueuedCallsProcessor = mock(); handler = mock(); - proof = ClientIvcProof.empty(); root = Buffer.alloc(32, 5); + const avmCircuitInputs = AvmCircuitInputs.empty(); + mockedAvmOutput = avmCircuitInputs.output; + mockedEnqueuedCallsResult = { + avmProvingRequest: { + type: ProvingRequestType.PUBLIC_VM, + inputs: avmCircuitInputs, + }, + gasUsed: { + totalGas: Gas.empty(), + teardownGas: Gas.empty(), + }, + revertCode: RevertCode.OK, + processedPhases: [], + }; + db.getTreeInfo.mockResolvedValue({ root } as TreeInfo); - worldStateDB.storageRead.mockResolvedValue(Fr.ZERO); - }); - describe('with mock circuits', () => { - let publicKernel: MockProxy; + worldStateDB.storageRead.mockResolvedValue(Fr.ZERO); - beforeEach(() => { - publicKernel = mock(); - processor = PublicProcessor.create( - db, - publicExecutor, - publicKernel, - GlobalVariables.empty(), - Header.empty(), - worldStateDB, - new NoopTelemetryClient(), - ); + enqueuedCallsProcessor.process.mockImplementation(() => { + return Promise.resolve(mockedEnqueuedCallsResult); }); - it('skips txs without public execution requests', async function () { - const tx = mockTx(1, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 0 }); + processor = new PublicProcessor( + db, + globalVariables, + Header.empty(), + worldStateDB, + enqueuedCallsProcessor, + new NoopTelemetryClient(), + ); + }); + + describe('process txs', () => { + it('process private-only txs', async function () { + const tx = mockPrivateOnlyTx(); - const hash = tx.getTxHash(); const [processed, failed] = await processor.process([tx], 1, handler); expect(processed.length).toBe(1); - expect(processed[0]).toEqual( - expect.objectContaining({ - hash, - data: tx.data, - }), - ); + expect(processed[0].hash).toEqual(tx.getTxHash()); + expect(processed[0].data).toEqual(tx.data); expect(failed).toEqual([]); expect(handler.addNewTx).toHaveBeenCalledWith(processed[0]); }); - it('returns failed txs without aborting entire operation', async function () { - publicExecutor.simulate.mockRejectedValue(new SimulationError(`Failed`, [])); + it('runs a tx with enqueued public calls', async function () { + const tx = mockTxWithPublicCalls(); - const tx = mockTx(1, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 1 }); const [processed, failed] = await processor.process([tx], 1, handler); - expect(processed).toEqual([]); - expect(failed[0].tx).toEqual(tx); - expect(failed[0].error).toEqual(new SimulationError(`Failed`, [])); - expect(worldStateDB.commit).toHaveBeenCalledTimes(0); - expect(worldStateDB.rollbackToCommit).toHaveBeenCalledTimes(1); - expect(handler.addNewTx).toHaveBeenCalledTimes(0); - }); - }); + expect(processed.length).toBe(1); + expect(processed[0].hash).toEqual(tx.getTxHash()); + expect(processed[0].data).toEqual(tx.data); + expect(failed).toEqual([]); - describe('with actual circuits', () => { - let publicKernel: PublicKernelCircuitSimulator; - let publicDataTree: AppendOnlyTree; - - beforeAll(async () => { - publicDataTree = await newTree( - StandardTree, - openTmpStore(), - new Poseidon(), - 'PublicData', - Fr, - PUBLIC_DATA_TREE_HEIGHT, - 1, // Add a default low leaf for the public data hints to be proved against. - ); + expect(worldStateDB.commit).toHaveBeenCalledTimes(1); }); - beforeEach(() => { - const snap = new AppendOnlyTreeSnapshot( - Fr.fromBuffer(publicDataTree.getRoot(true)), - Number(publicDataTree.getNumLeaves(true)), - ); + it('runs a tx with reverted enqueued public calls', async function () { + const tx = mockTxWithPublicCalls(); - const header = Header.empty(); - const stateReference = new StateReference( - header.state.l1ToL2MessageTree, - new PartialStateReference(header.state.partial.noteHashTree, header.state.partial.nullifierTree, snap), - ); - // Clone the whole state because somewhere down the line (AbstractPhaseManager) the public data root is modified in the referenced header directly :/ - header.state = StateReference.fromBuffer(stateReference.toBuffer()); + mockedEnqueuedCallsResult.revertCode = RevertCode.APP_LOGIC_REVERTED; + mockedEnqueuedCallsResult.revertReason = new SimulationError(`Failed`, []); - db.getStateReference.mockResolvedValue(stateReference); - db.getSiblingPath.mockResolvedValue(publicDataTree.getSiblingPath(0n, false)); - db.getPreviousValueIndex.mockResolvedValue({ index: 0n, alreadyPresent: true }); - db.getLeafPreimage.mockResolvedValue(new PublicDataTreeLeafPreimage(new Fr(0), new Fr(0), new Fr(0), 0n)); + const [processed, failed] = await processor.process([tx], 1, handler); - publicExecutor.simulate.mockImplementation((_stateManager, _request) => { - const result = PublicExecutionResultBuilder.empty().build(); - return Promise.resolve(result); - }); + expect(processed.length).toBe(1); + expect(processed[0].hash).toEqual(tx.getTxHash()); + expect(failed).toEqual([]); - publicKernel = new RealPublicKernelCircuitSimulator(new WASMSimulator()); - processor = PublicProcessor.create( - db, - publicExecutor, - publicKernel, - GlobalVariables.from({ ...GlobalVariables.empty(), gasFees: GasFees.default() }), - header, - worldStateDB, - new NoopTelemetryClient(), - ); + expect(worldStateDB.commit).toHaveBeenCalledTimes(1); }); - it('runs a tx with enqueued public calls', async function () { - const tx = mockTx(1, { - numberOfNonRevertiblePublicCallRequests: 0, - numberOfRevertiblePublicCallRequests: 2, - hasLogs: true, - }); + it('returns failed txs without aborting entire operation', async function () { + enqueuedCallsProcessor.process.mockRejectedValue(new SimulationError(`Failed`, [])); + const tx = mockTxWithPublicCalls(); const [processed, failed] = await processor.process([tx], 1, handler); - expect(failed.map(f => f.error)).toEqual([]); - expect(processed).toHaveLength(1); - expect(processed[0].hash).toEqual(tx.getTxHash()); - expect(processed[0].clientIvcProof).toEqual(proof); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(2); - expect(worldStateDB.commit).toHaveBeenCalledTimes(1); - expect(worldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); - - // we keep the logs - expect(processed[0].txEffect.encryptedLogs.getTotalLogCount()).toBe(6); - expect(processed[0].txEffect.unencryptedLogs.getTotalLogCount()).toBe(2); + expect(processed).toEqual([]); + expect(failed.length).toBe(1); + expect(failed[0].tx).toEqual(tx); + expect(failed[0].error).toEqual(new SimulationError(`Failed`, [])); - expect(handler.addNewTx).toHaveBeenCalledWith(processed[0]); + expect(worldStateDB.commit).toHaveBeenCalledTimes(0); + expect(handler.addNewTx).toHaveBeenCalledTimes(0); }); it('does not attempt to overfill a block', async function () { - const txs = Array.from([1, 2, 3], index => - mockTx(index, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 1 }), - ); + const txs = Array.from([1, 2, 3], seed => mockPrivateOnlyTx({ seed })); // We are passing 3 txs but only 2 can fit in the block const [processed, failed] = await processor.process(txs, 2, handler); - expect(processed).toHaveLength(2); + expect(processed.length).toBe(2); expect(processed[0].hash).toEqual(txs[0].getTxHash()); - expect(processed[0].clientIvcProof).toEqual(proof); expect(processed[1].hash).toEqual(txs[1].getTxHash()); - expect(processed[1].clientIvcProof).toEqual(proof); - expect(failed).toHaveLength(0); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(2); + expect(failed).toEqual([]); + expect(worldStateDB.commit).toHaveBeenCalledTimes(2); - expect(worldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); expect(handler.addNewTx).toHaveBeenCalledWith(processed[0]); expect(handler.addNewTx).toHaveBeenCalledWith(processed[1]); }); it('does not send a transaction to the prover if validation fails', async function () { - const tx = mockTx(1, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 1 }); + const tx = mockPrivateOnlyTx(); const txValidator: MockProxy> = mock(); txValidator.validateTxs.mockRejectedValue([[], [tx]]); const [processed, failed] = await processor.process([tx], 1, handler, txValidator); - expect(processed).toHaveLength(0); - expect(failed).toHaveLength(1); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(1); + expect(processed).toEqual([]); + expect(failed.length).toBe(1); + expect(failed[0].tx).toEqual(tx); expect(handler.addNewTx).toHaveBeenCalledTimes(0); }); + }); + + describe('with fee payer', () => { + const feePayer = AztecAddress.fromBigInt(123123n); + const initialBalance = new Fr(1000); + + beforeEach(() => { + worldStateDB.storageRead.mockResolvedValue(initialBalance); + + worldStateDB.storageWrite.mockImplementation((address: AztecAddress, slot: Fr) => + Promise.resolve(computePublicDataTreeLeafSlot(address, slot).toBigInt()), + ); + }); - describe('with fee payer', () => { - it('injects balance update with no public calls', async function () { - const feePayer = AztecAddress.random(); - const initialBalance = BigInt(1e12); - const inclusionFee = 100n; - const tx = mockTx(1, { - numberOfNonRevertiblePublicCallRequests: 0, - numberOfRevertiblePublicCallRequests: 0, - feePayer, - }); - - tx.data.constants.txContext.gasSettings = GasSettings.from({ - ...GasSettings.default(), - inclusionFee: new Fr(inclusionFee), - }); - - worldStateDB.storageRead.mockResolvedValue(new Fr(initialBalance)); - worldStateDB.storageWrite.mockImplementation((address: AztecAddress, slot: Fr) => - Promise.resolve(computePublicDataTreeLeafSlot(address, slot).toBigInt()), - ); - - const [processed, failed] = await processor.process([tx], 1, handler); - - expect(failed.map(f => f.error)).toEqual([]); - expect(processed).toHaveLength(1); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(0); - expect(worldStateDB.commit).toHaveBeenCalledTimes(1); - expect(worldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); - expect(worldStateDB.storageWrite).toHaveBeenCalledTimes(1); - expect(processed[0].data.feePayer).toEqual(feePayer); - expect(processed[0].txEffect.publicDataWrites[0]).toEqual( - new PublicDataWrite(computeFeePayerBalanceLeafSlot(feePayer), new Fr(initialBalance - inclusionFee)), - ); - - expect(handler.addNewTx).toHaveBeenCalledWith(processed[0]); + it('injects balance update with no public calls', async function () { + const tx = mockPrivateOnlyTx({ + feePayer, }); - it('injects balance update with public enqueued call', async function () { - const feePayer = AztecAddress.random(); - const initialBalance = BigInt(1e12); - const inclusionFee = 100n; - const tx = mockTx(1, { - numberOfNonRevertiblePublicCallRequests: 0, - numberOfRevertiblePublicCallRequests: 2, - feePayer, - }); - - tx.data.constants.txContext.gasSettings = GasSettings.from({ - ...GasSettings.default(), - inclusionFee: new Fr(inclusionFee), - }); - - worldStateDB.storageRead.mockResolvedValue(new Fr(initialBalance)); - worldStateDB.storageWrite.mockImplementation((address: AztecAddress, slot: Fr) => - Promise.resolve(computePublicDataTreeLeafSlot(address, slot).toBigInt()), - ); - - const [processed, failed] = await processor.process([tx], 1, handler); - - expect(failed.map(f => f.error)).toEqual([]); - expect(processed).toHaveLength(1); - expect(processed[0].hash).toEqual(tx.getTxHash()); - expect(processed[0].clientIvcProof).toEqual(proof); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(2); - expect(worldStateDB.commit).toHaveBeenCalledTimes(1); - expect(worldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); - expect(worldStateDB.storageWrite).toHaveBeenCalledTimes(1); - expect(processed[0].data.feePayer).toEqual(feePayer); - - const transactionFee = processed[0].txEffect.transactionFee.toBigInt(); - expect(processed[0].txEffect.publicDataWrites[0]).toEqual( - new PublicDataWrite(computeFeePayerBalanceLeafSlot(feePayer), new Fr(initialBalance - transactionFee)), - ); - - expect(handler.addNewTx).toHaveBeenCalledWith(processed[0]); + const privateGasUsed = new Gas(12, 34); + tx.data.forRollup!.end.gasUsed = privateGasUsed; + + const txFee = privateGasUsed.computeFee(globalVariables.gasFees); + + const [processed, failed] = await processor.process([tx], 1, handler); + + expect(processed).toHaveLength(1); + expect(processed[0].data.feePayer).toEqual(feePayer); + expect(processed[0].txEffect.publicDataWrites[0]).toEqual( + new PublicDataWrite(computeFeePayerBalanceLeafSlot(feePayer), initialBalance.sub(txFee)), + ); + expect(failed).toEqual([]); + + expect(worldStateDB.commit).toHaveBeenCalledTimes(1); + expect(worldStateDB.storageWrite).toHaveBeenCalledTimes(1); + + expect(handler.addNewTx).toHaveBeenCalledWith(processed[0]); + }); + + it('injects balance update with public enqueued call', async function () { + const txFee = new Fr(567); + mockedAvmOutput.transactionFee = txFee; + + const tx = mockTxWithPublicCalls({ + feePayer, }); - it('tweaks existing balance update from claim', async function () { - const feePayer = AztecAddress.random(); - const initialBalance = BigInt(1e12); - const inclusionFee = 100n; - const tx = mockTx(1, { - numberOfNonRevertiblePublicCallRequests: 0, - numberOfRevertiblePublicCallRequests: 0, - feePayer, - }); - - tx.data.constants.txContext.gasSettings = GasSettings.from({ - ...GasSettings.default(), - inclusionFee: new Fr(inclusionFee), - }); - - worldStateDB.storageRead.mockResolvedValue(Fr.ZERO); - worldStateDB.storageWrite.mockImplementation((address: AztecAddress, slot: Fr) => - Promise.resolve(computePublicDataTreeLeafSlot(address, slot).toBigInt()), - ); - - // TODO: Find a better way to test this. - // This is wrong. Private kernel tail cannot output any publicDataWrites. - tx.data.forRollup!.end.publicDataWrites[0] = new PublicDataWrite( - computeFeePayerBalanceLeafSlot(feePayer), - new Fr(initialBalance), - ); - - const [processed, failed] = await processor.process([tx], 1, handler); - - expect(failed.map(f => f.error)).toEqual([]); - expect(processed).toHaveLength(1); - expect(processed[0].hash).toEqual(tx.getTxHash()); - expect(processed[0].clientIvcProof).toEqual(proof); - expect(worldStateDB.commit).toHaveBeenCalledTimes(1); - expect(worldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); - expect(worldStateDB.storageWrite).toHaveBeenCalledTimes(1); - expect(processed[0].data.feePayer).toEqual(feePayer); - - const transactionFee = processed[0].txEffect.transactionFee.toBigInt(); - expect(processed[0].txEffect.publicDataWrites[0]).toEqual( - new PublicDataWrite(computeFeePayerBalanceLeafSlot(feePayer), new Fr(initialBalance - transactionFee)), - ); - - expect(handler.addNewTx).toHaveBeenCalledWith(processed[0]); + const [processed, failed] = await processor.process([tx], 1, handler); + + expect(processed).toHaveLength(1); + expect(processed[0].hash).toEqual(tx.getTxHash()); + expect(processed[0].data.feePayer).toEqual(feePayer); + expect(processed[0].txEffect.transactionFee).toEqual(txFee); + expect(processed[0].txEffect.publicDataWrites[0]).toEqual( + new PublicDataWrite(computeFeePayerBalanceLeafSlot(feePayer), initialBalance.sub(txFee)), + ); + expect(failed).toEqual([]); + + expect(worldStateDB.commit).toHaveBeenCalledTimes(1); + expect(worldStateDB.storageWrite).toHaveBeenCalledTimes(1); + + expect(handler.addNewTx).toHaveBeenCalledWith(processed[0]); + }); + + it('tweaks existing balance update from claim', async function () { + const txFee = new Fr(567); + const pendingBalance = new Fr(2000); + const pendingWrites = [ + new PublicDataWrite(AztecAddress.fromBigInt(888n), new Fr(999)), + new PublicDataWrite(computeFeePayerBalanceLeafSlot(feePayer), pendingBalance), + new PublicDataWrite(AztecAddress.fromBigInt(666n), new Fr(777)), + ]; + mockedAvmOutput.transactionFee = txFee; + mockedAvmOutput.accumulatedData.publicDataWrites[0] = pendingWrites[0]; + mockedAvmOutput.accumulatedData.publicDataWrites[1] = pendingWrites[1]; + mockedAvmOutput.accumulatedData.publicDataWrites[2] = pendingWrites[2]; + + const tx = mockTxWithPublicCalls({ + feePayer, }); - it('rejects tx if fee payer has not enough balance', async function () { - const feePayer = AztecAddress.random(); - const initialBalance = 1n; - const inclusionFee = 100n; - const tx = mockTx(1, { - numberOfNonRevertiblePublicCallRequests: 0, - numberOfRevertiblePublicCallRequests: 0, - feePayer, - }); - - tx.data.constants.txContext.gasSettings = GasSettings.from({ - ...GasSettings.default(), - inclusionFee: new Fr(inclusionFee), - }); - - worldStateDB.storageRead.mockResolvedValue(new Fr(initialBalance)); - worldStateDB.storageWrite.mockImplementation((address: AztecAddress, slot: Fr) => - Promise.resolve(computePublicDataTreeLeafSlot(address, slot).toBigInt()), - ); - - const [processed, failed] = await processor.process([tx], 1, handler); - - expect(processed).toHaveLength(0); - expect(failed).toHaveLength(1); - expect(failed[0].error.message).toMatch(/Not enough balance/i); - expect(publicExecutor.simulate).toHaveBeenCalledTimes(0); - expect(worldStateDB.commit).toHaveBeenCalledTimes(0); - expect(worldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); - expect(worldStateDB.storageWrite).toHaveBeenCalledTimes(0); + const [processed, failed] = await processor.process([tx], 1, handler); + + expect(processed).toHaveLength(1); + expect(processed[0].hash).toEqual(tx.getTxHash()); + expect(processed[0].data.feePayer).toEqual(feePayer); + expect(countAccumulatedItems(processed[0].txEffect.publicDataWrites)).toBe(3); + expect(processed[0].txEffect.publicDataWrites.slice(0, 3)).toEqual([ + pendingWrites[0], + new PublicDataWrite(computeFeePayerBalanceLeafSlot(feePayer), pendingBalance.sub(txFee)), + pendingWrites[2], + ]); + expect(failed).toEqual([]); + + expect(worldStateDB.commit).toHaveBeenCalledTimes(1); + expect(worldStateDB.storageWrite).toHaveBeenCalledTimes(1); + + expect(handler.addNewTx).toHaveBeenCalledWith(processed[0]); + }); + + it('rejects tx if fee payer has not enough balance', async function () { + const txFee = initialBalance.add(new Fr(1)); + mockedAvmOutput.transactionFee = txFee; + + const tx = mockTxWithPublicCalls({ + feePayer, }); + + const [processed, failed] = await processor.process([tx], 1, handler); + + expect(processed).toEqual([]); + expect(failed).toHaveLength(1); + expect(failed[0].error.message).toMatch(/Not enough balance/i); + + expect(worldStateDB.commit).toHaveBeenCalledTimes(0); + expect(worldStateDB.storageWrite).toHaveBeenCalledTimes(0); }); }); }); diff --git a/yarn-project/simulator/src/public/public_processor.ts b/yarn-project/simulator/src/public/public_processor.ts index ef43a25b28a..886e81d36d4 100644 --- a/yarn-project/simulator/src/public/public_processor.ts +++ b/yarn-project/simulator/src/public/public_processor.ts @@ -5,8 +5,8 @@ import { NestedProcessReturnValues, type ProcessedTx, type ProcessedTxHandler, - PublicKernelPhase, Tx, + TxExecutionPhase, type TxValidator, makeProcessedTxFromPrivateOnlyTx, makeProcessedTxFromTxWithPublicCalls, @@ -15,7 +15,6 @@ import { ContractClassRegisteredEvent, type ContractDataSource, Fr, - Gas, type GlobalVariables, type Header, MAX_NOTE_HASHES_PER_TX, @@ -88,8 +87,6 @@ export class PublicProcessor { private metrics: PublicProcessorMetrics; constructor( protected db: MerkleTreeWriteOperations, - protected publicExecutor: PublicExecutor, - protected publicKernel: PublicKernelCircuitSimulator, protected globalVariables: GlobalVariables, protected historicalHeader: Header, protected worldStateDB: WorldStateDB, @@ -120,8 +117,6 @@ export class PublicProcessor { return new PublicProcessor( db, - publicExecutor, - publicKernelSimulator, globalVariables, historicalHeader, worldStateDB, @@ -277,17 +272,14 @@ export class PublicProcessor { } private async processPrivateOnlyTx(tx: Tx): Promise<[ProcessedTx]> { - const txData = tx.data.toKernelCircuitPublicInputs(); - const gasFees = this.globalVariables.gasFees; - const transactionFee = txData.end.gasUsed - .computeFee(gasFees) - .add(txData.constants.txContext.gasSettings.inclusionFee); + const accumulatedData = tx.data.forRollup!.end; + const transactionFee = accumulatedData.gasUsed.computeFee(gasFees); const feePaymentPublicDataWrite = await this.getFeePaymentPublicDataWrite( - txData.end.publicDataWrites, + accumulatedData.publicDataWrites, transactionFee, - txData.feePayer, + tx.data.feePayer, ); const processedTx = makeProcessedTxFromPrivateOnlyTx( @@ -305,14 +297,8 @@ export class PublicProcessor { private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, NestedProcessReturnValues[]]> { const timer = new Timer(); - const { - avmProvingRequest, - returnValues, - revertCode, - revertReason, - gasUsed: phaseGasUsed, - processedPhases, - } = await this.enqueuedCallsProcessor.process(tx); + const { avmProvingRequest, gasUsed, revertCode, revertReason, processedPhases } = + await this.enqueuedCallsProcessor.process(tx); if (!avmProvingRequest) { this.metrics.recordFailedTx(); @@ -344,15 +330,6 @@ export class PublicProcessor { tx.data.feePayer, ); - const privateGasUsed = tx.data.forPublic!.revertibleAccumulatedData.gasUsed.add( - tx.data.forPublic!.nonRevertibleAccumulatedData.gasUsed, - ); - const publicGasUsed = Object.values(phaseGasUsed).reduce((total, gas) => total.add(gas), Gas.empty()); - const gasUsed = { - totalGas: privateGasUsed.add(publicGasUsed), - teardownGas: phaseGasUsed[PublicKernelPhase.TEARDOWN] ?? Gas.empty(), - }; - const processedTx = makeProcessedTxFromTxWithPublicCalls( tx, avmProvingRequest, @@ -362,6 +339,8 @@ export class PublicProcessor { revertReason, ); + const returnValues = processedPhases.find(({ phase }) => phase === TxExecutionPhase.APP_LOGIC)?.returnValues ?? []; + return [processedTx, returnValues]; } } diff --git a/yarn-project/simulator/src/public/public_processor_metrics.ts b/yarn-project/simulator/src/public/public_processor_metrics.ts index 6ddbef9fc27..ff54a7d152d 100644 --- a/yarn-project/simulator/src/public/public_processor_metrics.ts +++ b/yarn-project/simulator/src/public/public_processor_metrics.ts @@ -1,4 +1,4 @@ -import { type PublicKernelPhase } from '@aztec/circuit-types'; +import { type TxExecutionPhase } from '@aztec/circuit-types'; import { type ContractClassRegisteredEvent } from '@aztec/circuits.js'; import { Attributes, @@ -56,7 +56,7 @@ export class PublicProcessorMetrics { }); } - recordPhaseDuration(phaseName: PublicKernelPhase, durationMs: number) { + recordPhaseDuration(phaseName: TxExecutionPhase, durationMs: number) { this.phaseCount.add(1, { [Attributes.TX_PHASE_NAME]: phaseName, [Attributes.OK]: true }); this.phaseDuration.record(Math.ceil(durationMs), { [Attributes.TX_PHASE_NAME]: phaseName }); } @@ -75,7 +75,7 @@ export class PublicProcessorMetrics { }); } - recordRevertedPhase(phaseName: PublicKernelPhase) { + recordRevertedPhase(phaseName: TxExecutionPhase) { this.phaseCount.add(1, { [Attributes.TX_PHASE_NAME]: phaseName, [Attributes.OK]: false }); } diff --git a/yarn-project/txe/src/oracle/txe_oracle.ts b/yarn-project/txe/src/oracle/txe_oracle.ts index 242c8be2ae7..571b53a32c8 100644 --- a/yarn-project/txe/src/oracle/txe_oracle.ts +++ b/yarn-project/txe/src/oracle/txe_oracle.ts @@ -16,11 +16,13 @@ import { CombinedConstantData, type ContractInstance, type ContractInstanceWithAddress, + DEFAULT_GAS_LIMIT, Gas, Header, IndexedTaggingSecret, type KeyValidationRequest, type L1_TO_L2_MSG_TREE_HEIGHT, + MAX_L2_GAS_PER_ENQUEUED_CALL, NULLIFIER_SUBTREE_HEIGHT, type NULLIFIER_TREE_HEIGHT, type NullifierLeafPreimage, @@ -680,7 +682,7 @@ export class TXE implements TypedOracle { const executionResult = await simulator.simulateIsolatedEnqueuedCall( execution, combinedConstantData.globalVariables, - Gas.test(), + /*allocatedGas*/ new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_ENQUEUED_CALL), /*transactionFee=*/ Fr.ONE, /*startSideEffectCounter=*/ this.sideEffectCounter, ); From bc33b80e091649e676c84cd2be8d607c7eefc1ab Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 11 Nov 2024 18:49:31 +0000 Subject: [PATCH 3/7] Fix and fmt. --- .../src/public_kernel_merge.nr | 50 +------------------ yarn-project/cli-wallet/src/cmds/cancel_tx.ts | 2 +- .../src/block_builder/light.test.ts | 15 +++--- 3 files changed, 9 insertions(+), 58 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_merge.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_merge.nr index 72213f0b032..6fac486040f 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_merge.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_merge.nr @@ -45,7 +45,7 @@ mod tests { }; use dep::types::{ abis::{ - accumulated_data::PublicAccumulatedDataArrayLengths, gas::Gas, + accumulated_data::PublicAccumulatedDataArrayLengths, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, max_block_number::MaxBlockNumber, validation_requests::PublicValidationRequestArrayLengths, @@ -112,24 +112,6 @@ mod tests { kernel.execute() } - pub fn populate_gas_used(&mut self) { - // Transaction gas limit is 1k. - self.previous_kernel.tx_context.gas_settings.gas_limits = Gas::new(1000, 1000); - - // Non-revertible has used 200. - self.previous_kernel.gas_used = Gas::new(200, 200); - - // Revertible has used 100. - self.previous_revertible.gas_used = Gas::new(100, 100); - - // So this call starts with 700 gas left - self.enqueued_call.start_gas_left = Gas::new(700, 700); - // And uses 250. - self.enqueued_call.gas_used = Gas::new(250, 250); - // Ending with 450 left. - self.enqueued_call.end_gas_left = Gas::new(450, 450); - } - pub fn succeeded(&mut self) { let _ = self.execute(); } @@ -178,34 +160,4 @@ mod tests { [prev_calls[0].inner], // Public call requests can only be propagated from previous kernel. ); } - - #[test] - unconstrained fn updates_revertible_gas_used() { - let mut builder = PublicKernelMergeCircuitPrivateInputsBuilder::new(); - builder.phase = PublicKernelPhase.APP_LOGIC; - - builder.populate_gas_used(); - - // So the updated gas used by revertible must go up by 250, and non-revertible must stay the same. - let output = builder.execute(); - assert_eq(output.end_non_revertible.gas_used, Gas::new(200, 200)); - assert_eq(output.end.gas_used, Gas::new(350, 350)); - } - - #[test] - unconstrained fn handle_revert_in_app_logic() { - let mut builder = PublicKernelMergeCircuitPrivateInputsBuilder::new(); - builder.phase = PublicKernelPhase.APP_LOGIC; - builder.enqueued_call.revert_code = 1; - - builder.populate_gas_used(); - - let output = builder.execute(); - - assert_eq(output.revert_code, 1); - - // gas_used is propagated even when reverts. - assert_eq(output.end_non_revertible.gas_used, Gas::new(200, 200)); - assert_eq(output.end.gas_used, Gas::new(350, 350)); - } } diff --git a/yarn-project/cli-wallet/src/cmds/cancel_tx.ts b/yarn-project/cli-wallet/src/cmds/cancel_tx.ts index a37d76235d5..c0fb4812f77 100644 --- a/yarn-project/cli-wallet/src/cmds/cancel_tx.ts +++ b/yarn-project/cli-wallet/src/cmds/cancel_tx.ts @@ -1,6 +1,6 @@ import { type AccountWalletWithSecretKey, type FeePaymentMethod, SentTx, type TxHash, TxStatus } from '@aztec/aztec.js'; import { type FeeOptions } from '@aztec/aztec.js/entrypoint'; -import { Fr, type GasSettings } from '@aztec/circuits.js'; +import { type Fr, type GasSettings } from '@aztec/circuits.js'; import { type LogFn } from '@aztec/foundation/log'; export async function cancelTx( diff --git a/yarn-project/sequencer-client/src/block_builder/light.test.ts b/yarn-project/sequencer-client/src/block_builder/light.test.ts index a09eb9579dd..8304e8f510f 100644 --- a/yarn-project/sequencer-client/src/block_builder/light.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/light.test.ts @@ -65,7 +65,7 @@ jest.setTimeout(50_000); describe('LightBlockBuilder', () => { let simulator: ServerCircuitProver; let logger: DebugLogger; - let globals: GlobalVariables; + let globalVariables: GlobalVariables; let l1ToL2Messages: Fr[]; let vkTreeRoot: Fr; @@ -85,7 +85,7 @@ describe('LightBlockBuilder', () => { }); beforeEach(async () => { - globals = makeGlobalVariables(1, { chainId: Fr.ZERO, version: Fr.ZERO }); + globalVariables = makeGlobalVariables(1, { chainId: Fr.ZERO, version: Fr.ZERO }); l1ToL2Messages = times(7, i => new Fr(i + 1)); fork = await db.fork(); expectsFork = await db.fork(); @@ -184,8 +184,7 @@ describe('LightBlockBuilder', () => { const makeTx = (i: number) => makeBloatedProcessedTx({ header: fork.getInitialHeader(), - chainId: globals.chainId, - version: globals.version, + globalVariables, vkTreeRoot, protocolContractTreeRoot, seed: i + 1, @@ -195,7 +194,7 @@ describe('LightBlockBuilder', () => { // Builds the block header using the ts block builder const buildHeader = async (txs: ProcessedTx[], l1ToL2Messages: Fr[]) => { const txCount = Math.max(2, txs.length); - await builder.startNewBlock(txCount, globals, l1ToL2Messages); + await builder.startNewBlock(txCount, globalVariables, l1ToL2Messages); for (const tx of txs) { await builder.addNewTx(tx); } @@ -219,8 +218,8 @@ describe('LightBlockBuilder', () => { ...times(2 - txs.length, () => makeEmptyProcessedTx( expectsFork.getInitialHeader(), - globals.chainId, - globals.version, + globalVariables.chainId, + globalVariables.version, vkTreeRoot, protocolContractTreeRoot, ), @@ -268,7 +267,7 @@ describe('LightBlockBuilder', () => { const vkPath = getVKSiblingPath(vkIndex); const vkData = new VkWitnessData(TubeVk, vkIndex, vkPath); const tubeData = new PrivateTubeData(tx.data.toKernelCircuitPublicInputs(), emptyProof, vkData); - const hints = await buildBaseRollupHints(tx, globals, expectsFork); + const hints = await buildBaseRollupHints(tx, globalVariables, expectsFork); const inputs = new PrivateBaseRollupInputs(tubeData, hints); const result = await simulator.getPrivateBaseRollupProof(inputs); rollupOutputs.push(result.inputs); From 79f1207fa0eb0c879ea02f70ac27d0d09da7ba7d Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 11 Nov 2024 19:27:59 +0000 Subject: [PATCH 4/7] Fix. --- .../src/protocol_contract_data.ts | 14 +++++++------- .../simulator/src/public/public_processor.test.ts | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/yarn-project/protocol-contracts/src/protocol_contract_data.ts b/yarn-project/protocol-contracts/src/protocol_contract_data.ts index a210ce408ca..12eb0f6b395 100644 --- a/yarn-project/protocol-contracts/src/protocol_contract_data.ts +++ b/yarn-project/protocol-contracts/src/protocol_contract_data.ts @@ -50,14 +50,14 @@ export const ProtocolContractAddress: Record }; export const ProtocolContractLeaf = { - AuthRegistry: Fr.fromString('0x0931f3bf89563f3898ae9650851083cd560ad800c2e3c561c3853eec4dd7ea8b'), - ContractInstanceDeployer: Fr.fromString('0x266ea4c9917455daa905c1dd1a10753714c6d0369b6f2fe23feeca6de556d164'), - ContractClassRegisterer: Fr.fromString('0x1ccb7a219f72a851089e956d527997b01068d5a28c9ae96b35ebeb45f068af23'), - MultiCallEntrypoint: Fr.fromString('0x000b94baf1a8eebc1b280aa1f162f88ef4fa9da6bf4ebbe5bbb2a40386a91314'), - FeeJuice: Fr.fromString('0x1e47caab3dd90f26b91e14e003a5ceab8d069b654174f6d698cdec9b1a6d19d5'), - Router: Fr.fromString('0x00827d5a8aedb9627d9e5de04735600a4dbb817d4a2f51281aab991699f5de99'), + AuthRegistry: Fr.fromString('0x2eb96058b49c7563788c0ce69fe3fdeb5152c61a156e7a458d8b538365a87ab8'), + ContractInstanceDeployer: Fr.fromString('0x0e075e4452cefd29253761dd0e4d031703f295c1e59682a32acfcf59fe63d70e'), + ContractClassRegisterer: Fr.fromString('0x0e187c0485643e4f12d770134cdb4e3ea4b5ca3c0f7c6e6204393d1d76eba26c'), + MultiCallEntrypoint: Fr.fromString('0x20ca5aa14dc605a895ff96ec3812b7c0a3471996fffaf3e2d84ea430ff670e96'), + FeeJuice: Fr.fromString('0x1632b50cac161bd4097e549a3eea90fd0b8119750d040fb9f8ec27fa42a4be5d'), + Router: Fr.fromString('0x0b7c6404e8e27e11ac25e2c2bf063a2980f657c4ca9ac171c643dea9a9df7ca2'), }; export const protocolContractTreeRoot = Fr.fromString( - '0x23b9c035580b52d82ff309cd3c70acf754be2070d861572faf90fa403001ac24', + '0x23ab55baea8fdff99a32d1d0cf4fce2ccb28ca79cfa5d2b50bda1dcd8b8619df', ); diff --git a/yarn-project/simulator/src/public/public_processor.test.ts b/yarn-project/simulator/src/public/public_processor.test.ts index 99cf8f52db2..c62c7c5e4c6 100644 --- a/yarn-project/simulator/src/public/public_processor.test.ts +++ b/yarn-project/simulator/src/public/public_processor.test.ts @@ -249,9 +249,9 @@ describe('public_processor', () => { const txFee = new Fr(567); const pendingBalance = new Fr(2000); const pendingWrites = [ - new PublicDataWrite(AztecAddress.fromBigInt(888n), new Fr(999)), + new PublicDataWrite(new Fr(888n), new Fr(999)), new PublicDataWrite(computeFeePayerBalanceLeafSlot(feePayer), pendingBalance), - new PublicDataWrite(AztecAddress.fromBigInt(666n), new Fr(777)), + new PublicDataWrite(new Fr(666n), new Fr(777)), ]; mockedAvmOutput.transactionFee = txFee; mockedAvmOutput.accumulatedData.publicDataWrites[0] = pendingWrites[0]; From 8bea3d3880f930b9f9d8a89ac89143aecbc32245 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 12 Nov 2024 10:19:40 +0000 Subject: [PATCH 5/7] Combine gas used from private to public. --- .../src/core/libraries/ConstantsGen.sol | 6 +- .../src/components/tail_output_composer.nr | 2 +- .../src/components/tail_output_validator.nr | 4 +- .../tail_to_public_output_composer.nr | 24 ++- .../meter_gas_used.nr | 24 ++- .../tail_to_public_output_validator.nr | 29 +-- .../src/private_kernel_tail.nr | 6 +- .../src/private_kernel_tail_to_public.nr | 138 ++++++------- .../tail_output_validator_builder/mod.nr | 2 +- .../validate_gas_used.nr | 8 +- .../meter_gas_used.nr | 118 ++++++----- .../tail_to_public_output_composer.nr | 55 +++--- .../components/public_tail_output_composer.nr | 4 + .../combine_data.nr | 1 - .../src/base/private_base_rollup.nr | 2 +- .../rollup-lib/src/base/public_base_rollup.nr | 2 +- .../combined_accumulated_data.nr | 9 +- .../private_to_public_accumulated_data.nr | 7 +- ...vate_to_public_accumulated_data_builder.nr | 5 - .../src/abis/avm_circuit_public_inputs.nr | 6 + .../kernel_circuit_public_inputs.nr | 7 +- ..._to_public_kernel_circuit_public_inputs.nr | 10 +- .../crates/types/src/constants.nr | 11 +- .../crates/types/src/tests/fixture_builder.nr | 4 +- .../src/contract/get_gas_limits.test.ts | 2 +- .../circuit-types/src/test/factories.ts | 7 +- .../circuit-types/src/tx/processed_tx.ts | 2 +- .../circuit-types/src/tx/simulated_tx.ts | 2 +- yarn-project/circuits.js/src/constants.gen.ts | 6 +- .../structs/avm/avm_circuit_public_inputs.ts | 7 + .../kernel/combined_accumulated_data.ts | 11 +- .../kernel/kernel_circuit_public_inputs.ts | 8 + ...ivate_kernel_tail_circuit_public_inputs.ts | 12 ++ .../private_to_public_accumulated_data.ts | 10 +- ...vate_to_public_accumulated_data_builder.ts | 11 +- ..._to_public_kernel_circuit_public_inputs.ts | 5 + .../circuits.js/src/tests/factories.ts | 8 +- .../src/type_conversion.ts | 10 +- .../src/tx_validator/gas_validator.test.ts | 2 +- yarn-project/simulator/src/mocks/fixtures.ts | 2 +- .../public/enqueued_calls_processor.test.ts | 186 +++++++++--------- .../src/public/enqueued_calls_processor.ts | 74 +++---- .../src/public/public_processor.test.ts | 2 +- .../simulator/src/public/public_processor.ts | 4 +- 44 files changed, 419 insertions(+), 436 deletions(-) diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 2eb54b0ec29..a7ced68ea06 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -214,17 +214,17 @@ library Constants { uint256 internal constant NUM_PUBLIC_VALIDATION_REQUEST_ARRAYS = 5; uint256 internal constant PUBLIC_VALIDATION_REQUESTS_LENGTH = 834; uint256 internal constant PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 3; - uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = 547; + uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = 545; uint256 internal constant TX_CONSTANT_DATA_LENGTH = 34; uint256 internal constant COMBINED_CONSTANT_DATA_LENGTH = 43; uint256 internal constant PRIVATE_ACCUMULATED_DATA_LENGTH = 1064; uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1877; uint256 internal constant PUBLIC_ACCUMULATED_DATA_LENGTH = 1023; uint256 internal constant NUM_PUBLIC_ACCUMULATED_DATA_ARRAYS = 8; - uint256 internal constant PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 578; + uint256 internal constant PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 576; uint256 internal constant PRIVATE_TO_AVM_ACCUMULATED_DATA_LENGTH = 160; uint256 internal constant NUM_PRIVATE_TO_AVM_ACCUMULATED_DATA_ARRAYS = 3; - uint256 internal constant PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1198; + uint256 internal constant PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1196; uint256 internal constant PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2931; uint256 internal constant VM_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2340; uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 600; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer.nr index 8ed0ab04f1f..f0741e993d5 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_composer.nr @@ -35,6 +35,7 @@ impl TailOutputComposer { let mut output = KernelCircuitPublicInputs::empty(); output.rollup_validation_requests = source.validation_requests.for_rollup; output.end = self.build_combined_accumulated_data(); + output.gas_used = meter_gas_used(output.end); output.constants = CombinedConstantData::combine(source.constants, GlobalVariables::empty()); output.fee_payer = source.fee_payer; @@ -65,7 +66,6 @@ impl TailOutputComposer { 0, |len, l: ScopedLogHash| len + l.log_hash.length, ); - data.gas_used = meter_gas_used(data); data } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_validator.nr index fee3e43e133..4c3df11c4a8 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_output_validator.nr @@ -127,9 +127,9 @@ impl TailOutputValidator { fn validate_gas_used(self) { let gas_used = meter_gas_used(self.output.end); - assert(self.output.end.gas_used == gas_used, "incorrect metered gas used"); + assert(self.output.gas_used == gas_used, "incorrect metered gas used"); let limits = self.previous_kernel.constants.tx_context.gas_settings.gas_limits; - assert(self.output.end.gas_used.within(limits), "The gas used exceeds the gas limits"); + assert(self.output.gas_used.within(limits), "The gas used exceeds the gas limits"); } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer.nr index f5d48debad2..05191951423 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer.nr @@ -4,15 +4,11 @@ mod split_to_public; use crate::components::{ private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer, tail_to_public_output_composer::{ - meter_gas_used::{meter_gas_used_non_revertible, meter_gas_used_revertible}, - split_to_public::split_to_public, + meter_gas_used::meter_gas_used, split_to_public::split_to_public, }, }; -use dep::types::abis::{ - kernel_circuit_public_inputs::{ - PrivateKernelCircuitPublicInputs, PrivateToPublicKernelCircuitPublicInputs, - }, - validation_requests::PublicValidationRequests, +use dep::types::abis::kernel_circuit_public_inputs::{ + PrivateKernelCircuitPublicInputs, PrivateToPublicKernelCircuitPublicInputs, }; pub struct TailToPublicOutputComposer { @@ -31,14 +27,15 @@ impl TailToPublicOutputComposer { pub unconstrained fn finish(self) -> PrivateToPublicKernelCircuitPublicInputs { let source = self.output_composer.public_inputs; - let mut (non_revertible_accumulated_data, revertible_accumulated_data) = + let (non_revertible_accumulated_data, revertible_accumulated_data) = split_to_public(source.end, source.min_revertible_side_effect_counter); - non_revertible_accumulated_data.gas_used = - meter_gas_used_non_revertible(non_revertible_accumulated_data); - - revertible_accumulated_data.gas_used = - meter_gas_used_revertible(revertible_accumulated_data); + let gas_used = meter_gas_used( + non_revertible_accumulated_data, + revertible_accumulated_data, + source.public_teardown_call_request, + source.constants.tx_context.gas_settings.teardown_gas_limits, + ); let mut output = PrivateToPublicKernelCircuitPublicInputs { constants: source.constants, @@ -46,6 +43,7 @@ impl TailToPublicOutputComposer { non_revertible_accumulated_data, revertible_accumulated_data, public_teardown_call_request: source.public_teardown_call_request, + gas_used, fee_payer: source.fee_payer, }; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/meter_gas_used.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/meter_gas_used.nr index 16e11c7f4a9..54cd0bf3aa9 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/meter_gas_used.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_composer/meter_gas_used.nr @@ -3,15 +3,17 @@ use dep::types::{ accumulated_data::PrivateToPublicAccumulatedData, gas::Gas, log_hash::{LogHash, ScopedLogHash}, + public_call_request::PublicCallRequest, }, constants::{ DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, FIXED_AVM_STARTUP_L2_GAS, L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, }, + traits::is_empty, utils::arrays::array_length, }; -fn meter_gas_used(data: PrivateToPublicAccumulatedData) -> Gas { +fn meter_accumulated_data_gas_used(data: PrivateToPublicAccumulatedData) -> Gas { let mut metered_da_bytes = 0; let mut metered_l2_gas = 0; @@ -45,10 +47,20 @@ fn meter_gas_used(data: PrivateToPublicAccumulatedData) -> Gas { Gas::new(metered_da_bytes * DA_GAS_PER_BYTE, metered_l2_gas) } -pub fn meter_gas_used_non_revertible(data: PrivateToPublicAccumulatedData) -> Gas { - meter_gas_used(data) + Gas::tx_overhead() -} +pub fn meter_gas_used( + non_revertible_data: PrivateToPublicAccumulatedData, + revertible_data: PrivateToPublicAccumulatedData, + public_teardown_call_request: PublicCallRequest, + teardown_gas_limits: Gas, +) -> Gas { + let teardown_gas = if is_empty(public_teardown_call_request) { + Gas::empty() + } else { + teardown_gas_limits + }; -pub fn meter_gas_used_revertible(data: PrivateToPublicAccumulatedData) -> Gas { - meter_gas_used(data) + Gas::tx_overhead() + + meter_accumulated_data_gas_used(non_revertible_data) + + meter_accumulated_data_gas_used(revertible_data) + + teardown_gas } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr index e768fbc3802..052583ecb66 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr @@ -1,9 +1,7 @@ mod tail_to_public_output_hints; use crate::components::{ - tail_to_public_output_composer::meter_gas_used::{ - meter_gas_used_non_revertible, meter_gas_used_revertible, - }, + tail_to_public_output_composer::meter_gas_used::meter_gas_used, tail_to_public_output_validator::tail_to_public_output_hints::{ generate_tail_to_public_output_hints, TailToPublicOutputHints, }, @@ -15,7 +13,7 @@ use dep::types::{ }, log_hash::{LogHash, NoteLogHash, ScopedEncryptedLogHash, ScopedLogHash}, note_hash::ScopedNoteHash, - nullifier::{Nullifier, ScopedNullifier}, + nullifier::ScopedNullifier, public_call_request::PublicCallRequest, side_effect::Counted, }, @@ -148,21 +146,14 @@ impl TailToPublicOutputValidator { } fn validate_gas_used(self) { - let gas_used = meter_gas_used_non_revertible(self.output.non_revertible_accumulated_data); - assert( - self.output.non_revertible_accumulated_data.gas_used == gas_used, - "incorrect metered non-revertible gas used", - ); - - let gas_used = meter_gas_used_revertible(self.output.revertible_accumulated_data); - assert( - self.output.revertible_accumulated_data.gas_used == gas_used, - "incorrect metered revertible gas used", + let gas_limits = self.previous_kernel.constants.tx_context.gas_settings.gas_limits; + let gas_used = meter_gas_used( + self.output.non_revertible_accumulated_data, + self.output.revertible_accumulated_data, + self.output.public_teardown_call_request, + self.output.constants.tx_context.gas_settings.teardown_gas_limits, ); - - let limits = self.previous_kernel.constants.tx_context.gas_settings.gas_limits; - let total_gas_used = self.output.non_revertible_accumulated_data.gas_used - + self.output.revertible_accumulated_data.gas_used; - assert(total_gas_used.within(limits), "The gas used exceeds the gas limits"); + assert_eq(self.output.gas_used, gas_used, "incorrect metered gas used"); + assert(gas_used.within(gas_limits), "The gas used exceeds the gas limits"); } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 0aca41a778c..02d68f07770 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -248,7 +248,7 @@ mod tests { DA_GAS_PER_BYTE * DA_BYTES_PER_FIELD * 1, L2_GAS_PER_NULLIFIER * 1, ); - assert_eq(public_inputs.end.gas_used, expected_gas_consumed); + assert_eq(public_inputs.gas_used, expected_gas_consumed); } #[test] @@ -268,7 +268,7 @@ mod tests { 4 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, 1 * L2_GAS_PER_NULLIFIER, ), - public_inputs.end.gas_used, + public_inputs.gas_used, ); } @@ -290,7 +290,7 @@ mod tests { (1 * DA_BYTES_PER_FIELD + 25) * DA_GAS_PER_BYTE, 1 * L2_GAS_PER_NULLIFIER + 25 * L2_GAS_PER_LOG_BYTE, ), - public_inputs.end.gas_used, + public_inputs.gas_used, ); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index 0dbd3cd46f6..1765f6f6254 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -170,21 +170,12 @@ mod tests { [output_nullifiers[3], output_nullifiers[4]], ); - assert_eq( - public_inputs.revertible_accumulated_data.gas_used, - Gas::new( - 2 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, - 2 * L2_GAS_PER_NULLIFIER, - ), - ); - assert_eq( - public_inputs.non_revertible_accumulated_data.gas_used, - Gas::new( - 3 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, - FIXED_AVM_STARTUP_L2_GAS + 3 * L2_GAS_PER_NULLIFIER, - ) - + Gas::tx_overhead(), - ); + let num_nullifiers = 1 /* tx nullifier */ + + 2 /* non-revertible */ + + 2 /* revertible */; + let da_gas = num_nullifiers * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE; + let l2_gas = FIXED_AVM_STARTUP_L2_GAS + num_nullifiers * L2_GAS_PER_NULLIFIER; + assert_eq(public_inputs.gas_used, Gas::tx_overhead() + Gas::new(da_gas, l2_gas)); } #[test] @@ -213,21 +204,14 @@ mod tests { [exposed_note_hashes[2], exposed_note_hashes[3]], ); - assert_eq( - public_inputs.revertible_accumulated_data.gas_used, - Gas::new( - (2 * DA_BYTES_PER_FIELD) * DA_GAS_PER_BYTE, - 2 * L2_GAS_PER_NOTE_HASH, - ), - ); - assert_eq( - public_inputs.non_revertible_accumulated_data.gas_used, - Gas::new( - (3 * DA_BYTES_PER_FIELD) * DA_GAS_PER_BYTE, - FIXED_AVM_STARTUP_L2_GAS + L2_GAS_PER_NULLIFIER + 2 * L2_GAS_PER_NOTE_HASH, - ) - + Gas::tx_overhead(), - ); + let num_note_hashes = 2 /* non-revertible */ + + 2 /* revertible */; + let num_side_effects = num_note_hashes + 1 /* tx nullifier */; + let da_gas = (num_side_effects * DA_BYTES_PER_FIELD) * DA_GAS_PER_BYTE; + let l2_gas = FIXED_AVM_STARTUP_L2_GAS + + L2_GAS_PER_NULLIFIER + + num_note_hashes * L2_GAS_PER_NOTE_HASH; + assert_eq(public_inputs.gas_used, Gas::tx_overhead() + Gas::new(da_gas, l2_gas)); } #[test(should_fail_with = "Non empty note hash read requests")] @@ -264,42 +248,57 @@ mod tests { builder.previous_kernel.end_setup(); let public_inputs = builder.execute(); - assert_eq(public_inputs.revertible_accumulated_data.gas_used, Gas::empty()); - - let expected_non_revertible_gas_used = Gas::tx_overhead() - + Gas::new( - DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE * 1, - L2_GAS_PER_NULLIFIER * 1 + FIXED_AVM_STARTUP_L2_GAS, - ); - - assert_eq( - public_inputs.non_revertible_accumulated_data.gas_used, - expected_non_revertible_gas_used, - ); + let da_gas = DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE * 1; + let l2_gas = L2_GAS_PER_NULLIFIER * 1 + FIXED_AVM_STARTUP_L2_GAS; + assert_eq(public_inputs.gas_used, Gas::tx_overhead() + Gas::new(da_gas, l2_gas)); } #[test] unconstrained fn enqueued_public_calls_consume_startup_gas() { let mut builder = PrivateKernelTailToPublicInputsBuilder::new(); + + let teardown_gas_limits = Gas::new(1, 2); + builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = teardown_gas_limits; + // add an extra non-revertible call builder.previous_kernel.append_public_call_requests(1); builder.previous_kernel.end_setup(); // add some revertible calls builder.previous_kernel.append_public_call_requests(3); + let public_inputs = builder.execute(); - let expected_revertible_gas_used = Gas::new(0, 3 * FIXED_AVM_STARTUP_L2_GAS); - assert_eq(public_inputs.revertible_accumulated_data.gas_used, expected_revertible_gas_used); + let num_public_calls = 2 /* non-revertible */ + + 3 /* revertible */; + let da_gas = DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE * 1; + let l2_gas = L2_GAS_PER_NULLIFIER * 1 + num_public_calls * FIXED_AVM_STARTUP_L2_GAS; + assert_eq(public_inputs.gas_used, Gas::tx_overhead() + Gas::new(da_gas, l2_gas)); + } + + #[test] + unconstrained fn enqueued_public_calls_with_teardown_gas() { + let mut builder = PrivateKernelTailToPublicInputsBuilder::new(); - let expected_non_revertible_gas_used = Gas::tx_overhead() - + Gas::new( - DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE * 1, - L2_GAS_PER_NULLIFIER * 1 + 2 * FIXED_AVM_STARTUP_L2_GAS, - ); + let teardown_gas_limits = Gas::new(1, 2); + builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = teardown_gas_limits; + // add an extra non-revertible call + builder.previous_kernel.append_public_call_requests(1); + builder.previous_kernel.end_setup(); + // add some revertible calls + builder.previous_kernel.append_public_call_requests(3); + // add a teardown call + builder.previous_kernel.set_public_teardown_call_request(); + + let public_inputs = builder.execute(); + + let num_public_calls = 2 /* non-revertible */ + + 3 /* revertible */; + let da_gas = DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE * 1; + let l2_gas = L2_GAS_PER_NULLIFIER * 1 + num_public_calls * FIXED_AVM_STARTUP_L2_GAS; assert_eq( - public_inputs.non_revertible_accumulated_data.gas_used, - expected_non_revertible_gas_used, + public_inputs.gas_used, + Gas::tx_overhead() + Gas::new(da_gas, l2_gas) + teardown_gas_limits, ); } @@ -314,18 +313,12 @@ mod tests { let public_inputs = builder.execute(); - assert_eq( - Gas::new(1 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, 0), - public_inputs.revertible_accumulated_data.gas_used, - ); - assert_eq( - Gas::tx_overhead() - + Gas::new( - 3 * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE, - FIXED_AVM_STARTUP_L2_GAS + 1 * L2_GAS_PER_NULLIFIER, - ), - public_inputs.non_revertible_accumulated_data.gas_used, - ); + let num_msgs = 2 /* non-revertible */ + + 1 /* revertible */; + let num_side_effects = num_msgs + 1 /* tx nullifier */; + let da_gas = num_side_effects * DA_BYTES_PER_FIELD * DA_GAS_PER_BYTE; + let l2_gas = FIXED_AVM_STARTUP_L2_GAS + 1 * L2_GAS_PER_NULLIFIER; + assert_eq(public_inputs.gas_used, Gas::tx_overhead() + Gas::new(da_gas, l2_gas)); } #[test] @@ -340,19 +333,12 @@ mod tests { let public_inputs = builder.execute(); - assert_eq( - Gas::new(13 * DA_GAS_PER_BYTE, 13 * L2_GAS_PER_LOG_BYTE), - public_inputs.revertible_accumulated_data.gas_used, - ); - - assert_eq( - Gas::tx_overhead() - + Gas::new( - (1 * DA_BYTES_PER_FIELD + 12) * DA_GAS_PER_BYTE, - FIXED_AVM_STARTUP_L2_GAS + 1 * L2_GAS_PER_NULLIFIER + 12 * L2_GAS_PER_LOG_BYTE, - ), - public_inputs.non_revertible_accumulated_data.gas_used, - ); + let num_log_bytes = 3 + 4 + 5 + 6 + 7; + let da_gas = (1 * DA_BYTES_PER_FIELD + num_log_bytes) * DA_GAS_PER_BYTE; + let l2_gas = FIXED_AVM_STARTUP_L2_GAS + + 1 * L2_GAS_PER_NULLIFIER + + num_log_bytes * L2_GAS_PER_LOG_BYTE; + assert_eq(public_inputs.gas_used, Gas::tx_overhead() + Gas::new(da_gas, l2_gas)); } #[test(should_fail_with = "The gas used exceeds the gas limits")] diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/mod.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/mod.nr index 89b81810ca1..a624732fde9 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/mod.nr @@ -40,7 +40,7 @@ impl TailOutputValidatorBuilder { pub fn export_output(self) -> KernelCircuitPublicInputs { let mut output = self.output.to_kernel_circuit_public_inputs(); - output.end.gas_used = meter_gas_used(output.end); + output.gas_used = meter_gas_used(output.end); output } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_gas_used.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_gas_used.nr index 5f9b63587f2..f8393d50aa7 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_gas_used.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_output_validator_builder/validate_gas_used.nr @@ -27,7 +27,7 @@ fn validate_gas_used_wrong_da_gas_fails() { let mut output = builder.export_output(); // Tweak the da gas in the output to be a wrong value. - output.end.gas_used.da_gas += 1; + output.gas_used.da_gas += 1; builder.validate_with_output(output); } @@ -38,7 +38,7 @@ fn validate_gas_used_wrong_l2_gas_fails() { let mut output = builder.export_output(); // Tweak the l2 gas in the output to be a wrong value. - output.end.gas_used.l2_gas += 1; + output.gas_used.l2_gas += 1; builder.validate_with_output(output); } @@ -48,7 +48,7 @@ fn validate_gas_used_exceed_da_limit_fails() { let mut builder = TailOutputValidatorBuilder::new_with_data(); let mut output = builder.export_output(); - let gas_used = output.end.gas_used.da_gas; + let gas_used = output.gas_used.da_gas; // Tweak the da gas limit to be less than the gas used. output.constants.tx_context.gas_settings.gas_limits.da_gas = gas_used - 1; // Constants must match. @@ -62,7 +62,7 @@ fn validate_gas_used_exceed_l2_limit_fails() { let mut builder = TailOutputValidatorBuilder::new_with_data(); let mut output = builder.export_output(); - let gas_used = output.end.gas_used.l2_gas; + let gas_used = output.gas_used.l2_gas; // Tweak the l2 gas limit to be less than the gas used. output.constants.tx_context.gas_settings.gas_limits.l2_gas = gas_used - 1; // Constants must match. diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/meter_gas_used.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/meter_gas_used.nr index e684d244c33..d6352017f30 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/meter_gas_used.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/meter_gas_used.nr @@ -1,8 +1,6 @@ -use crate::components::tail_to_public_output_composer::meter_gas_used::{ - meter_gas_used_non_revertible, meter_gas_used_revertible, -}; +use crate::components::tail_to_public_output_composer::meter_gas_used::meter_gas_used; use dep::types::{ - abis::gas::Gas, + abis::{gas::Gas, public_call_request::PublicCallRequest}, constants::{ DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE, FIXED_AVM_STARTUP_L2_GAS, L2_GAS_PER_LOG_BYTE, L2_GAS_PER_NOTE_HASH, L2_GAS_PER_NULLIFIER, @@ -11,75 +9,72 @@ use dep::types::{ }; #[test] -fn meter_gas_used_non_revertible_empty_succeeds() { +fn meter_gas_used_empty_succeeds() { let builder = FixtureBuilder::new(); - let data = builder.to_private_to_public_accumulated_data(); - let gas = meter_gas_used_non_revertible(data); + let empty_data = builder.to_private_to_public_accumulated_data(); + let teardown_call_request = PublicCallRequest::empty(); + let teardown_gas_limits = Gas::new(1, 2); + let gas = meter_gas_used( + empty_data, + empty_data, + teardown_call_request, + teardown_gas_limits, + ); assert_eq(gas, Gas::tx_overhead()); } #[test] -fn meter_gas_used_non_revertible_everything_succeeds() { - let mut builder = FixtureBuilder::new(); - - builder.append_note_hashes(4); - builder.append_nullifiers(3); - builder.append_l2_to_l1_msgs(1); - builder.add_note_encrypted_log_hash(1001, 12, 0); - builder.add_note_encrypted_log_hash(1002, 8, 0); - builder.add_note_encrypted_log_hash(1003, 20, 0); - builder.add_encrypted_log_hash(2001, 2); - builder.add_encrypted_log_hash(2002, 6); - builder.add_unencrypted_log_hash(3001, 51); - builder.append_public_call_requests(2); - builder.end_setup(); +fn meter_gas_used_with_teardown_call_succeeds() { + let builder = FixtureBuilder::new(); + let empty_data = builder.to_private_to_public_accumulated_data(); - let data = builder.to_private_to_public_accumulated_data(); - let gas = meter_gas_used_non_revertible(data); + let mut teardown_call_request = PublicCallRequest::empty(); + teardown_call_request.contract_address = builder.contract_address; - let total_num_side_effects = 4 + 3 + 1; - let total_log_length = 12 - + 8 - + 20 // note_encrypted_log_hash - + 2 - + 6 // encrypted_log_hash - + 51; // unencrypted_log_hash - let computed_da_gas = - (total_num_side_effects * DA_BYTES_PER_FIELD + total_log_length) * DA_GAS_PER_BYTE; - let computed_l2_gas = 4 * L2_GAS_PER_NOTE_HASH - + 3 * L2_GAS_PER_NULLIFIER - + total_log_length * L2_GAS_PER_LOG_BYTE - + 2 * FIXED_AVM_STARTUP_L2_GAS; + let teardown_gas_limits = Gas::new(1, 2); - assert_eq(gas, Gas::new(computed_da_gas, computed_l2_gas) + Gas::tx_overhead()); + let gas = meter_gas_used( + empty_data, + empty_data, + teardown_call_request, + teardown_gas_limits, + ); + assert_eq(gas, Gas::tx_overhead() + teardown_gas_limits); } #[test] -fn meter_gas_used_revertible_empty_succeeds() { - let builder = FixtureBuilder::new(); - let data = builder.to_private_to_public_accumulated_data(); - let gas = meter_gas_used_revertible(data); - assert_eq(gas, Gas::empty()); -} +fn meter_gas_used_everything_succeeds() { + let mut non_revertible_builder = FixtureBuilder::new(); + let mut revertible_builder = FixtureBuilder::new(); -#[test] -fn meter_gas_used_revertible_everything_succeeds() { - let mut builder = FixtureBuilder::new(); + non_revertible_builder.append_note_hashes(3); + non_revertible_builder.append_nullifiers(1); + non_revertible_builder.append_l2_to_l1_msgs(0); + non_revertible_builder.add_note_encrypted_log_hash(1001, 12, 0); + non_revertible_builder.add_encrypted_log_hash(2001, 2); + non_revertible_builder.append_public_call_requests(1); + + revertible_builder.append_note_hashes(1); + revertible_builder.append_nullifiers(2); + revertible_builder.append_l2_to_l1_msgs(1); + revertible_builder.add_note_encrypted_log_hash(1002, 8, 0); + revertible_builder.add_note_encrypted_log_hash(1003, 20, 0); + revertible_builder.add_encrypted_log_hash(2002, 6); + revertible_builder.add_unencrypted_log_hash(3001, 51); + revertible_builder.append_public_call_requests(1); - builder.append_note_hashes(4); - builder.append_nullifiers(3); - builder.append_l2_to_l1_msgs(1); - builder.add_note_encrypted_log_hash(1001, 12, 0); - builder.add_note_encrypted_log_hash(1002, 8, 0); - builder.add_note_encrypted_log_hash(1003, 20, 0); - builder.add_encrypted_log_hash(2001, 2); - builder.add_encrypted_log_hash(2002, 6); - builder.add_unencrypted_log_hash(3001, 51); - builder.append_public_call_requests(2); - builder.end_setup(); + let non_revertible_data = non_revertible_builder.to_private_to_public_accumulated_data(); + let revertible_data = revertible_builder.to_private_to_public_accumulated_data(); + let mut teardown_call_request = PublicCallRequest::empty(); + teardown_call_request.contract_address = non_revertible_builder.contract_address; + let teardown_gas_limits = Gas::new(1, 2); - let data = builder.to_private_to_public_accumulated_data(); - let gas = meter_gas_used_revertible(data); + let gas = meter_gas_used( + non_revertible_data, + revertible_data, + teardown_call_request, + teardown_gas_limits, + ); let total_num_side_effects = 4 + 3 + 1; let total_log_length = 12 @@ -95,5 +90,8 @@ fn meter_gas_used_revertible_everything_succeeds() { + total_log_length * L2_GAS_PER_LOG_BYTE + 2 * FIXED_AVM_STARTUP_L2_GAS; - assert_eq(gas, Gas::new(computed_da_gas, computed_l2_gas)); + assert_eq( + gas, + Gas::new(computed_da_gas, computed_l2_gas) + Gas::tx_overhead() + teardown_gas_limits, + ); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/tail_to_public_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/tail_to_public_output_composer.nr index 7910d8f2000..a96d4da43c3 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/tail_to_public_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/tail_to_public_output_composer_builder/tail_to_public_output_composer.nr @@ -12,8 +12,8 @@ use dep::types::{ fn tail_to_public_output_composer_succeeds() { let mut builder = TailToPublicOutputComposerBuilder::new(); - let teardown_gas = Gas::new(789, 3254); - builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = teardown_gas; + let teardown_gas_limits = Gas::new(789, 3254); + builder.previous_kernel.tx_context.gas_settings.teardown_gas_limits = teardown_gas_limits; // Non-revertibles. builder.previous_kernel.append_siloed_note_hashes(4); @@ -35,6 +35,8 @@ fn tail_to_public_output_composer_succeeds() { builder.previous_kernel.end_setup(); // Revertibles. + builder.previous_kernel.set_public_teardown_call_request(); + builder.previous_kernel.append_siloed_note_hashes(2); builder.previous_kernel.append_siloed_nullifiers(1); @@ -137,37 +139,38 @@ fn tail_to_public_output_composer_succeeds() { ); // Gas: non-revertible - let total_num_side_effects = 4 + 3 + 1; - let total_log_length = 12 + let mut num_note_hashes = 4; + let mut num_nullifiers = 3; + let mut num_msgs = 1; + let mut num_public_calls = 2; + let mut total_log_length = 12 + 8 // note_encrypted_log_hash + 2 // encrypted_log_hash + 51 + 9; // unencrypted_log_hash - let computed_da_gas = - (total_num_side_effects * DA_BYTES_PER_FIELD + total_log_length) * DA_GAS_PER_BYTE; - let computed_l2_gas = 4 * L2_GAS_PER_NOTE_HASH - + 3 * L2_GAS_PER_NULLIFIER - + total_log_length * L2_GAS_PER_LOG_BYTE - + 2 * FIXED_AVM_STARTUP_L2_GAS; - assert_eq( - output.non_revertible_accumulated_data.gas_used, - Gas::new(computed_da_gas, computed_l2_gas) + Gas::tx_overhead(), - ); - // Gas: revertible - let total_num_side_effects = 2 + 1 + 1; - let total_log_length = 20 // note_encrypted_log_hash - + 6 - + 24 // encrypted_log_hash - + 4; // unencrypted_log_hash + { + num_note_hashes += 2; + num_nullifiers += 1; + num_public_calls += 3; + num_msgs += 1; + total_log_length += 20 // note_encrypted_log_hash + + 6 + + 24 // encrypted_log_hash + + 4; // unencrypted_log_hash + } + + let num_da_effects = num_note_hashes + num_nullifiers + num_msgs; let computed_da_gas = - (total_num_side_effects * DA_BYTES_PER_FIELD + total_log_length) * DA_GAS_PER_BYTE; - let computed_l2_gas = 2 * L2_GAS_PER_NOTE_HASH - + 1 * L2_GAS_PER_NULLIFIER + (num_da_effects * DA_BYTES_PER_FIELD + total_log_length) * DA_GAS_PER_BYTE; + + let computed_l2_gas = num_note_hashes * L2_GAS_PER_NOTE_HASH + + num_nullifiers * L2_GAS_PER_NULLIFIER + total_log_length * L2_GAS_PER_LOG_BYTE - + 3 * FIXED_AVM_STARTUP_L2_GAS; + + num_public_calls * FIXED_AVM_STARTUP_L2_GAS; + assert_eq( - output.revertible_accumulated_data.gas_used, - Gas::new(computed_da_gas, computed_l2_gas), + output.gas_used, + Gas::tx_overhead() + Gas::new(computed_da_gas, computed_l2_gas) + teardown_gas_limits, ); } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer.nr index 788fd4eff55..87d6118f8f3 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/components/public_tail_output_composer.nr @@ -42,6 +42,9 @@ impl PublicTailOutputComposer PublicTailOutputComposer( encrypted_log_preimages_length, unencrypted_log_preimages_length, public_data_writes, - gas_used: revertible.gas_used + non_revertible.gas_used, } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr index bf4c31a6fee..43bd41049b3 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr @@ -42,7 +42,7 @@ impl PrivateBaseRollupInputs { fn compute_transaction_fee(self) -> Field { let gas_fees = self.constants.global_variables.gas_fees; let data = self.tube_data.public_inputs; - data.end.gas_used.compute_fee(gas_fees) + data.gas_used.compute_fee(gas_fees) } pub fn execute(self) -> BaseOrMergeRollupPublicInputs { diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr index 8a8a9650bbc..0f31631c0c3 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/public_base_rollup.nr @@ -86,7 +86,6 @@ impl PublicBaseRollupInputs { encrypted_log_preimages_length, unencrypted_log_preimages_length, public_data_writes: from_public.accumulated_data.public_data_writes, - gas_used: Gas::empty(), // gas_used is not used in rollup circuits. }; let constants = @@ -106,6 +105,7 @@ impl PublicBaseRollupInputs { end, start_state, revert_code, + gas_used: Gas::empty(), // gas_used is not used in rollup circuits. fee_payer: from_private.fee_payer, } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index a696abacc42..ae51db5c9d8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -1,5 +1,5 @@ use crate::{ - abis::{gas::Gas, log_hash::{LogHash, ScopedLogHash}, public_data_write::PublicDataWrite}, + abis::{log_hash::{LogHash, ScopedLogHash}, public_data_write::PublicDataWrite}, constants::{ COMBINED_ACCUMULATED_DATA_LENGTH, MAX_ENCRYPTED_LOGS_PER_TX, MAX_L2_TO_L1_MSGS_PER_TX, MAX_NOTE_ENCRYPTED_LOGS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, @@ -26,8 +26,6 @@ pub struct CombinedAccumulatedData { pub unencrypted_log_preimages_length: Field, pub public_data_writes: [PublicDataWrite; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - - pub gas_used: Gas, } impl Empty for CombinedAccumulatedData { @@ -43,7 +41,6 @@ impl Empty for CombinedAccumulatedData { encrypted_log_preimages_length: 0, unencrypted_log_preimages_length: 0, public_data_writes: [PublicDataWrite::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - gas_used: Gas::empty(), } } } @@ -74,8 +71,6 @@ impl Serialize for CombinedAccumulatedData { fields.extend_from_array(self.public_data_writes[i].serialize()); } - fields.extend_from_array(self.gas_used.serialize()); - assert_eq(fields.len(), COMBINED_ACCUMULATED_DATA_LENGTH); fields.storage() @@ -112,7 +107,6 @@ impl Deserialize for CombinedAccumulatedData { PublicDataWrite::deserialize, [PublicDataWrite::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], ), - gas_used: reader.read_struct(Gas::deserialize), }; reader.finish(); item @@ -134,7 +128,6 @@ impl Eq for CombinedAccumulatedData { & (self.encrypted_log_preimages_length == other.encrypted_log_preimages_length) & (self.unencrypted_log_preimages_length == other.unencrypted_log_preimages_length) & (self.public_data_writes == other.public_data_writes) - & (self.gas_used == other.gas_used) } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data.nr index ca864b3cb89..ee7ce56dbea 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data.nr @@ -1,5 +1,5 @@ use crate::{ - abis::{gas::Gas, log_hash::{LogHash, ScopedLogHash}, public_call_request::PublicCallRequest}, + abis::{log_hash::{LogHash, ScopedLogHash}, public_call_request::PublicCallRequest}, messaging::l2_to_l1_message::ScopedL2ToL1Message, traits::{Deserialize, Empty, Serialize}, utils::reader::Reader, @@ -18,7 +18,6 @@ pub struct PrivateToPublicAccumulatedData { pub encrypted_logs_hashes: [ScopedLogHash; MAX_ENCRYPTED_LOGS_PER_TX], pub unencrypted_logs_hashes: [ScopedLogHash; MAX_UNENCRYPTED_LOGS_PER_TX], pub public_call_requests: [PublicCallRequest; MAX_ENQUEUED_CALLS_PER_TX], - pub gas_used: Gas, } impl Empty for PrivateToPublicAccumulatedData { @@ -31,7 +30,6 @@ impl Empty for PrivateToPublicAccumulatedData { encrypted_logs_hashes: [ScopedLogHash::empty(); MAX_ENCRYPTED_LOGS_PER_TX], unencrypted_logs_hashes: [ScopedLogHash::empty(); MAX_UNENCRYPTED_LOGS_PER_TX], public_call_requests: [PublicCallRequest::empty(); MAX_ENQUEUED_CALLS_PER_TX], - gas_used: Gas::empty(), } } } @@ -45,7 +43,6 @@ impl Eq for PrivateToPublicAccumulatedData { & (self.encrypted_logs_hashes == other.encrypted_logs_hashes) & (self.unencrypted_logs_hashes == other.unencrypted_logs_hashes) & (self.public_call_requests == other.public_call_requests) - & (self.gas_used == other.gas_used) } } @@ -71,7 +68,6 @@ impl Serialize for PrivateToPublicAcc for i in 0..self.public_call_requests.len() { fields.extend_from_array(self.public_call_requests[i].serialize()); } - fields.extend_from_array(self.gas_used.serialize()); assert_eq(fields.len(), PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH); @@ -108,7 +104,6 @@ impl Deserialize for PrivateToPublicA PublicCallRequest::deserialize, [PublicCallRequest::empty(); MAX_ENQUEUED_CALLS_PER_TX], ), - gas_used: reader.read_struct(Gas::deserialize), }; reader.finish(); item diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data_builder.nr index 64a4451f820..5f2567d999d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_to_public_accumulated_data_builder.nr @@ -1,7 +1,6 @@ use crate::{ abis::{ accumulated_data::private_to_public_accumulated_data::PrivateToPublicAccumulatedData, - gas::Gas, log_hash::{LogHash, ScopedLogHash}, public_call_request::PublicCallRequest, }, @@ -23,7 +22,6 @@ pub struct PrivateToPublicAccumulatedDataBuilder { encrypted_logs_hashes: BoundedVec, unencrypted_logs_hashes: BoundedVec, public_call_requests: BoundedVec, - gas_used: Gas, } impl PrivateToPublicAccumulatedDataBuilder { @@ -36,7 +34,6 @@ impl PrivateToPublicAccumulatedDataBuilder { encrypted_logs_hashes: array_to_bounded_vec(data.encrypted_logs_hashes), unencrypted_logs_hashes: array_to_bounded_vec(data.unencrypted_logs_hashes), public_call_requests: array_to_bounded_vec(data.public_call_requests), - gas_used: data.gas_used, } } @@ -49,7 +46,6 @@ impl PrivateToPublicAccumulatedDataBuilder { encrypted_logs_hashes: self.encrypted_logs_hashes.storage(), unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage(), public_call_requests: self.public_call_requests.storage(), - gas_used: self.gas_used, } } } @@ -64,7 +60,6 @@ impl Empty for PrivateToPublicAccumulatedDataBuilder { encrypted_logs_hashes: BoundedVec::new(), unencrypted_logs_hashes: BoundedVec::new(), public_call_requests: BoundedVec::new(), - gas_used: Gas::empty(), } } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/avm_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/avm_circuit_public_inputs.nr index 280f82ceff5..6f13d86177c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/avm_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/avm_circuit_public_inputs.nr @@ -6,6 +6,7 @@ use crate::{ PrivateToAvmAccumulatedData, PrivateToAvmAccumulatedDataArrayLengths, }, }, + gas::Gas, gas_settings::GasSettings, global_variables::GlobalVariables, public_call_request::PublicCallRequest, @@ -21,6 +22,7 @@ pub struct AvmCircuitPublicInputs { // Inputs. global_variables: GlobalVariables, start_tree_snapshots: TreeSnapshots, + start_gas_used: Gas, gas_settings: GasSettings, public_setup_call_requests: [PublicCallRequest; MAX_ENQUEUED_CALLS_PER_TX], public_app_logic_call_requests: [PublicCallRequest; MAX_ENQUEUED_CALLS_PER_TX], @@ -43,6 +45,7 @@ impl Empty for AvmCircuitPublicInputs { AvmCircuitPublicInputs { global_variables: GlobalVariables::empty(), start_tree_snapshots: TreeSnapshots::empty(), + start_gas_used: Gas::empty(), gas_settings: GasSettings::empty(), public_setup_call_requests: [PublicCallRequest::empty(); MAX_ENQUEUED_CALLS_PER_TX], public_app_logic_call_requests: [PublicCallRequest::empty(); MAX_ENQUEUED_CALLS_PER_TX], @@ -63,6 +66,7 @@ impl Eq for AvmCircuitPublicInputs { fn eq(self, other: Self) -> bool { (self.global_variables == other.global_variables) & (self.start_tree_snapshots == other.start_tree_snapshots) + & (self.start_gas_used == other.start_gas_used) & (self.gas_settings == other.gas_settings) & (self.public_setup_call_requests == other.public_setup_call_requests) & (self.public_app_logic_call_requests == other.public_app_logic_call_requests) @@ -96,6 +100,7 @@ impl Serialize for AvmCircuitPublicInputs { fields.extend_from_array(self.global_variables.serialize()); fields.extend_from_array(self.start_tree_snapshots.serialize()); + fields.extend_from_array(self.start_gas_used.serialize()); fields.extend_from_array(self.gas_settings.serialize()); for i in 0..self.public_setup_call_requests.len() { fields.extend_from_array(self.public_setup_call_requests[i].serialize()); @@ -127,6 +132,7 @@ impl Deserialize for AvmCircuitPublicInputs { let item = AvmCircuitPublicInputs { global_variables: reader.read_struct(GlobalVariables::deserialize), start_tree_snapshots: reader.read_struct(TreeSnapshots::deserialize), + start_gas_used: reader.read_struct(Gas::deserialize), gas_settings: reader.read_struct(GasSettings::deserialize), public_setup_call_requests: reader.read_struct_array( PublicCallRequest::deserialize, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr index ceb418c3970..115beab20f9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr @@ -1,7 +1,7 @@ use crate::{ abis::{ accumulated_data::CombinedAccumulatedData, combined_constant_data::CombinedConstantData, - validation_requests::RollupValidationRequests, + gas::Gas, validation_requests::RollupValidationRequests, }, address::AztecAddress, constants::KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH, @@ -17,6 +17,7 @@ pub struct KernelCircuitPublicInputs { pub constants: CombinedConstantData, pub start_state: PartialStateReference, pub revert_code: u8, + pub gas_used: Gas, pub fee_payer: AztecAddress, } @@ -28,6 +29,7 @@ impl Empty for KernelCircuitPublicInputs { constants: CombinedConstantData::empty(), start_state: PartialStateReference::empty(), revert_code: 0, + gas_used: Gas::empty(), fee_payer: AztecAddress::empty(), } } @@ -40,6 +42,7 @@ impl Eq for KernelCircuitPublicInputs { & (self.constants.eq(other.constants)) & (self.start_state.eq(other.start_state)) & (self.revert_code == other.revert_code) + & (self.gas_used == other.gas_used) & (self.fee_payer.eq(other.fee_payer)) } } @@ -53,6 +56,7 @@ impl Serialize for KernelCircuitPublicInput fields.extend_from_array(self.constants.serialize()); fields.extend_from_array(self.start_state.serialize()); fields.push(self.revert_code as Field); + fields.extend_from_array(self.gas_used.serialize()); fields.extend_from_array(self.fee_payer.serialize()); assert_eq(fields.len(), KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH); @@ -72,6 +76,7 @@ impl Deserialize for KernelCircuitPublicInp constants: reader.read_struct(CombinedConstantData::deserialize), start_state: reader.read_struct(PartialStateReference::deserialize), revert_code: reader.read() as u8, + gas_used: reader.read_struct(Gas::deserialize), fee_payer: reader.read_struct(AztecAddress::deserialize), }; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_to_public_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_to_public_kernel_circuit_public_inputs.nr index 1860a126550..517f6870590 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_to_public_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_to_public_kernel_circuit_public_inputs.nr @@ -1,7 +1,8 @@ use crate::{ abis::{ - accumulated_data::PrivateToPublicAccumulatedData, public_call_request::PublicCallRequest, - tx_constant_data::TxConstantData, validation_requests::RollupValidationRequests, + accumulated_data::PrivateToPublicAccumulatedData, gas::Gas, + public_call_request::PublicCallRequest, tx_constant_data::TxConstantData, + validation_requests::RollupValidationRequests, }, address::AztecAddress, constants::PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH, @@ -15,6 +16,7 @@ pub struct PrivateToPublicKernelCircuitPublicInputs { pub non_revertible_accumulated_data: PrivateToPublicAccumulatedData, pub revertible_accumulated_data: PrivateToPublicAccumulatedData, pub public_teardown_call_request: PublicCallRequest, + pub gas_used: Gas, pub fee_payer: AztecAddress, } @@ -26,6 +28,7 @@ impl Empty for PrivateToPublicKernelCircuitPublicInputs { non_revertible_accumulated_data: PrivateToPublicAccumulatedData::empty(), revertible_accumulated_data: PrivateToPublicAccumulatedData::empty(), public_teardown_call_request: PublicCallRequest::empty(), + gas_used: Gas::empty(), fee_payer: AztecAddress::empty(), } } @@ -38,6 +41,7 @@ impl Eq for PrivateToPublicKernelCircuitPublicInputs { & (self.non_revertible_accumulated_data == other.non_revertible_accumulated_data) & (self.revertible_accumulated_data == other.revertible_accumulated_data) & (self.public_teardown_call_request == other.public_teardown_call_request) + & (self.gas_used == other.gas_used) & (self.fee_payer == other.fee_payer) } } @@ -52,6 +56,7 @@ impl Serialize for Privat fields.extend_from_array(self.non_revertible_accumulated_data.serialize()); fields.extend_from_array(self.revertible_accumulated_data.serialize()); fields.extend_from_array(self.public_teardown_call_request.serialize()); + fields.extend_from_array(self.gas_used.serialize()); fields.extend_from_array(self.fee_payer.serialize()); assert_eq(fields.len(), PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH); @@ -76,6 +81,7 @@ impl Deserialize for Priv PrivateToPublicAccumulatedData::deserialize, ), public_teardown_call_request: reader.read_struct(PublicCallRequest::deserialize), + gas_used: reader.read_struct(Gas::deserialize), fee_payer: reader.read_struct(AztecAddress::deserialize), }; reader.finish(); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 3e60e8e9247..9b72610458b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -376,8 +376,7 @@ pub global COMBINED_ACCUMULATED_DATA_LENGTH: u32 = MAX_NOTE_HASHES_PER_TX + (SCOPED_LOG_HASH_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + 3 + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) - + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_WRITE_LENGTH) - + GAS_LENGTH; + + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_WRITE_LENGTH); pub global TX_CONSTANT_DATA_LENGTH: u32 = HEADER_LENGTH + TX_CONTEXT_LENGTH + 1 /* vk_tree_root */ @@ -416,8 +415,7 @@ pub global PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH: u32 = MAX_NOTE_HASHES_PER_ + (MAX_NOTE_ENCRYPTED_LOGS_PER_TX * LOG_HASH_LENGTH) + (MAX_ENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) + (MAX_UNENCRYPTED_LOGS_PER_TX * SCOPED_LOG_HASH_LENGTH) - + (MAX_ENQUEUED_CALLS_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) - + GAS_LENGTH; + + (MAX_ENQUEUED_CALLS_PER_TX * PUBLIC_CALL_REQUEST_LENGTH); pub global PRIVATE_TO_AVM_ACCUMULATED_DATA_LENGTH: u32 = MAX_NOTE_HASHES_PER_TX + MAX_NULLIFIERS_PER_TX @@ -435,6 +433,7 @@ pub global PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = TX_CONST + PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH /* non_revertible_accumulated_data */ + PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH /* revertible_accumulated_data */ + PUBLIC_CALL_REQUEST_LENGTH /* public_teardown_call_request */ + + GAS_LENGTH /* gas_used */ + AZTEC_ADDRESS_LENGTH /* fee_payer */; pub global PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = COMBINED_CONSTANT_DATA_LENGTH + PUBLIC_VALIDATION_REQUESTS_LENGTH @@ -461,11 +460,13 @@ pub global KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = ROLLUP_VALIDATION_REQUESTS + COMBINED_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH - + 1 + + 1 /* revert_code */ + + GAS_LENGTH /* gas_used */ + AZTEC_ADDRESS_LENGTH; pub global AVM_CIRCUIT_PUBLIC_INPUTS_LENGTH: u32 = GLOBAL_VARIABLES_LENGTH + TREE_SNAPSHOTS_LENGTH /* start_tree_snapshots */ + + GAS_LENGTH /* start_gas_used */ + GAS_SETTINGS_LENGTH + (MAX_ENQUEUED_CALLS_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) /* public_setup_call_requests */ + (MAX_ENQUEUED_CALLS_PER_TX * PUBLIC_CALL_REQUEST_LENGTH) /* public_app_logic_call_requests */ diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index 8e1244ffb61..14924b0d267 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -479,7 +479,6 @@ impl FixtureBuilder { public_call_requests: self.public_call_requests.storage().map( |cr: Counted| cr.inner, ), - gas_used: self.gas_used, } } @@ -503,7 +502,6 @@ impl FixtureBuilder { encrypted_log_preimages_length: self.encrypted_log_preimages_length, unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, public_data_writes: self.public_data_writes.storage(), - gas_used: self.gas_used, } } @@ -568,6 +566,7 @@ impl FixtureBuilder { non_revertible_accumulated_data, revertible_accumulated_data, public_teardown_call_request: self.public_teardown_call_request, + gas_used: self.gas_used, fee_payer: self.fee_payer, } } @@ -659,6 +658,7 @@ impl FixtureBuilder { constants, start_state: self.start_state, revert_code: self.revert_code, + gas_used: self.gas_used, fee_payer: self.fee_payer, } } diff --git a/yarn-project/aztec.js/src/contract/get_gas_limits.test.ts b/yarn-project/aztec.js/src/contract/get_gas_limits.test.ts index bd77479e8f0..f42e45a0655 100644 --- a/yarn-project/aztec.js/src/contract/get_gas_limits.test.ts +++ b/yarn-project/aztec.js/src/contract/get_gas_limits.test.ts @@ -10,7 +10,7 @@ describe('getGasLimits', () => { txSimulationResult = mockSimulatedTx(); const tx = mockTxForRollup(); - tx.data.forRollup!.end.gasUsed = Gas.from({ daGas: 100, l2Gas: 200 }); + tx.data.gasUsed = Gas.from({ daGas: 100, l2Gas: 200 }); txSimulationResult.publicInputs = tx.data; txSimulationResult.publicOutput!.gasUsed = { diff --git a/yarn-project/circuit-types/src/test/factories.ts b/yarn-project/circuit-types/src/test/factories.ts index 4bf76476afe..b43f883bb7e 100644 --- a/yarn-project/circuit-types/src/test/factories.ts +++ b/yarn-project/circuit-types/src/test/factories.ts @@ -74,15 +74,16 @@ export function makeBloatedProcessedTx({ : mockTx(seed, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 0 }); tx.data.constants = txConstantData; + // No side effects were created in mockTx. The default gasUsed is the tx overhead. + tx.data.gasUsed = Gas.from({ daGas: FIXED_DA_GAS, l2Gas: FIXED_L2_GAS }); + if (privateOnly) { const data = makeCombinedAccumulatedData(seed + 0x1000); // Private-only tx has no public data writes. data.publicDataWrites.forEach((_, i) => (data.publicDataWrites[i] = PublicDataWrite.empty())); - // No side effects were created in mockTx. The default gasUsed is the tx overhead. - data.gasUsed = Gas.from({ daGas: FIXED_DA_GAS, l2Gas: FIXED_L2_GAS }); - const transactionFee = data.gasUsed.computeFee(globalVariables.gasFees); + const transactionFee = tx.data.gasUsed.computeFee(globalVariables.gasFees); clearLogs(data); diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index 75f4a60387b..05b3427ccbf 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -174,7 +174,7 @@ export function makeProcessedTxFromPrivateOnlyTx( ); const gasUsed = { - totalGas: tx.data.forRollup!.end.gasUsed, + totalGas: tx.data.gasUsed, teardownGas: Gas.empty(), }; diff --git a/yarn-project/circuit-types/src/tx/simulated_tx.ts b/yarn-project/circuit-types/src/tx/simulated_tx.ts index e202b02a6ab..f3af028d0c5 100644 --- a/yarn-project/circuit-types/src/tx/simulated_tx.ts +++ b/yarn-project/circuit-types/src/tx/simulated_tx.ts @@ -76,7 +76,7 @@ export class TxSimulationResult extends PrivateSimulationResult { get gasUsed(): GasUsed { return ( this.publicOutput?.gasUsed ?? { - totalGas: this.publicInputs.forRollup!.end.gasUsed, + totalGas: this.publicInputs.gasUsed, teardownGas: Gas.empty(), } ); diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 5c4dc7f9b67..03c3733ad47 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -192,18 +192,18 @@ export const PRIVATE_VALIDATION_REQUESTS_LENGTH = 772; export const NUM_PUBLIC_VALIDATION_REQUEST_ARRAYS = 5; export const PUBLIC_VALIDATION_REQUESTS_LENGTH = 834; export const PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 3; -export const COMBINED_ACCUMULATED_DATA_LENGTH = 547; +export const COMBINED_ACCUMULATED_DATA_LENGTH = 545; export const TX_CONSTANT_DATA_LENGTH = 34; export const COMBINED_CONSTANT_DATA_LENGTH = 43; export const PRIVATE_ACCUMULATED_DATA_LENGTH = 1064; export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1877; export const PUBLIC_ACCUMULATED_DATA_LENGTH = 1023; export const NUM_PUBLIC_ACCUMULATED_DATA_ARRAYS = 8; -export const PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 578; +export const PRIVATE_TO_PUBLIC_ACCUMULATED_DATA_LENGTH = 576; export const PRIVATE_TO_AVM_ACCUMULATED_DATA_LENGTH = 160; export const NUM_PRIVATE_TO_AVM_ACCUMULATED_DATA_ARRAYS = 3; export const AVM_ACCUMULATED_DATA_LENGTH = 318; -export const PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1198; +export const PRIVATE_TO_PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1196; export const PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2931; export const VM_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2340; export const KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 600; diff --git a/yarn-project/circuits.js/src/structs/avm/avm_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/avm/avm_circuit_public_inputs.ts index b01f1d40a84..6c68ce02a23 100644 --- a/yarn-project/circuits.js/src/structs/avm/avm_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/avm/avm_circuit_public_inputs.ts @@ -5,6 +5,7 @@ import { BufferReader, FieldReader, type Tuple, serializeToBuffer } from '@aztec import { inspect } from 'util'; import { MAX_ENQUEUED_CALLS_PER_TX } from '../../constants.gen.js'; +import { Gas } from '../gas.js'; import { GasSettings } from '../gas_settings.js'; import { GlobalVariables } from '../global_variables.js'; import { @@ -19,6 +20,7 @@ export class AvmCircuitPublicInputs { constructor( public globalVariables: GlobalVariables, public startTreeSnapshots: TreeSnapshots, + public startGasUsed: Gas, public gasSettings: GasSettings, public publicSetupCallRequests: Tuple, public publicAppLogicCallRequests: Tuple, @@ -38,6 +40,7 @@ export class AvmCircuitPublicInputs { return new AvmCircuitPublicInputs( reader.readObject(GlobalVariables), reader.readObject(TreeSnapshots), + reader.readObject(Gas), reader.readObject(GasSettings), reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest), reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest), @@ -57,6 +60,7 @@ export class AvmCircuitPublicInputs { return serializeToBuffer( this.globalVariables, this.startTreeSnapshots, + this.startGasUsed, this.gasSettings, this.publicSetupCallRequests, this.publicAppLogicCallRequests, @@ -85,6 +89,7 @@ export class AvmCircuitPublicInputs { return new AvmCircuitPublicInputs( GlobalVariables.fromFields(reader), TreeSnapshots.fromFields(reader), + Gas.fromFields(reader), GasSettings.fromFields(reader), reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest), reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest), @@ -104,6 +109,7 @@ export class AvmCircuitPublicInputs { return new AvmCircuitPublicInputs( GlobalVariables.empty(), TreeSnapshots.empty(), + Gas.empty(), GasSettings.empty(), makeTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest.empty), makeTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest.empty), @@ -123,6 +129,7 @@ export class AvmCircuitPublicInputs { return `AvmCircuitPublicInputs { globalVariables: ${inspect(this.globalVariables)}, startTreeSnapshots: ${inspect(this.startTreeSnapshots)}, + startGasUsed: ${inspect(this.startGasUsed)}, gasSettings: ${inspect(this.gasSettings)}, publicSetupCallRequests: [${this.publicSetupCallRequests .filter(x => !x.isEmpty()) diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index 5135b74324f..a66c8742fa1 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -15,7 +15,6 @@ import { MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, } from '../../constants.gen.js'; -import { Gas } from '../gas.js'; import { ScopedL2ToL1Message } from '../l2_to_l1_message.js'; import { LogHash, ScopedLogHash } from '../log_hash.js'; import { PublicDataWrite } from '../public_data_write.js'; @@ -66,9 +65,6 @@ export class CombinedAccumulatedData { * All the public data update requests made in this transaction. */ public publicDataWrites: Tuple, - - /** Gas used during this transaction */ - public gasUsed: Gas, ) {} getSize() { @@ -82,8 +78,7 @@ export class CombinedAccumulatedData { this.noteEncryptedLogPreimagesLength.size + this.encryptedLogPreimagesLength.size + this.unencryptedLogPreimagesLength.size + - arraySerializedSizeOfNonEmpty(this.publicDataWrites) + - this.gasUsed.toBuffer().length + arraySerializedSizeOfNonEmpty(this.publicDataWrites) ); } @@ -99,7 +94,6 @@ export class CombinedAccumulatedData { fields.encryptedLogPreimagesLength, fields.unencryptedLogPreimagesLength, fields.publicDataWrites, - fields.gasUsed, ] as const; } @@ -141,7 +135,6 @@ export class CombinedAccumulatedData { Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite), - reader.readObject(Gas), ); } @@ -166,7 +159,6 @@ export class CombinedAccumulatedData { Fr.zero(), Fr.zero(), makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataWrite.empty), - Gas.empty(), ); } @@ -203,7 +195,6 @@ export class CombinedAccumulatedData { .filter(x => !x.isEmpty()) .map(x => inspect(x)) .join(', ')}], - gasUsed: ${inspect(this.gasUsed)} }`; } } diff --git a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts index f2861693c3b..2ec58bdd269 100644 --- a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts @@ -2,6 +2,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { hexSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { Gas } from '../gas.js'; import { PartialStateReference } from '../partial_state_reference.js'; import { RevertCode } from '../revert_code.js'; import { RollupValidationRequests } from '../rollup_validation_requests.js'; @@ -31,6 +32,10 @@ export class KernelCircuitPublicInputs { * Flag indicating whether the transaction reverted. */ public revertCode: RevertCode, + /** + * Gas used during this transaction + */ + public gasUsed: Gas, /** * The address of the fee payer for the transaction. */ @@ -48,6 +53,7 @@ export class KernelCircuitPublicInputs { this.constants, this.startState, this.revertCode, + this.gasUsed, this.feePayer, ); } @@ -65,6 +71,7 @@ export class KernelCircuitPublicInputs { reader.readObject(CombinedConstantData), reader.readObject(PartialStateReference), reader.readObject(RevertCode), + reader.readObject(Gas), reader.readObject(AztecAddress), ); } @@ -76,6 +83,7 @@ export class KernelCircuitPublicInputs { CombinedConstantData.empty(), PartialStateReference.empty(), RevertCode.OK, + Gas.empty(), AztecAddress.ZERO, ); } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts index a60d44d5139..7ce5ae26c0d 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts @@ -4,6 +4,7 @@ import { hexSchemaFor } from '@aztec/foundation/schemas'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { countAccumulatedItems, mergeAccumulatedData } from '../../utils/index.js'; +import { Gas } from '../gas.js'; import { GlobalVariables } from '../global_variables.js'; import { PartialStateReference } from '../partial_state_reference.js'; import { PublicCallRequest } from '../public_call_request.js'; @@ -106,6 +107,11 @@ export class PrivateKernelTailCircuitPublicInputs { */ public constants: TxConstantData, public rollupValidationRequests: RollupValidationRequests, + /** + * The accumulated gas used after private execution. + * If the tx has a teardown call request, the teardown gas limits will also be included. + */ + public gasUsed: Gas, /** * The address of the fee payer for the transaction. */ @@ -152,6 +158,7 @@ export class PrivateKernelTailCircuitPublicInputs { this.forPublic.nonRevertibleAccumulatedData, this.forPublic.revertibleAccumulatedData, this.forPublic.publicTeardownCallRequest, + this.gasUsed, this.feePayer, ); } @@ -173,6 +180,7 @@ export class PrivateKernelTailCircuitPublicInputs { constants, PartialStateReference.empty(), RevertCode.OK, + this.gasUsed, this.feePayer, ); } @@ -238,6 +246,7 @@ export class PrivateKernelTailCircuitPublicInputs { return new PrivateKernelTailCircuitPublicInputs( reader.readObject(TxConstantData), reader.readObject(RollupValidationRequests), + reader.readObject(Gas), reader.readObject(AztecAddress), isForPublic ? reader.readObject(PartialPrivateTailPublicInputsForPublic) : undefined, !isForPublic ? reader.readObject(PartialPrivateTailPublicInputsForRollup) : undefined, @@ -250,6 +259,7 @@ export class PrivateKernelTailCircuitPublicInputs { isForPublic, this.constants, this.rollupValidationRequests, + this.gasUsed, this.feePayer, isForPublic ? this.forPublic!.toBuffer() : this.forRollup!.toBuffer(), ); @@ -259,6 +269,7 @@ export class PrivateKernelTailCircuitPublicInputs { return new PrivateKernelTailCircuitPublicInputs( TxConstantData.empty(), RollupValidationRequests.empty(), + Gas.empty(), AztecAddress.ZERO, undefined, PartialPrivateTailPublicInputsForRollup.empty(), @@ -276,6 +287,7 @@ export class PrivateKernelTailCircuitPublicInputs { return new PrivateKernelTailCircuitPublicInputs( TxConstantData.empty(), RollupValidationRequests.empty(), + Gas.empty(), AztecAddress.ZERO, undefined, new PartialPrivateTailPublicInputsForRollup(data), diff --git a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts index 6db4c8979ae..069629ac373 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts @@ -14,7 +14,6 @@ import { MAX_NULLIFIERS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, } from '../../constants.gen.js'; -import { Gas } from '../gas.js'; import { ScopedL2ToL1Message } from '../l2_to_l1_message.js'; import { LogHash, ScopedLogHash } from '../log_hash.js'; import { PublicCallRequest } from '../public_call_request.js'; @@ -28,7 +27,6 @@ export class PrivateToPublicAccumulatedData { public encryptedLogsHashes: Tuple, public unencryptedLogsHashes: Tuple, public publicCallRequests: Tuple, - public gasUsed: Gas, ) {} getSize() { @@ -39,8 +37,7 @@ export class PrivateToPublicAccumulatedData { arraySerializedSizeOfNonEmpty(this.noteEncryptedLogsHashes) + arraySerializedSizeOfNonEmpty(this.encryptedLogsHashes) + arraySerializedSizeOfNonEmpty(this.unencryptedLogsHashes) + - arraySerializedSizeOfNonEmpty(this.publicCallRequests) + - this.gasUsed.toBuffer().length + arraySerializedSizeOfNonEmpty(this.publicCallRequests) ); } @@ -53,7 +50,6 @@ export class PrivateToPublicAccumulatedData { fields.encryptedLogsHashes, fields.unencryptedLogsHashes, fields.publicCallRequests, - fields.gasUsed, ] as const; } @@ -67,7 +63,6 @@ export class PrivateToPublicAccumulatedData { reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, ScopedLogHash), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_TX, ScopedLogHash), reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest), - reader.readObject(Gas), ); } @@ -85,7 +80,6 @@ export class PrivateToPublicAccumulatedData { reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, ScopedLogHash), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_TX, ScopedLogHash), reader.readArray(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest), - reader.readObject(Gas), ); } @@ -102,7 +96,6 @@ export class PrivateToPublicAccumulatedData { makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, ScopedLogHash.empty), makeTuple(MAX_UNENCRYPTED_LOGS_PER_TX, ScopedLogHash.empty), makeTuple(MAX_ENQUEUED_CALLS_PER_TX, PublicCallRequest.empty), - Gas.empty(), ); } @@ -136,7 +129,6 @@ export class PrivateToPublicAccumulatedData { .filter(x => !x.isEmpty()) .map(h => inspect(h)) .join(', ')}], - gasUsed: [${inspect(this.gasUsed)}] }`; } } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data_builder.ts b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data_builder.ts index 802e541d16c..9ab560d782f 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data_builder.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data_builder.ts @@ -10,7 +10,6 @@ import { MAX_NULLIFIERS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, } from '../../constants.gen.js'; -import { Gas } from '../gas.js'; import { ScopedL2ToL1Message } from '../l2_to_l1_message.js'; import { LogHash, ScopedLogHash } from '../log_hash.js'; import { PublicCallRequest } from '../public_call_request.js'; @@ -30,7 +29,6 @@ export class PrivateToPublicAccumulatedDataBuilder { private encryptedLogsHashes: ScopedLogHash[] = []; private unencryptedLogsHashes: ScopedLogHash[] = []; private publicCallStack: PublicCallRequest[] = []; - private gasUsed: Gas = Gas.empty(); pushNoteHash(newNoteHash: Fr) { this.noteHashes.push(newNoteHash); @@ -102,11 +100,6 @@ export class PrivateToPublicAccumulatedDataBuilder { return this; } - withGasUsed(gasUsed: Gas) { - this.gasUsed = gasUsed; - return this; - } - build() { return new PrivateToPublicAccumulatedData( padArrayEnd(this.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX), @@ -116,7 +109,6 @@ export class PrivateToPublicAccumulatedDataBuilder { padArrayEnd(this.encryptedLogsHashes, ScopedLogHash.empty(), MAX_ENCRYPTED_LOGS_PER_TX), padArrayEnd(this.unencryptedLogsHashes, ScopedLogHash.empty(), MAX_UNENCRYPTED_LOGS_PER_TX), padArrayEnd(this.publicCallStack, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX), - this.gasUsed, ); } @@ -128,7 +120,6 @@ export class PrivateToPublicAccumulatedDataBuilder { .withNoteEncryptedLogsHashes(publicAccumulatedData.noteEncryptedLogsHashes) .withEncryptedLogsHashes(publicAccumulatedData.encryptedLogsHashes) .withUnencryptedLogsHashes(publicAccumulatedData.unencryptedLogsHashes) - .withPublicCallStack(publicAccumulatedData.publicCallRequests) - .withGasUsed(publicAccumulatedData.gasUsed); + .withPublicCallStack(publicAccumulatedData.publicCallRequests); } } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_to_public_kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_to_public_kernel_circuit_public_inputs.ts index 7e1e45f176d..7a93e0cee96 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_to_public_kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_to_public_kernel_circuit_public_inputs.ts @@ -1,6 +1,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { Gas } from '../gas.js'; import { PublicCallRequest } from '../public_call_request.js'; import { RollupValidationRequests } from '../rollup_validation_requests.js'; import { PrivateToPublicAccumulatedData } from './private_to_public_accumulated_data.js'; @@ -13,6 +14,7 @@ export class PrivateToPublicKernelCircuitPublicInputs { public nonRevertibleAccumulatedData: PrivateToPublicAccumulatedData, public revertibleAccumulatedData: PrivateToPublicAccumulatedData, public publicTeardownCallRequest: PublicCallRequest, + public gasUsed: Gas, public feePayer: AztecAddress, ) {} @@ -23,6 +25,7 @@ export class PrivateToPublicKernelCircuitPublicInputs { this.nonRevertibleAccumulatedData, this.revertibleAccumulatedData, this.publicTeardownCallRequest, + this.gasUsed, this.feePayer, ); } @@ -35,6 +38,7 @@ export class PrivateToPublicKernelCircuitPublicInputs { reader.readObject(PrivateToPublicAccumulatedData), reader.readObject(PrivateToPublicAccumulatedData), reader.readObject(PublicCallRequest), + reader.readObject(Gas), reader.readObject(AztecAddress), ); } @@ -46,6 +50,7 @@ export class PrivateToPublicKernelCircuitPublicInputs { PrivateToPublicAccumulatedData.empty(), PrivateToPublicAccumulatedData.empty(), PublicCallRequest.empty(), + Gas.empty(), AztecAddress.ZERO, ); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index cbfe639b20a..fc8fc097757 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -394,7 +394,6 @@ export function makeCombinedAccumulatedData(seed = 1, full = false): CombinedAcc fr(seed + 0xb00), // encrypted_log_preimages_length fr(seed + 0xc00), // unencrypted_log_preimages_length tupleGenerator(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataWrite, seed + 0xd00, PublicDataWrite.empty), - makeGas(seed + 0xe00), ); } @@ -407,7 +406,6 @@ export function makePrivateToPublicAccumulatedData(seed = 1) { makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, makeScopedLogHash, seed + 0x800), makeTuple(MAX_UNENCRYPTED_LOGS_PER_TX, makeScopedLogHash, seed + 0x900), makeTuple(MAX_ENQUEUED_CALLS_PER_TX, makePublicCallRequest, seed + 0x500), - makeGas(seed + 0x600), ); } @@ -589,6 +587,7 @@ export function makePrivateKernelTailCircuitPublicInputs( return new PrivateKernelTailCircuitPublicInputs( makeTxConstantData(seed + 0x300), makeRollupValidationRequests(seed + 0x500), + makeGas(seed + 0x600), makeAztecAddress(seed + 0x700), forPublic, forRollup, @@ -602,7 +601,8 @@ function makePrivateToPublicKernelCircuitPublicInputs(seed = 1) { makePrivateToPublicAccumulatedData(seed + 0x200), makePrivateToPublicAccumulatedData(seed + 0x300), makePublicCallRequest(seed + 0x400), - makeAztecAddress(seed + 0x500), + makeGas(seed + 0x500), + makeAztecAddress(seed + 0x600), ); } @@ -618,6 +618,7 @@ export function makeKernelCircuitPublicInputs(seed = 1, fullAccumulatedData = tr makeCombinedConstantData(seed + 0x100), makePartialStateReference(seed + 0x200), RevertCode.OK, + makeGas(seed + 0x600), makeAztecAddress(seed + 0x700), ); } @@ -643,6 +644,7 @@ function makeAvmCircuitPublicInputs(seed = 1) { return new AvmCircuitPublicInputs( makeGlobalVariables(seed), makeTreeSnapshots(seed + 0x10), + makeGas(), makeGasSettings(), makeTuple(MAX_ENQUEUED_CALLS_PER_TX, makePublicCallRequest, seed + 0x100), makeTuple(MAX_ENQUEUED_CALLS_PER_TX, makePublicCallRequest, seed + 0x200), diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index e612e5413ef..4f0147f12ae 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -1539,7 +1539,6 @@ function mapPrivateToPublicAccumulatedDataFromNoir(data: PrivateToPublicAccumula mapTupleFromNoir(data.encrypted_logs_hashes, MAX_ENCRYPTED_LOGS_PER_TX, mapScopedLogHashFromNoir), mapTupleFromNoir(data.unencrypted_logs_hashes, MAX_UNENCRYPTED_LOGS_PER_TX, mapScopedLogHashFromNoir), mapTupleFromNoir(data.public_call_requests, MAX_ENQUEUED_CALLS_PER_TX, mapPublicCallRequestFromNoir), - mapGasFromNoir(data.gas_used), ); } @@ -1554,7 +1553,6 @@ function mapPrivateToPublicAccumulatedDataToNoir( encrypted_logs_hashes: mapTuple(data.encryptedLogsHashes, mapScopedLogHashToNoir), unencrypted_logs_hashes: mapTuple(data.unencryptedLogsHashes, mapScopedLogHashToNoir), public_call_requests: mapTuple(data.publicCallRequests, mapPublicCallRequestToNoir), - gas_used: mapGasToNoir(data.gasUsed), }; } @@ -1621,7 +1619,6 @@ export function mapCombinedAccumulatedDataFromNoir( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, mapPublicDataWriteFromNoir, ), - mapGasFromNoir(combinedAccumulatedData.gas_used), ); } @@ -1639,7 +1636,6 @@ export function mapCombinedAccumulatedDataToNoir( encrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.unencryptedLogPreimagesLength), public_data_writes: mapTuple(combinedAccumulatedData.publicDataWrites, mapPublicDataWriteToNoir), - gas_used: mapGasToNoir(combinedAccumulatedData.gasUsed), }; } @@ -1705,6 +1701,7 @@ export function mapPrivateToPublicKernelCircuitPublicInputsToNoir( non_revertible_accumulated_data: mapPrivateToPublicAccumulatedDataToNoir(inputs.nonRevertibleAccumulatedData), revertible_accumulated_data: mapPrivateToPublicAccumulatedDataToNoir(inputs.revertibleAccumulatedData), public_teardown_call_request: mapPublicCallRequestToNoir(inputs.publicTeardownCallRequest), + gas_used: mapGasToNoir(inputs.gasUsed), fee_payer: mapAztecAddressToNoir(inputs.feePayer), }; } @@ -1716,6 +1713,7 @@ export function mapKernelCircuitPublicInputsFromNoir(inputs: KernelCircuitPublic mapCombinedConstantDataFromNoir(inputs.constants), mapPartialStateReferenceFromNoir(inputs.start_state), mapRevertCodeFromNoir(inputs.revert_code), + mapGasFromNoir(inputs.gas_used), mapAztecAddressFromNoir(inputs.fee_payer), ); } @@ -1727,6 +1725,7 @@ export function mapKernelCircuitPublicInputsToNoir(inputs: KernelCircuitPublicIn end: mapCombinedAccumulatedDataToNoir(inputs.end), start_state: mapPartialStateReferenceToNoir(inputs.startState), revert_code: mapRevertCodeToNoir(inputs.revertCode), + gas_used: mapGasToNoir(inputs.gasUsed), fee_payer: mapAztecAddressToNoir(inputs.feePayer), }; } @@ -1815,6 +1814,7 @@ export function mapPrivateKernelTailCircuitPublicInputsForRollupFromNoir( return new PrivateKernelTailCircuitPublicInputs( mapTxConstantDataFromNoir(inputs.constants), mapRollupValidationRequestsFromNoir(inputs.rollup_validation_requests), + mapGasFromNoir(inputs.gas_used), mapAztecAddressFromNoir(inputs.fee_payer), undefined, forRollup, @@ -1832,6 +1832,7 @@ export function mapPrivateKernelTailCircuitPublicInputsForPublicFromNoir( return new PrivateKernelTailCircuitPublicInputs( mapTxConstantDataFromNoir(inputs.constants), mapRollupValidationRequestsFromNoir(inputs.rollup_validation_requests), + mapGasFromNoir(inputs.gas_used), mapAztecAddressFromNoir(inputs.fee_payer), forPublic, ); @@ -2107,6 +2108,7 @@ function mapAvmCircuitPublicInputsToNoir(inputs: AvmCircuitPublicInputs): AvmCir return { global_variables: mapGlobalVariablesToNoir(inputs.globalVariables), start_tree_snapshots: mapTreeSnapshotsToNoir(inputs.startTreeSnapshots), + start_gas_used: mapGasToNoir(inputs.startGasUsed), gas_settings: mapGasSettingsToNoir(inputs.gasSettings), public_setup_call_requests: mapTuple(inputs.publicSetupCallRequests, mapPublicCallRequestToNoir), public_app_logic_call_requests: mapTuple(inputs.publicAppLogicCallRequests, mapPublicCallRequestToNoir), diff --git a/yarn-project/sequencer-client/src/tx_validator/gas_validator.test.ts b/yarn-project/sequencer-client/src/tx_validator/gas_validator.test.ts index de4c0be3736..172c7ef67fd 100644 --- a/yarn-project/sequencer-client/src/tx_validator/gas_validator.test.ts +++ b/yarn-project/sequencer-client/src/tx_validator/gas_validator.test.ts @@ -26,7 +26,7 @@ describe('GasTxValidator', () => { let tx: Tx; let payer: AztecAddress; let expectedBalanceSlot: Fr; - let feeLimit = 0n; + let feeLimit: bigint; beforeEach(() => { tx = mockTx(1, { numberOfNonRevertiblePublicCallRequests: 2 }); diff --git a/yarn-project/simulator/src/mocks/fixtures.ts b/yarn-project/simulator/src/mocks/fixtures.ts index 9a267e689bd..9c5bd74e06d 100644 --- a/yarn-project/simulator/src/mocks/fixtures.ts +++ b/yarn-project/simulator/src/mocks/fixtures.ts @@ -51,7 +51,7 @@ export class PublicExecutionResultBuilder { build(overrides: Partial = {}): EnqueuedPublicCallExecutionResult { return { - endGasLeft: new Gas(0, 0), + endGasLeft: Gas.empty(), endSideEffectCounter: Fr.ZERO, returnValues: padArrayEnd(this._returnValues, Fr.ZERO, 4), // TODO(#5450) Need to use the proper return values here reverted: this._reverted, diff --git a/yarn-project/simulator/src/public/enqueued_calls_processor.test.ts b/yarn-project/simulator/src/public/enqueued_calls_processor.test.ts index 6622c06322b..dfccb2e1216 100644 --- a/yarn-project/simulator/src/public/enqueued_calls_processor.test.ts +++ b/yarn-project/simulator/src/public/enqueued_calls_processor.test.ts @@ -33,7 +33,6 @@ import { type AvmPersistableStateManager } from '../avm/journal/journal.js'; import { PublicExecutionResultBuilder } from '../mocks/fixtures.js'; import { WASMSimulator } from '../providers/acvm_wasm.js'; import { EnqueuedCallsProcessor } from './enqueued_calls_processor.js'; -import { type EnqueuedPublicCallExecutionResult } from './execution.js'; import { type PublicExecutor } from './executor.js'; import { type WorldStateDB } from './public_db_sources.js'; import { RealPublicKernelCircuitSimulator } from './public_kernel.js'; @@ -46,9 +45,8 @@ describe('enqueued_calls_processor', () => { const teardownGasLimits = Gas.from({ daGas: 20, l2Gas: 30 }); const maxFeesPerGas = gasFees; - // gasUsed for the tx after private execution. - const txPrivateNonRevertibleGasUsed = Gas.from({ daGas: 13, l2Gas: 17 }); - const txPrivateRevertibleGasUsed = Gas.from({ daGas: 7, l2Gas: 11 }); + // gasUsed for the tx after private execution, minus the teardownGasLimits. + const privateGasUsed = Gas.from({ daGas: 13, l2Gas: 17 }); // gasUsed for each enqueued call. const enqueuedCallGasUsed = new Gas(12, 34); @@ -81,23 +79,30 @@ describe('enqueued_calls_processor', () => { tx.data.forPublic!.nonRevertibleAccumulatedData.nullifiers[0] = new Fr(7777); tx.data.forPublic!.nonRevertibleAccumulatedData.nullifiers[1] = new Fr(8888); - tx.data.forPublic!.nonRevertibleAccumulatedData.gasUsed = txPrivateNonRevertibleGasUsed; tx.data.forPublic!.revertibleAccumulatedData.nullifiers[0] = new Fr(9999); - tx.data.forPublic!.revertibleAccumulatedData.gasUsed = txPrivateRevertibleGasUsed; + + tx.data.gasUsed = privateGasUsed; + if (hasPublicTeardownCall) { + tx.data.gasUsed = tx.data.gasUsed.add(teardownGasLimits); + } return tx; }; const mockPublicExecutor = ( - mockedSimulatorExecutions: ((stateManager: AvmPersistableStateManager) => Promise)[], + mockedSimulatorExecutions: (( + stateManager: AvmPersistableStateManager, + resultBuilder: PublicExecutionResultBuilder, + ) => Promise)[], ) => { for (const executeSimulator of mockedSimulatorExecutions) { publicExecutor.simulate.mockImplementationOnce( - async (stateManager: AvmPersistableStateManager, _executionResult, _globalVariables, allocatedGas) => { - const builder = await executeSimulator(stateManager); + async (stateManager: AvmPersistableStateManager, _executionResult, _globalVariables, availableGas) => { + const builder = PublicExecutionResultBuilder.empty(); + await executeSimulator(stateManager, builder); return builder.build({ - endGasLeft: allocatedGas.sub(enqueuedCallGasUsed), + endGasLeft: availableGas.sub(enqueuedCallGasUsed), }); }, ); @@ -124,9 +129,9 @@ describe('enqueued_calls_processor', () => { root = Buffer.alloc(32, 5); publicExecutor = mock(); - publicExecutor.simulate.mockImplementation((_stateManager, _executionResult, _globalVariables, allocatedGas) => { + publicExecutor.simulate.mockImplementation((_stateManager, _executionResult, _globalVariables, availableGas) => { const result = PublicExecutionResultBuilder.empty().build({ - endGasLeft: allocatedGas.sub(enqueuedCallGasUsed), + endGasLeft: availableGas.sub(enqueuedCallGasUsed), }); return Promise.resolve(result); }); @@ -184,15 +189,14 @@ describe('enqueued_calls_processor', () => { expect(txResult.revertCode).toEqual(RevertCode.OK); expect(txResult.revertReason).toBe(undefined); - const expectedPrivateGasUsed = txPrivateNonRevertibleGasUsed.add(txPrivateRevertibleGasUsed); const expectedPublicGasUsed = enqueuedCallGasUsed.mul(2); // For 2 setup calls. - const expectedTotalGas = expectedPrivateGasUsed.add(expectedPublicGasUsed); + const expectedTotalGas = privateGasUsed.add(expectedPublicGasUsed); expect(txResult.gasUsed).toEqual({ totalGas: expectedTotalGas, teardownGas: Gas.empty(), }); - const availableGasForFirstSetup = gasLimits.sub(txPrivateNonRevertibleGasUsed); + const availableGasForFirstSetup = gasLimits.sub(privateGasUsed); const availableGasForSecondSetup = availableGasForFirstSetup.sub(enqueuedCallGasUsed); expectAvailableGasForCalls([availableGasForFirstSetup, availableGasForSecondSetup]); @@ -218,15 +222,14 @@ describe('enqueued_calls_processor', () => { expect(txResult.revertCode).toEqual(RevertCode.OK); expect(txResult.revertReason).toBe(undefined); - const expectedPrivateGasUsed = txPrivateNonRevertibleGasUsed.add(txPrivateRevertibleGasUsed); const expectedPublicGasUsed = enqueuedCallGasUsed.mul(2); // For 2 app logic calls. - const expectedTotalGas = expectedPrivateGasUsed.add(expectedPublicGasUsed); + const expectedTotalGas = privateGasUsed.add(expectedPublicGasUsed); expect(txResult.gasUsed).toEqual({ totalGas: expectedTotalGas, teardownGas: Gas.empty(), }); - const availableGasForFirstAppLogic = gasLimits.sub(expectedPrivateGasUsed); + const availableGasForFirstAppLogic = gasLimits.sub(privateGasUsed); const availableGasForSecondAppLogic = availableGasForFirstAppLogic.sub(enqueuedCallGasUsed); expectAvailableGasForCalls([availableGasForFirstAppLogic, availableGasForSecondAppLogic]); @@ -252,9 +255,8 @@ describe('enqueued_calls_processor', () => { expect(txResult.revertCode).toEqual(RevertCode.OK); expect(txResult.revertReason).toBe(undefined); - const expectedPrivateGasUsed = txPrivateNonRevertibleGasUsed.add(txPrivateRevertibleGasUsed); const expectedTeardownGasUsed = enqueuedCallGasUsed; - const expectedTotalGas = expectedPrivateGasUsed.add(expectedTeardownGasUsed); + const expectedTotalGas = privateGasUsed.add(expectedTeardownGasUsed); expect(txResult.gasUsed).toEqual({ totalGas: expectedTotalGas, teardownGas: expectedTeardownGasUsed, @@ -290,19 +292,18 @@ describe('enqueued_calls_processor', () => { expect(txResult.revertCode).toEqual(RevertCode.OK); expect(txResult.revertReason).toBe(undefined); - const expectedPrivateGasUsed = txPrivateNonRevertibleGasUsed.add(txPrivateRevertibleGasUsed); const expectedPublicGasUsed = enqueuedCallGasUsed.mul(3); // 2 for setup and 1 for app logic. const expectedTeardownGasUsed = enqueuedCallGasUsed; - const expectedTotalGas = expectedPrivateGasUsed.add(expectedPublicGasUsed).add(expectedTeardownGasUsed); + const expectedTotalGas = privateGasUsed.add(expectedPublicGasUsed).add(expectedTeardownGasUsed); expect(txResult.gasUsed).toEqual({ totalGas: expectedTotalGas, teardownGas: expectedTeardownGasUsed, }); // Check that each enqueued call is allocated the correct amount of gas. - const availableGasForFirstSetup = gasLimits.sub(teardownGasLimits).sub(txPrivateNonRevertibleGasUsed); + const availableGasForFirstSetup = gasLimits.sub(teardownGasLimits).sub(privateGasUsed); const availableGasForSecondSetup = availableGasForFirstSetup.sub(enqueuedCallGasUsed); - const availableGasForAppLogic = availableGasForSecondSetup.sub(txPrivateRevertibleGasUsed).sub(enqueuedCallGasUsed); + const availableGasForAppLogic = availableGasForSecondSetup.sub(enqueuedCallGasUsed); expectAvailableGasForCalls([ availableGasForFirstSetup, availableGasForSecondSetup, @@ -334,7 +335,7 @@ describe('enqueued_calls_processor', () => { const contractSlotB = fr(0x150); const contractSlotC = fr(0x200); - const mockedSimulatorExecutions = [ + mockPublicExecutor([ // SETUP async (_stateManager: AvmPersistableStateManager) => { // Nothing happened in setup phase. @@ -355,24 +356,7 @@ describe('enqueued_calls_processor', () => { stateManager.writeStorage(contractAddress, contractSlotC, fr(0x152)); await stateManager.readStorage(contractAddress, contractSlotA); }, - ]; - - for (const executeSimulator of mockedSimulatorExecutions) { - publicExecutor.simulate.mockImplementationOnce( - async ( - stateManager: AvmPersistableStateManager, - _executionResult, - _globalVariables, - allocatedGas, - ): Promise => { - await executeSimulator(stateManager); - const result = PublicExecutionResultBuilder.empty().build({ - endGasLeft: allocatedGas.sub(enqueuedCallGasUsed), - }); - return Promise.resolve(result); - }, - ); - } + ]); const txResult = await processor.process(tx); @@ -415,7 +399,7 @@ describe('enqueued_calls_processor', () => { it('includes a transaction that reverts in app logic', async function () { const tx = mockTxWithPublicCalls({ numberOfSetupCalls: 1, - numberOfAppLogicCalls: 1, + numberOfAppLogicCalls: 2, hasPublicTeardownCall: true, }); @@ -425,21 +409,20 @@ describe('enqueued_calls_processor', () => { mockPublicExecutor([ // SETUP async (stateManager: AvmPersistableStateManager) => { - // mock nullifiers on the state manager await stateManager.writeNullifier(contractAddress, new Fr(1)); - return PublicExecutionResultBuilder.empty(); }, // APP LOGIC async (stateManager: AvmPersistableStateManager) => { - // mock nullifiers the state manager await stateManager.writeNullifier(contractAddress, new Fr(2)); await stateManager.writeNullifier(contractAddress, new Fr(3)); - return PublicExecutionResultBuilder.empty().withReverted(appLogicFailure); }, - async (stateManager: AvmPersistableStateManager) => { - // mock nullifiers the state manager + async (stateManager: AvmPersistableStateManager, resultBuilder: PublicExecutionResultBuilder) => { await stateManager.writeNullifier(contractAddress, new Fr(4)); - return PublicExecutionResultBuilder.empty(); + resultBuilder.withReverted(appLogicFailure); + }, + // TEARDOWN + async (stateManager: AvmPersistableStateManager) => { + await stateManager.writeNullifier(contractAddress, new Fr(5)); }, ]); @@ -455,20 +438,24 @@ describe('enqueued_calls_processor', () => { // tx reports app logic failure expect(txResult.revertReason).toBe(appLogicFailure); - const expectedSetupGas = txPrivateNonRevertibleGasUsed.add(enqueuedCallGasUsed); - const { l2Gas: appLogicL2Gas } = txPrivateRevertibleGasUsed.add(enqueuedCallGasUsed); - // All data emitted from app logic were discarded. daGas set to 0. - const expectedAppLogicGas = Gas.from({ daGas: 0, l2Gas: appLogicL2Gas }); + const expectedSetupGas = enqueuedCallGasUsed; + const expectedAppLogicGas = enqueuedCallGasUsed.mul(2); const expectedTeardownGasUsed = enqueuedCallGasUsed; - const expectedTotalGas = expectedSetupGas.add(expectedAppLogicGas).add(expectedTeardownGasUsed); + const expectedTotalGas = privateGasUsed.add(expectedSetupGas).add(expectedAppLogicGas).add(expectedTeardownGasUsed); expect(txResult.gasUsed).toEqual({ totalGas: expectedTotalGas, teardownGas: expectedTeardownGasUsed, }); - const availableGasForSetup = gasLimits.sub(teardownGasLimits).sub(txPrivateNonRevertibleGasUsed); - const allocatedAppLogicGas = availableGasForSetup.sub(txPrivateRevertibleGasUsed).sub(enqueuedCallGasUsed); - expectAvailableGasForCalls([availableGasForSetup, allocatedAppLogicGas, teardownGasLimits]); + const availableGasForSetup = gasLimits.sub(teardownGasLimits).sub(privateGasUsed); + const availableGasForFirstAppLogic = availableGasForSetup.sub(enqueuedCallGasUsed); + const availableGasForSecondAppLogic = availableGasForFirstAppLogic.sub(enqueuedCallGasUsed); + expectAvailableGasForCalls([ + availableGasForSetup, + availableGasForFirstAppLogic, + availableGasForSecondAppLogic, + teardownGasLimits, + ]); const output = txResult.avmProvingRequest!.inputs.output; @@ -482,14 +469,14 @@ describe('enqueued_calls_processor', () => { new Fr(7777), new Fr(8888), siloNullifier(contractAddress, new Fr(1)), - siloNullifier(contractAddress, new Fr(4)), + siloNullifier(contractAddress, new Fr(5)), ]); }); it('includes a transaction that reverts in teardown', async function () { const tx = mockTxWithPublicCalls({ numberOfSetupCalls: 1, - numberOfAppLogicCalls: 1, + numberOfAppLogicCalls: 2, hasPublicTeardownCall: true, }); @@ -499,21 +486,20 @@ describe('enqueued_calls_processor', () => { mockPublicExecutor([ // SETUP async (stateManager: AvmPersistableStateManager) => { - // mock nullifiers on the state manager await stateManager.writeNullifier(contractAddress, new Fr(1)); - return PublicExecutionResultBuilder.empty(); }, // APP LOGIC async (stateManager: AvmPersistableStateManager) => { - // mock nullifiers on the state manager await stateManager.writeNullifier(contractAddress, new Fr(2)); await stateManager.writeNullifier(contractAddress, new Fr(3)); - return PublicExecutionResultBuilder.empty(); }, async (stateManager: AvmPersistableStateManager) => { - // mock nullifiers on the state manager await stateManager.writeNullifier(contractAddress, new Fr(4)); - return PublicExecutionResultBuilder.empty().withReverted(teardownFailure); + }, + // TEARDOWN + async (stateManager: AvmPersistableStateManager, resultBuilder: PublicExecutionResultBuilder) => { + await stateManager.writeNullifier(contractAddress, new Fr(5)); + resultBuilder.withReverted(teardownFailure); }, ]); @@ -527,20 +513,24 @@ describe('enqueued_calls_processor', () => { expect(txResult.revertCode).toEqual(RevertCode.TEARDOWN_REVERTED); expect(txResult.revertReason).toBe(teardownFailure); - const expectedSetupGas = txPrivateNonRevertibleGasUsed.add(enqueuedCallGasUsed); - const expectedAppLogicGas = txPrivateRevertibleGasUsed.add(enqueuedCallGasUsed); - const { l2Gas: teardownL2Gas } = enqueuedCallGasUsed; - // All data emitted from teardown were discarded. daGas set to 0. - const expectedTeardownGasUsed = Gas.from({ daGas: 0, l2Gas: teardownL2Gas }); - const expectedTotalGas = expectedSetupGas.add(expectedAppLogicGas).add(expectedTeardownGasUsed); + const expectedSetupGas = enqueuedCallGasUsed; + const expectedAppLogicGas = enqueuedCallGasUsed.mul(2); + const expectedTeardownGasUsed = enqueuedCallGasUsed; + const expectedTotalGas = privateGasUsed.add(expectedSetupGas).add(expectedAppLogicGas).add(expectedTeardownGasUsed); expect(txResult.gasUsed).toEqual({ totalGas: expectedTotalGas, teardownGas: expectedTeardownGasUsed, }); - const availableGasForSetup = gasLimits.sub(teardownGasLimits).sub(txPrivateNonRevertibleGasUsed); - const allocatedAppLogicGas = availableGasForSetup.sub(txPrivateRevertibleGasUsed).sub(enqueuedCallGasUsed); - expectAvailableGasForCalls([availableGasForSetup, allocatedAppLogicGas, teardownGasLimits]); + const availableGasForSetup = gasLimits.sub(teardownGasLimits).sub(privateGasUsed); + const availableGasForFirstAppLogic = availableGasForSetup.sub(enqueuedCallGasUsed); + const availableGasForSecondAppLogic = availableGasForFirstAppLogic.sub(enqueuedCallGasUsed); + expectAvailableGasForCalls([ + availableGasForSetup, + availableGasForFirstAppLogic, + availableGasForSecondAppLogic, + teardownGasLimits, + ]); const output = txResult.avmProvingRequest!.inputs.output; @@ -557,14 +547,16 @@ describe('enqueued_calls_processor', () => { // new Fr(9999), // TODO: Data in app logic should be kept if teardown reverts. siloNullifier(contractAddress, new Fr(1)), // siloNullifier(contractAddress, new Fr(2)), - // siloNullifier(contractAddress, new Fr(2)), + // siloNullifier(contractAddress, new Fr(3)), + // siloNullifier(contractAddress, new Fr(4)), + // siloNullifier(contractAddress, new Fr(5)), ]); }); it('includes a transaction that reverts in app logic and teardown', async function () { const tx = mockTxWithPublicCalls({ numberOfSetupCalls: 1, - numberOfAppLogicCalls: 1, + numberOfAppLogicCalls: 2, hasPublicTeardownCall: true, }); @@ -574,21 +566,21 @@ describe('enqueued_calls_processor', () => { mockPublicExecutor([ // SETUP async (stateManager: AvmPersistableStateManager) => { - // mock nullifiers on the state manager await stateManager.writeNullifier(contractAddress, new Fr(1)); - return PublicExecutionResultBuilder.empty(); }, // APP LOGIC async (stateManager: AvmPersistableStateManager) => { - // mock nullifiers on the state manager await stateManager.writeNullifier(contractAddress, new Fr(2)); await stateManager.writeNullifier(contractAddress, new Fr(3)); - return PublicExecutionResultBuilder.empty().withReverted(appLogicFailure); }, - async (stateManager: AvmPersistableStateManager) => { - // mock nullifiers on the state manager + async (stateManager: AvmPersistableStateManager, resultBuilder: PublicExecutionResultBuilder) => { await stateManager.writeNullifier(contractAddress, new Fr(4)); - return PublicExecutionResultBuilder.empty().withReverted(teardownFailure); + resultBuilder.withReverted(appLogicFailure); + }, + // TEARDOWN + async (stateManager: AvmPersistableStateManager, resultBuilder: PublicExecutionResultBuilder) => { + await stateManager.writeNullifier(contractAddress, new Fr(5)); + resultBuilder.withReverted(teardownFailure); }, ]); @@ -604,22 +596,24 @@ describe('enqueued_calls_processor', () => { // tx reports app logic failure expect(txResult.revertReason).toBe(appLogicFailure); - const expectedSetupGas = txPrivateNonRevertibleGasUsed.add(enqueuedCallGasUsed); - const { l2Gas: appLogicL2Gas } = txPrivateRevertibleGasUsed.add(enqueuedCallGasUsed); - // All data emitted from app logic were discarded. daGas set to 0. - const expectedAppLogicGas = Gas.from({ daGas: 0, l2Gas: appLogicL2Gas }); - const { l2Gas: teardownL2Gas } = enqueuedCallGasUsed; - // All data emitted from teardown were discarded. daGas set to 0. - const expectedTeardownGasUsed = Gas.from({ daGas: 0, l2Gas: teardownL2Gas }); - const expectedTotalGas = expectedSetupGas.add(expectedAppLogicGas).add(expectedTeardownGasUsed); + const expectedSetupGas = enqueuedCallGasUsed; + const expectedAppLogicGas = enqueuedCallGasUsed.mul(2); + const expectedTeardownGasUsed = enqueuedCallGasUsed; + const expectedTotalGas = privateGasUsed.add(expectedSetupGas).add(expectedAppLogicGas).add(expectedTeardownGasUsed); expect(txResult.gasUsed).toEqual({ totalGas: expectedTotalGas, teardownGas: expectedTeardownGasUsed, }); - const availableGasForSetup = gasLimits.sub(teardownGasLimits).sub(txPrivateNonRevertibleGasUsed); - const allocatedAppLogicGas = availableGasForSetup.sub(txPrivateRevertibleGasUsed).sub(enqueuedCallGasUsed); - expectAvailableGasForCalls([availableGasForSetup, allocatedAppLogicGas, teardownGasLimits]); + const availableGasForSetup = gasLimits.sub(teardownGasLimits).sub(privateGasUsed); + const availableGasForFirstAppLogic = availableGasForSetup.sub(enqueuedCallGasUsed); + const availableGasForSecondAppLogic = availableGasForFirstAppLogic.sub(enqueuedCallGasUsed); + expectAvailableGasForCalls([ + availableGasForSetup, + availableGasForFirstAppLogic, + availableGasForSecondAppLogic, + teardownGasLimits, + ]); const output = txResult.avmProvingRequest!.inputs.output; diff --git a/yarn-project/simulator/src/public/enqueued_calls_processor.ts b/yarn-project/simulator/src/public/enqueued_calls_processor.ts index dc4bf63a502..1aaeef23cac 100644 --- a/yarn-project/simulator/src/public/enqueued_calls_processor.ts +++ b/yarn-project/simulator/src/public/enqueued_calls_processor.ts @@ -16,7 +16,6 @@ import { EnqueuedCallData, Fr, Gas, - type GasSettings, type GlobalVariables, type Header, type KernelCircuitPublicInputs, @@ -69,7 +68,7 @@ type PublicPhaseResult = { publicKernelOutput: PublicKernelCircuitPublicInputs; /** Return values of simulating complete callstack */ returnValues: NestedProcessReturnValues[]; - /** Gas used during the execution of a phase, including the gas used for the data emitted in the same phase from private */ + /** Gas used during the execution of this phase */ gasUsed: Gas; /** Time spent for the execution this phase */ durationMs: number; @@ -90,7 +89,7 @@ export type ProcessedPhase = { export type TxPublicCallsResult = { avmProvingRequest: AvmProvingRequest; - /** Gas used during the execution this tx */ + /** Gas used during the execution of this tx */ gasUsed: GasUsed; revertCode: RevertCode; /** Revert reason, if any */ @@ -174,13 +173,11 @@ export class EnqueuedCallsProcessor { this.log.verbose(`Processing tx ${tx.getTxHash()}`); const constants = CombinedConstantData.combine(tx.data.constants, this.globalVariables); - const gasSettings = constants.txContext.gasSettings; const phases: TxExecutionPhase[] = [TxExecutionPhase.SETUP, TxExecutionPhase.APP_LOGIC, TxExecutionPhase.TEARDOWN]; - const requireTeardown = tx.data.hasTeardownPublicCallRequest(); const processedPhases: ProcessedPhase[] = []; let phaseGasUsed: PhaseGasUsed = { - [TxExecutionPhase.SETUP]: tx.data.forPublic!.nonRevertibleAccumulatedData.gasUsed, - [TxExecutionPhase.APP_LOGIC]: tx.data.forPublic!.revertibleAccumulatedData.gasUsed, + [TxExecutionPhase.SETUP]: Gas.empty(), + [TxExecutionPhase.APP_LOGIC]: Gas.empty(), [TxExecutionPhase.TEARDOWN]: Gas.empty(), }; let avmProvingRequest: AvmProvingRequest; @@ -231,11 +228,8 @@ export class EnqueuedCallsProcessor { } const callRequests = EnqueuedCallsProcessor.getCallRequestsByPhase(tx, phase); if (callRequests.length) { - const allocatedGas = this.getAllocatedGasForPhase(gasSettings, phase, phaseGasUsed, requireTeardown); - const transactionFee = - phase !== TxExecutionPhase.TEARDOWN - ? Fr.ZERO - : this.getTransactionFee(gasSettings, phaseGasUsed, requireTeardown); + const allocatedGas = this.getAllocatedGasForPhase(phase, tx, phaseGasUsed); + const transactionFee = phase !== TxExecutionPhase.TEARDOWN ? Fr.ZERO : this.getTransactionFee(tx, phaseGasUsed); const executionRequests = EnqueuedCallsProcessor.getExecutionRequestsByPhase(tx, phase); const result = await this.processPhase( @@ -246,7 +240,6 @@ export class EnqueuedCallsProcessor { executionRequests, publicKernelOutput, allocatedGas, - phaseGasUsed[phase] /* initialGasUsed */, transactionFee, stateManagerForPhase, ).catch(async err => { @@ -293,12 +286,11 @@ export class EnqueuedCallsProcessor { }, ); - const transactionFee = this.getTransactionFee(gasSettings, phaseGasUsed, requireTeardown); + const transactionFee = this.getTransactionFee(tx, phaseGasUsed); avmProvingRequest!.inputs.output = this.generateAvmCircuitPublicInputs(tx, tailKernelOutput, transactionFee); - const totalGas = Object.values(phaseGasUsed).reduce((total, gas) => total.add(gas), Gas.empty()); const gasUsed = { - totalGas, + totalGas: this.getActualGasUsed(tx, phaseGasUsed), teardownGas: phaseGasUsed[TxExecutionPhase.TEARDOWN], }; @@ -319,7 +311,6 @@ export class EnqueuedCallsProcessor { executionRequests: PublicExecutionRequest[], previousPublicKernelOutput: PublicKernelCircuitPublicInputs, allocatedGas: Gas, - initialGasUsed: Gas, transactionFee: Fr, txStateManager: AvmPersistableStateManager, ): Promise { @@ -327,10 +318,9 @@ export class EnqueuedCallsProcessor { const phaseTimer = new Timer(); const returnValues: NestedProcessReturnValues[] = []; + let availableGas = allocatedGas; let avmProvingRequest: AvmProvingRequest; let publicKernelOutput = previousPublicKernelOutput; - let availableGas = allocatedGas.sub(initialGasUsed); - let gasUsedInPhase = initialGasUsed; let reverted: boolean = false; let revertReason: SimulationError | undefined; for (let i = callRequests.length - 1; i >= 0; i--) { @@ -373,18 +363,14 @@ export class EnqueuedCallsProcessor { enqueuedCallResult.reverted!, ); + availableGas = availableGas.sub(enqueuedCallResult.gasUsed); avmProvingRequest = enqueuedCallResult.avmProvingRequest; returnValues.push(enqueuedCallResult.returnValues); - availableGas = availableGas.sub(enqueuedCallResult.gasUsed); - gasUsedInPhase = gasUsedInPhase.add(enqueuedCallResult.gasUsed); reverted = enqueuedCallResult.reverted; revertReason = enqueuedCallResult.revertReason; // Instead of operating on worldStateDB here, do we do AvmPersistableStateManager.revert() or return()? if (reverted) { - // Clear daGas as no data will be emitted. - gasUsedInPhase = Gas.from({ daGas: 0, l2Gas: gasUsedInPhase.l2Gas }); - // TODO(#6464): Should we allow emitting contracts in the private setup phase? // if so, this is removing contracts deployed in private setup // You can't submit contracts in public, so this is only relevant for private-created @@ -405,38 +391,30 @@ export class EnqueuedCallsProcessor { avmProvingRequest: avmProvingRequest!, publicKernelOutput, durationMs: phaseTimer.ms(), - gasUsed: gasUsedInPhase, + gasUsed: allocatedGas.sub(availableGas), returnValues, reverted, revertReason, }; } - private getAllocatedGasForPhase( - gasSettings: GasSettings, - phase: TxExecutionPhase, - phaseGasUsed: PhaseGasUsed, - requireTeardown: boolean, - ) { - const gasForTeardown = requireTeardown ? gasSettings.teardownGasLimits : Gas.empty(); + private getAllocatedGasForPhase(phase: TxExecutionPhase, tx: Tx, phaseGasUsed: PhaseGasUsed) { + const gasSettings = tx.data.constants.txContext.gasSettings; if (phase === TxExecutionPhase.TEARDOWN) { - return gasForTeardown; - } - - const gasForSetup = gasSettings.gasLimits.sub(gasForTeardown); - if (phase === TxExecutionPhase.SETUP) { - return gasForSetup; + return gasSettings.teardownGasLimits; } else { - const gasForAppLogic = gasForSetup.sub(phaseGasUsed[TxExecutionPhase.SETUP]); - return gasForAppLogic; + return gasSettings.gasLimits + .sub(tx.data.gasUsed) + .sub(phaseGasUsed[TxExecutionPhase.SETUP]) + .sub(phaseGasUsed[TxExecutionPhase.APP_LOGIC]); } } - private getTransactionFee(gasSettings: GasSettings, phaseGasUsed: PhaseGasUsed, requireTeardown: boolean): Fr { + private getTransactionFee(tx: Tx, phaseGasUsed: PhaseGasUsed): Fr { const gasFees = this.globalVariables.gasFees; - const txFee = phaseGasUsed[TxExecutionPhase.SETUP] + const txFee = tx.data.gasUsed // This should've included teardown gas limits. + .add(phaseGasUsed[TxExecutionPhase.SETUP]) .add(phaseGasUsed[TxExecutionPhase.APP_LOGIC]) - .add(requireTeardown ? gasSettings.teardownGasLimits : Gas.empty()) .computeFee(gasFees); this.log.debug(`Computed tx fee`, { txFee, gasUsed: inspect(phaseGasUsed), gasFees: inspect(gasFees) }); @@ -444,6 +422,14 @@ export class EnqueuedCallsProcessor { return txFee; } + private getActualGasUsed(tx: Tx, phaseGasUsed: PhaseGasUsed) { + const requireTeardown = tx.data.hasTeardownPublicCallRequest(); + const teardownGasLimits = tx.data.constants.txContext.gasSettings.teardownGasLimits; + const privateGasUsed = tx.data.gasUsed.sub(requireTeardown ? teardownGasLimits : Gas.empty()); + const publicGasUsed = Object.values(phaseGasUsed).reduce((accum, gasUsed) => accum.add(gasUsed), Gas.empty()); + return privateGasUsed.add(publicGasUsed); + } + private async runMergeKernelCircuit( previousOutput: PublicKernelCircuitPublicInputs, enqueuedCallData: VMCircuitPublicInputs, @@ -486,7 +472,6 @@ export class EnqueuedCallsProcessor { to.encryptedLogsHashes.forEach((_, i) => (to.encryptedLogsHashes[i] = from.encryptedLogsHashes[i])); to.unencryptedLogsHashes.forEach((_, i) => (to.unencryptedLogsHashes[i] = from.unencryptedLogsHashes[i])); to.publicCallStack.forEach((_, i) => (to.publicCallStack[i] = from.publicCallRequests[i])); - (to.gasUsed as any) = from.gasUsed; return to; }; @@ -537,6 +522,7 @@ export class EnqueuedCallsProcessor { return new AvmCircuitPublicInputs( tailOutput.constants.globalVariables, startTreeSnapshots, + tx.data.gasUsed, tx.data.constants.txContext.gasSettings, tx.data.forPublic!.nonRevertibleAccumulatedData.publicCallRequests, tx.data.forPublic!.revertibleAccumulatedData.publicCallRequests, diff --git a/yarn-project/simulator/src/public/public_processor.test.ts b/yarn-project/simulator/src/public/public_processor.test.ts index c62c7c5e4c6..b15932abf08 100644 --- a/yarn-project/simulator/src/public/public_processor.test.ts +++ b/yarn-project/simulator/src/public/public_processor.test.ts @@ -201,7 +201,7 @@ describe('public_processor', () => { }); const privateGasUsed = new Gas(12, 34); - tx.data.forRollup!.end.gasUsed = privateGasUsed; + tx.data.gasUsed = privateGasUsed; const txFee = privateGasUsed.computeFee(globalVariables.gasFees); diff --git a/yarn-project/simulator/src/public/public_processor.ts b/yarn-project/simulator/src/public/public_processor.ts index 299acfe5c84..f248c965e3a 100644 --- a/yarn-project/simulator/src/public/public_processor.ts +++ b/yarn-project/simulator/src/public/public_processor.ts @@ -274,9 +274,9 @@ export class PublicProcessor { private async processPrivateOnlyTx(tx: Tx): Promise<[ProcessedTx]> { const gasFees = this.globalVariables.gasFees; - const accumulatedData = tx.data.forRollup!.end; - const transactionFee = accumulatedData.gasUsed.computeFee(gasFees); + const transactionFee = tx.data.gasUsed.computeFee(gasFees); + const accumulatedData = tx.data.forRollup!.end; const feePaymentPublicDataWrite = await this.getFeePaymentPublicDataWrite( accumulatedData.publicDataWrites, transactionFee, From ab885832b3e85823c4a3fe048e52299af3bac394 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 12 Nov 2024 11:02:24 +0000 Subject: [PATCH 6/7] Fix. --- .../components/tail_to_public_output_validator.nr | 6 +++--- .../rollup-lib/src/base/private_base_rollup.nr | 4 ++-- .../circuits.js/src/structs/gas_settings.ts | 2 -- .../kernel/private_to_public_accumulated_data.ts | 14 +++++++------- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr index 052583ecb66..ddfde23c024 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/tail_to_public_output_validator.nr @@ -146,14 +146,14 @@ impl TailToPublicOutputValidator { } fn validate_gas_used(self) { - let gas_limits = self.previous_kernel.constants.tx_context.gas_settings.gas_limits; + let gas_settings = self.output.constants.tx_context.gas_settings; let gas_used = meter_gas_used( self.output.non_revertible_accumulated_data, self.output.revertible_accumulated_data, self.output.public_teardown_call_request, - self.output.constants.tx_context.gas_settings.teardown_gas_limits, + gas_settings.teardown_gas_limits, ); assert_eq(self.output.gas_used, gas_used, "incorrect metered gas used"); - assert(gas_used.within(gas_limits), "The gas used exceeds the gas limits"); + assert(gas_used.within(gas_settings.gas_limits), "The gas used exceeds the gas limits"); } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr index 43bd41049b3..848147c61b9 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/private_base_rollup.nr @@ -41,8 +41,8 @@ pub struct PrivateBaseRollupInputs { impl PrivateBaseRollupInputs { fn compute_transaction_fee(self) -> Field { let gas_fees = self.constants.global_variables.gas_fees; - let data = self.tube_data.public_inputs; - data.gas_used.compute_fee(gas_fees) + let gas_used = self.tube_data.public_inputs.gas_used; + gas_used.compute_fee(gas_fees) } pub fn execute(self) -> BaseOrMergeRollupPublicInputs { diff --git a/yarn-project/circuits.js/src/structs/gas_settings.ts b/yarn-project/circuits.js/src/structs/gas_settings.ts index 9033535c2f0..9ea1dbea30a 100644 --- a/yarn-project/circuits.js/src/structs/gas_settings.ts +++ b/yarn-project/circuits.js/src/structs/gas_settings.ts @@ -1,6 +1,5 @@ import { compact } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; -import { schemas } from '@aztec/foundation/schemas'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; @@ -29,7 +28,6 @@ export class GasSettings { gasLimits: Gas.schema, teardownGasLimits: Gas.schema, maxFeesPerGas: GasFees.schema, - inclusionFee: schemas.Fr, }) .transform(GasSettings.from); } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts index 069629ac373..c23c188e125 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_to_public_accumulated_data.ts @@ -20,13 +20,13 @@ import { PublicCallRequest } from '../public_call_request.js'; export class PrivateToPublicAccumulatedData { constructor( - public noteHashes: Tuple, - public nullifiers: Tuple, - public l2ToL1Msgs: Tuple, - public noteEncryptedLogsHashes: Tuple, - public encryptedLogsHashes: Tuple, - public unencryptedLogsHashes: Tuple, - public publicCallRequests: Tuple, + public readonly noteHashes: Tuple, + public readonly nullifiers: Tuple, + public readonly l2ToL1Msgs: Tuple, + public readonly noteEncryptedLogsHashes: Tuple, + public readonly encryptedLogsHashes: Tuple, + public readonly unencryptedLogsHashes: Tuple, + public readonly publicCallRequests: Tuple, ) {} getSize() { From 7529d803e2d838ce287e594e28a3e243966d23d9 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 12 Nov 2024 14:44:04 +0000 Subject: [PATCH 7/7] Ignore auto-generated protocol_contract_data.ts. --- yarn-project/.gitignore | 1 + .../src/protocol_contract_data.ts | 63 ------------------- 2 files changed, 1 insertion(+), 63 deletions(-) delete mode 100644 yarn-project/protocol-contracts/src/protocol_contract_data.ts diff --git a/yarn-project/.gitignore b/yarn-project/.gitignore index eddf5f9fa17..abacb3d21aa 100644 --- a/yarn-project/.gitignore +++ b/yarn-project/.gitignore @@ -41,6 +41,7 @@ noir-protocol-circuits-types/src/types/ ivc-integration/artifacts ivc-integration/src/types/ protocol-contracts/artifacts +protocol-contracts/src/protocol_contract_data.ts scripts/tmp noir-contracts.js/src noir-contracts.js/artifacts/ diff --git a/yarn-project/protocol-contracts/src/protocol_contract_data.ts b/yarn-project/protocol-contracts/src/protocol_contract_data.ts deleted file mode 100644 index 484ae16e204..00000000000 --- a/yarn-project/protocol-contracts/src/protocol_contract_data.ts +++ /dev/null @@ -1,63 +0,0 @@ -// GENERATED FILE - DO NOT EDIT. RUN `yarn generate` or `yarn generate:data` -import { AztecAddress, Fr } from '@aztec/circuits.js'; -import { type ContractArtifact } from '@aztec/foundation/abi'; -import { loadContractArtifact } from '@aztec/types/abi'; -import { type NoirCompiledContract } from '@aztec/types/noir'; - -import AuthRegistryJson from '../artifacts/AuthRegistry.json' assert { type: 'json' }; -import ContractClassRegistererJson from '../artifacts/ContractClassRegisterer.json' assert { type: 'json' }; -import ContractInstanceDeployerJson from '../artifacts/ContractInstanceDeployer.json' assert { type: 'json' }; -import FeeJuiceJson from '../artifacts/FeeJuice.json' assert { type: 'json' }; -import MultiCallEntrypointJson from '../artifacts/MultiCallEntrypoint.json' assert { type: 'json' }; -import RouterJson from '../artifacts/Router.json' assert { type: 'json' }; - -export const protocolContractNames = [ - 'AuthRegistry', - 'ContractInstanceDeployer', - 'ContractClassRegisterer', - 'MultiCallEntrypoint', - 'FeeJuice', - 'Router', -] as const; - -export type ProtocolContractName = (typeof protocolContractNames)[number]; - -export const ProtocolContractArtifact: Record = { - AuthRegistry: loadContractArtifact(AuthRegistryJson as NoirCompiledContract), - ContractInstanceDeployer: loadContractArtifact(ContractInstanceDeployerJson as NoirCompiledContract), - ContractClassRegisterer: loadContractArtifact(ContractClassRegistererJson as NoirCompiledContract), - MultiCallEntrypoint: loadContractArtifact(MultiCallEntrypointJson as NoirCompiledContract), - FeeJuice: loadContractArtifact(FeeJuiceJson as NoirCompiledContract), - Router: loadContractArtifact(RouterJson as NoirCompiledContract), -}; - -export const ProtocolContractSalt: Record = { - AuthRegistry: new Fr(1), - ContractInstanceDeployer: new Fr(1), - ContractClassRegisterer: new Fr(1), - MultiCallEntrypoint: new Fr(1), - FeeJuice: new Fr(1), - Router: new Fr(1), -}; - -export const ProtocolContractAddress: Record = { - AuthRegistry: AztecAddress.fromBigInt(1n), - ContractInstanceDeployer: AztecAddress.fromBigInt(2n), - ContractClassRegisterer: AztecAddress.fromBigInt(3n), - MultiCallEntrypoint: AztecAddress.fromBigInt(4n), - FeeJuice: AztecAddress.fromBigInt(5n), - Router: AztecAddress.fromBigInt(6n), -}; - -export const ProtocolContractLeaf = { - AuthRegistry: Fr.fromString('0x0931f3bf89563f3898ae9650851083cd560ad800c2e3c561c3853eec4dd7ea8b'), - ContractInstanceDeployer: Fr.fromString('0x266ea4c9917455daa905c1dd1a10753714c6d0369b6f2fe23feeca6de556d164'), - ContractClassRegisterer: Fr.fromString('0x1ccb7a219f72a851089e956d527997b01068d5a28c9ae96b35ebeb45f068af23'), - MultiCallEntrypoint: Fr.fromString('0x1d060217817cf472a579638db722903fd1bbc4c3bdb0ecefa5694c0d4eed851a'), - FeeJuice: Fr.fromString('0x1e47caab3dd90f26b91e14e003a5ceab8d069b654174f6d698cdec9b1a6d19d5'), - Router: Fr.fromString('0x00827d5a8aedb9627d9e5de04735600a4dbb817d4a2f51281aab991699f5de99'), -}; - -export const protocolContractTreeRoot = Fr.fromString( - '0x24df09a860e983bd4e2e63538c62419d9640ae4d2ed77153b104cb8f1a9fd27e', -);