@aztec/stdlib 0.0.1-commit.3100065 → 0.0.1-commit.330febf
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/abi/abi.d.ts +32 -7
- package/dest/abi/abi.d.ts.map +1 -1
- package/dest/abi/abi.js +11 -2
- package/dest/abi/contract_artifact.d.ts +1 -14
- package/dest/abi/contract_artifact.d.ts.map +1 -1
- package/dest/abi/contract_artifact.js +35 -36
- package/dest/abi/decoder.d.ts +12 -5
- package/dest/abi/decoder.d.ts.map +1 -1
- package/dest/abi/decoder.js +18 -21
- package/dest/abi/function_call.d.ts +17 -8
- package/dest/abi/function_call.d.ts.map +1 -1
- package/dest/abi/function_call.js +28 -9
- package/dest/avm/avm.d.ts +212 -211
- package/dest/avm/avm.d.ts.map +1 -1
- package/dest/avm/avm.js +3 -1
- package/dest/avm/index.d.ts +1 -6
- package/dest/avm/index.d.ts.map +1 -1
- package/dest/avm/index.js +0 -5
- package/dest/block/l2_block_source.d.ts +1 -1
- package/dest/block/l2_block_source.d.ts.map +1 -1
- package/dest/block/l2_block_source.js +6 -2
- package/dest/block/l2_block_stream/interfaces.d.ts +7 -5
- package/dest/block/l2_block_stream/interfaces.d.ts.map +1 -1
- package/dest/block/l2_block_stream/l2_block_stream.d.ts +2 -1
- package/dest/block/l2_block_stream/l2_block_stream.d.ts.map +1 -1
- package/dest/block/l2_block_stream/l2_block_stream.js +47 -20
- package/dest/block/test/l2_tips_store_test_suite.d.ts +1 -1
- package/dest/block/test/l2_tips_store_test_suite.d.ts.map +1 -1
- package/dest/block/test/l2_tips_store_test_suite.js +9 -4
- package/dest/config/node-rpc-config.d.ts +1 -1
- package/dest/config/node-rpc-config.d.ts.map +1 -1
- package/dest/config/node-rpc-config.js +1 -1
- package/dest/contract/artifact_hash.d.ts +2 -2
- package/dest/contract/artifact_hash.d.ts.map +1 -1
- package/dest/contract/artifact_hash.js +10 -2
- package/dest/contract/contract_class.d.ts +1 -1
- package/dest/contract/contract_class.d.ts.map +1 -1
- package/dest/contract/contract_class.js +3 -2
- package/dest/contract/index.d.ts +1 -2
- package/dest/contract/index.d.ts.map +1 -1
- package/dest/contract/index.js +0 -1
- package/dest/interfaces/api_limit.d.ts +6 -1
- package/dest/interfaces/api_limit.d.ts.map +1 -1
- package/dest/interfaces/api_limit.js +3 -0
- package/dest/interfaces/aztec-node-admin.d.ts +2 -1
- package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
- package/dest/interfaces/block-builder.d.ts +7 -2
- package/dest/interfaces/block-builder.d.ts.map +1 -1
- package/dest/interfaces/configs.d.ts +7 -1
- package/dest/interfaces/configs.d.ts.map +1 -1
- package/dest/interfaces/configs.js +1 -0
- package/dest/interfaces/merkle_tree_operations.d.ts +8 -3
- package/dest/interfaces/merkle_tree_operations.d.ts.map +1 -1
- package/dest/interfaces/private_kernel_prover.d.ts +64 -3
- package/dest/interfaces/private_kernel_prover.d.ts.map +1 -1
- package/dest/interfaces/proving-job.d.ts +1 -1
- package/dest/interfaces/server.d.ts +1 -2
- package/dest/interfaces/server.d.ts.map +1 -1
- package/dest/interfaces/server.js +0 -1
- package/dest/interfaces/tx_provider.d.ts +5 -1
- package/dest/interfaces/tx_provider.d.ts.map +1 -1
- package/dest/kernel/hints/index.d.ts +1 -2
- package/dest/kernel/hints/index.d.ts.map +1 -1
- package/dest/kernel/hints/index.js +0 -1
- package/dest/kernel/index.d.ts +5 -1
- package/dest/kernel/index.d.ts.map +1 -1
- package/dest/kernel/index.js +4 -0
- package/dest/kernel/private_kernel_circuit_public_inputs.d.ts +1 -9
- package/dest/kernel/private_kernel_circuit_public_inputs.d.ts.map +1 -1
- package/dest/kernel/private_kernel_circuit_public_inputs.js +3 -7
- package/dest/kernel/private_kernel_init_4_circuit_private_inputs.d.ts +24 -0
- package/dest/kernel/private_kernel_init_4_circuit_private_inputs.d.ts.map +1 -0
- package/dest/kernel/private_kernel_init_4_circuit_private_inputs.js +37 -0
- package/dest/kernel/private_kernel_init_5_circuit_private_inputs.d.ts +25 -0
- package/dest/kernel/private_kernel_init_5_circuit_private_inputs.d.ts.map +1 -0
- package/dest/kernel/private_kernel_init_5_circuit_private_inputs.js +39 -0
- package/dest/kernel/private_kernel_inner_4_circuit_private_inputs.d.ts +18 -0
- package/dest/kernel/private_kernel_inner_4_circuit_private_inputs.d.ts.map +1 -0
- package/dest/kernel/private_kernel_inner_4_circuit_private_inputs.js +27 -0
- package/dest/kernel/private_kernel_inner_5_circuit_private_inputs.d.ts +19 -0
- package/dest/kernel/private_kernel_inner_5_circuit_private_inputs.d.ts.map +1 -0
- package/dest/kernel/private_kernel_inner_5_circuit_private_inputs.js +29 -0
- package/dest/kernel/private_kernel_prover_output.d.ts +4 -1
- package/dest/kernel/private_kernel_prover_output.d.ts.map +1 -1
- package/dest/kernel/private_kernel_prover_output.js +4 -1
- package/dest/kernel/private_kernel_simulated_output.d.ts +1 -7
- package/dest/kernel/private_kernel_simulated_output.d.ts.map +1 -1
- package/dest/kernel/private_kernel_simulated_output.js +2 -1
- package/dest/kernel/utils/index.d.ts +1 -2
- package/dest/kernel/utils/index.d.ts.map +1 -1
- package/dest/kernel/utils/index.js +0 -1
- package/dest/logs/index.d.ts +3 -1
- package/dest/logs/index.d.ts.map +1 -1
- package/dest/logs/index.js +2 -0
- package/dest/logs/logs_query.d.ts +2 -2
- package/dest/logs/message_context.d.ts +17 -0
- package/dest/logs/message_context.d.ts.map +1 -0
- package/dest/logs/message_context.js +9 -0
- package/dest/logs/pending_tagged_log.d.ts +11 -0
- package/dest/logs/pending_tagged_log.d.ts.map +1 -0
- package/dest/logs/pending_tagged_log.js +4 -0
- package/dest/logs/shared_secret_derivation.d.ts +12 -2
- package/dest/logs/shared_secret_derivation.d.ts.map +1 -1
- package/dest/logs/shared_secret_derivation.js +18 -0
- package/dest/noir/index.d.ts +3 -3
- package/dest/noir/index.d.ts.map +1 -1
- package/dest/p2p/index.d.ts +1 -2
- package/dest/p2p/index.d.ts.map +1 -1
- package/dest/p2p/index.js +0 -1
- package/dest/stats/stats.d.ts +2 -2
- package/dest/stats/stats.d.ts.map +1 -1
- package/dest/tests/factories.d.ts +1 -27
- package/dest/tests/factories.d.ts.map +1 -1
- package/dest/tests/factories.js +0 -30
- package/dest/tx/hashed_values.d.ts +7 -1
- package/dest/tx/hashed_values.d.ts.map +1 -1
- package/dest/tx/hashed_values.js +9 -1
- package/dest/tx/index.d.ts +1 -2
- package/dest/tx/index.d.ts.map +1 -1
- package/dest/tx/index.js +0 -1
- package/dest/tx/offchain_effect.js +1 -1
- package/dest/tx/profiling.d.ts +1 -1
- package/dest/tx/profiling.d.ts.map +1 -1
- package/dest/tx/profiling.js +2 -0
- package/dest/tx/simulated_tx.d.ts +1 -1
- package/dest/tx/simulated_tx.d.ts.map +1 -1
- package/dest/tx/simulated_tx.js +7 -2
- package/dest/tx/tx.d.ts +8 -1
- package/dest/tx/tx.d.ts.map +1 -1
- package/dest/tx/tx.js +9 -3
- package/dest/validators/errors.d.ts +16 -1
- package/dest/validators/errors.d.ts.map +1 -1
- package/dest/validators/errors.js +12 -0
- package/dest/world-state/world_state_revision.d.ts +1 -18
- package/dest/world-state/world_state_revision.d.ts.map +1 -1
- package/dest/world-state/world_state_revision.js +0 -20
- package/package.json +8 -8
- package/src/abi/abi.ts +32 -4
- package/src/abi/contract_artifact.ts +40 -35
- package/src/abi/decoder.ts +20 -24
- package/src/abi/function_call.ts +19 -7
- package/src/avm/avm.ts +4 -1
- package/src/avm/index.ts +0 -5
- package/src/block/l2_block_source.ts +14 -2
- package/src/block/l2_block_stream/interfaces.ts +6 -4
- package/src/block/l2_block_stream/l2_block_stream.ts +58 -21
- package/src/block/test/l2_tips_store_test_suite.ts +5 -0
- package/src/config/node-rpc-config.ts +2 -1
- package/src/contract/artifact_hash.ts +15 -3
- package/src/contract/contract_class.ts +3 -2
- package/src/contract/index.ts +0 -1
- package/src/gas/README.md +108 -36
- package/src/interfaces/api_limit.ts +5 -0
- package/src/interfaces/block-builder.ts +6 -1
- package/src/interfaces/configs.ts +6 -0
- package/src/interfaces/merkle_tree_operations.ts +8 -2
- package/src/interfaces/private_kernel_prover.ts +94 -1
- package/src/interfaces/server.ts +0 -1
- package/src/interfaces/tx_provider.ts +4 -0
- package/src/kernel/hints/index.ts +0 -1
- package/src/kernel/index.ts +4 -0
- package/src/kernel/private_kernel_circuit_public_inputs.ts +0 -7
- package/src/kernel/private_kernel_init_4_circuit_private_inputs.ts +52 -0
- package/src/kernel/private_kernel_init_5_circuit_private_inputs.ts +55 -0
- package/src/kernel/private_kernel_inner_4_circuit_private_inputs.ts +39 -0
- package/src/kernel/private_kernel_inner_5_circuit_private_inputs.ts +42 -0
- package/src/kernel/private_kernel_prover_output.ts +4 -0
- package/src/kernel/private_kernel_reset_dimensions.ts +1 -1
- package/src/kernel/private_kernel_simulated_output.ts +0 -7
- package/src/kernel/utils/index.ts +0 -1
- package/src/logs/index.ts +2 -0
- package/src/logs/logs_query.ts +2 -2
- package/src/logs/message_context.ts +18 -0
- package/src/logs/pending_tagged_log.ts +12 -0
- package/src/logs/shared_secret_derivation.ts +18 -1
- package/src/noir/index.ts +2 -1
- package/src/p2p/index.ts +0 -1
- package/src/stats/stats.ts +4 -0
- package/src/tests/factories.ts +0 -38
- package/src/tx/hashed_values.ts +11 -6
- package/src/tx/index.ts +0 -1
- package/src/tx/offchain_effect.ts +1 -1
- package/src/tx/profiling.ts +2 -0
- package/src/tx/simulated_tx.ts +13 -2
- package/src/tx/tx.ts +19 -3
- package/src/validators/errors.ts +17 -0
- package/src/world-state/world_state_revision.ts +0 -33
- package/dest/avm/contract_storage_read.d.ts +0 -58
- package/dest/avm/contract_storage_read.d.ts.map +0 -1
- package/dest/avm/contract_storage_read.js +0 -65
- package/dest/avm/contract_storage_update_request.d.ts +0 -65
- package/dest/avm/contract_storage_update_request.d.ts.map +0 -1
- package/dest/avm/contract_storage_update_request.js +0 -80
- package/dest/avm/public_call_stack_item_compressed.d.ts +0 -43
- package/dest/avm/public_call_stack_item_compressed.d.ts.map +0 -1
- package/dest/avm/public_call_stack_item_compressed.js +0 -70
- package/dest/avm/public_data_update_request.d.ts +0 -62
- package/dest/avm/public_data_update_request.d.ts.map +0 -1
- package/dest/avm/public_data_update_request.js +0 -67
- package/dest/avm/public_inner_call_request.d.ts +0 -50
- package/dest/avm/public_inner_call_request.d.ts.map +0 -1
- package/dest/avm/public_inner_call_request.js +0 -74
- package/dest/contract/deployment_info.d.ts +0 -24
- package/dest/contract/deployment_info.d.ts.map +0 -1
- package/dest/contract/deployment_info.js +0 -3
- package/dest/interfaces/prover-coordination.d.ts +0 -15
- package/dest/interfaces/prover-coordination.d.ts.map +0 -1
- package/dest/interfaces/prover-coordination.js +0 -1
- package/dest/kernel/hints/tree_leaf_read_request.d.ts +0 -14
- package/dest/kernel/hints/tree_leaf_read_request.d.ts.map +0 -1
- package/dest/kernel/hints/tree_leaf_read_request.js +0 -33
- package/dest/kernel/utils/optional_number.d.ts +0 -31
- package/dest/kernel/utils/optional_number.d.ts.map +0 -1
- package/dest/kernel/utils/optional_number.js +0 -42
- package/dest/p2p/interface.d.ts +0 -5
- package/dest/p2p/interface.d.ts.map +0 -1
- package/dest/p2p/interface.js +0 -1
- package/dest/tx/validator/empty_validator.d.ts +0 -5
- package/dest/tx/validator/empty_validator.d.ts.map +0 -1
- package/dest/tx/validator/empty_validator.js +0 -7
- package/src/avm/contract_storage_read.ts +0 -77
- package/src/avm/contract_storage_update_request.ts +0 -93
- package/src/avm/public_call_stack_item_compressed.ts +0 -113
- package/src/avm/public_data_update_request.ts +0 -106
- package/src/avm/public_inner_call_request.ts +0 -85
- package/src/contract/deployment_info.ts +0 -25
- package/src/interfaces/prover-coordination.ts +0 -17
- package/src/kernel/hints/tree_leaf_read_request.ts +0 -35
- package/src/kernel/utils/optional_number.ts +0 -50
- package/src/p2p/interface.ts +0 -4
- package/src/tx/validator/empty_validator.ts +0 -7
package/src/abi/function_call.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { z } from 'zod';
|
|
|
5
5
|
|
|
6
6
|
import { AztecAddress } from '../aztec-address/index.js';
|
|
7
7
|
import { schemas } from '../schemas/index.js';
|
|
8
|
-
import { type AbiType, AbiTypeSchema, FunctionType } from './abi.js';
|
|
8
|
+
import { type AbiType, AbiTypeSchema, FunctionType, getFunctionReturnType } from './abi.js';
|
|
9
9
|
import { FunctionSelector } from './function_selector.js';
|
|
10
10
|
|
|
11
11
|
/** A request to call a function on a contract. */
|
|
@@ -25,8 +25,8 @@ export class FunctionCall {
|
|
|
25
25
|
public isStatic: boolean,
|
|
26
26
|
/** The encoded args */
|
|
27
27
|
public args: Fr[],
|
|
28
|
-
/** The
|
|
29
|
-
public
|
|
28
|
+
/** The type the call returns, for decoding, or undefined if it returns nothing */
|
|
29
|
+
public returnType?: AbiType,
|
|
30
30
|
) {}
|
|
31
31
|
|
|
32
32
|
static getFields(fields: FieldsOf<FunctionCall>) {
|
|
@@ -38,7 +38,7 @@ export class FunctionCall {
|
|
|
38
38
|
fields.hideMsgSender,
|
|
39
39
|
fields.isStatic,
|
|
40
40
|
fields.args,
|
|
41
|
-
fields.
|
|
41
|
+
fields.returnType,
|
|
42
42
|
] as const;
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -56,9 +56,22 @@ export class FunctionCall {
|
|
|
56
56
|
isStatic: z.boolean(),
|
|
57
57
|
hideMsgSender: z.boolean(),
|
|
58
58
|
args: z.array(schemas.Fr),
|
|
59
|
-
|
|
59
|
+
returnType: AbiTypeSchema.optional(),
|
|
60
|
+
// Old consumers send `returnTypes`, not `returnType`. So we accept both for now, until we can safely remove
|
|
61
|
+
// the old version.
|
|
62
|
+
returnTypes: z.array(AbiTypeSchema).optional(),
|
|
60
63
|
})
|
|
61
|
-
.transform(
|
|
64
|
+
.transform(({ returnType, returnTypes, ...fields }) =>
|
|
65
|
+
FunctionCall.from({ ...fields, returnType: getFunctionReturnType({ returnType, returnTypes }) }),
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Serializes the deprecated `returnTypes` alongside `returnType`, so that peers that still require the old field can
|
|
71
|
+
* parse calls sent by this version.
|
|
72
|
+
*/
|
|
73
|
+
public toJSON() {
|
|
74
|
+
return { ...this, returnTypes: this.returnType ? [this.returnType] : [] };
|
|
62
75
|
}
|
|
63
76
|
|
|
64
77
|
public isPublicStatic(): boolean {
|
|
@@ -78,7 +91,6 @@ export class FunctionCall {
|
|
|
78
91
|
hideMsgSender: false,
|
|
79
92
|
isStatic: false,
|
|
80
93
|
args: [],
|
|
81
|
-
returnTypes: [],
|
|
82
94
|
});
|
|
83
95
|
}
|
|
84
96
|
}
|
package/src/avm/avm.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { DEFAULT_MAX_DEBUG_LOG_MEMORY_READS } from '@aztec/constants';
|
|
2
1
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
2
|
import { jsonParseWithSchema, jsonStringify } from '@aztec/foundation/json-rpc';
|
|
4
3
|
|
|
@@ -1384,6 +1383,10 @@ export class PublicTxResult {
|
|
|
1384
1383
|
}
|
|
1385
1384
|
}
|
|
1386
1385
|
|
|
1386
|
+
// Excessive memory reads due to debug logging can open a DOS vector to nodes that perform public tx simulation for users.
|
|
1387
|
+
// This default limit (4MB) can be configured further by node runners via the `RPC_SIMULATE_PUBLIC_MAX_DEBUG_LOG_MEMORY_READS` environment variable.
|
|
1388
|
+
export const DEFAULT_MAX_DEBUG_LOG_MEMORY_READS = 125000;
|
|
1389
|
+
|
|
1387
1390
|
export class CollectionLimitsConfig {
|
|
1388
1391
|
constructor(
|
|
1389
1392
|
public readonly maxDebugLogMemoryReads: number,
|
package/src/avm/index.ts
CHANGED
|
@@ -3,10 +3,5 @@ export * from './avm_accumulated_data.js';
|
|
|
3
3
|
export * from './avm_circuit_public_inputs.js';
|
|
4
4
|
export * from './revert_code.js';
|
|
5
5
|
export * from './public_data_write.js';
|
|
6
|
-
export * from './public_data_update_request.js';
|
|
7
|
-
export * from './contract_storage_update_request.js';
|
|
8
|
-
export * from './contract_storage_read.js';
|
|
9
|
-
export * from './public_inner_call_request.js';
|
|
10
|
-
export * from './public_call_stack_item_compressed.js';
|
|
11
6
|
export * from './avm_proving_request.js';
|
|
12
7
|
export * from './message_pack.js';
|
|
@@ -19,6 +19,7 @@ import type { CheckpointData, ProposedCheckpointData, ProposedCheckpointInput }
|
|
|
19
19
|
import type { CheckpointInfo } from '../checkpoint/checkpoint_info.js';
|
|
20
20
|
import type { PublishedCheckpoint } from '../checkpoint/published_checkpoint.js';
|
|
21
21
|
import type { L1RollupConstants } from '../epoch-helpers/index.js';
|
|
22
|
+
import { MAX_RPC_CHECKPOINTS_DATA_LEN } from '../interfaces/api_limit.js';
|
|
22
23
|
import type { L2ToL1MembershipWitness } from '../messaging/l2_to_l1_membership.js';
|
|
23
24
|
import { CheckpointHeader } from '../rollup/checkpoint_header.js';
|
|
24
25
|
import type { IndexedTxEffect } from '../tx/indexed_tx_effect.js';
|
|
@@ -89,9 +90,20 @@ export const CheckpointQuerySchema: z.ZodType<CheckpointQuery, unknown> = z.unio
|
|
|
89
90
|
z.object({ tag: z.union([z.literal('checkpointed'), z.literal('proven'), z.literal('finalized')]) }).strict(),
|
|
90
91
|
]);
|
|
91
92
|
|
|
93
|
+
const checkpointsQueryLimitSchema = () =>
|
|
94
|
+
z
|
|
95
|
+
.number()
|
|
96
|
+
.int()
|
|
97
|
+
.min(1)
|
|
98
|
+
.max(MAX_RPC_CHECKPOINTS_DATA_LEN, {
|
|
99
|
+
message: `limit must be at most ${MAX_RPC_CHECKPOINTS_DATA_LEN}`,
|
|
100
|
+
});
|
|
101
|
+
|
|
92
102
|
export const CheckpointsQuerySchema: z.ZodType<CheckpointsQuery, unknown> = z.union([
|
|
93
|
-
z.object({ from: CheckpointNumberSchema, limit:
|
|
94
|
-
z
|
|
103
|
+
z.object({ from: CheckpointNumberSchema, limit: checkpointsQueryLimitSchema() }).strict(),
|
|
104
|
+
z
|
|
105
|
+
.object({ fromSlot: SlotNumberSchema, limit: checkpointsQueryLimitSchema(), reverse: z.boolean().optional() })
|
|
106
|
+
.strict(),
|
|
95
107
|
z.object({ epoch: EpochNumberSchema }).strict(),
|
|
96
108
|
]);
|
|
97
109
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
2
|
|
|
3
|
+
import type { BlockHeader } from '../../tx/block_header.js';
|
|
3
4
|
import type { L2Block } from '../l2_block.js';
|
|
4
5
|
import type { CheckpointId, L2BlockId, L2TipId, L2Tips, LocalL2Tips } from '../l2_block_source.js';
|
|
5
6
|
|
|
@@ -81,13 +82,14 @@ export type L2BlockStreamEvent =
|
|
|
81
82
|
}
|
|
82
83
|
| /**
|
|
83
84
|
* Reports the new proposed tip of the chain. Emitted once per sync pass when the source's proposed tip differs
|
|
84
|
-
* from the pre-pass local one (downloads, a prune, or a thin tip movement).
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
85
|
+
* from the pre-pass local one (downloads, a prune, or a thin tip movement). In block mode the corresponding
|
|
86
|
+
* payloads also arrive via preceding `blocks-added` events, while in tips-only mode this is the sole signal that
|
|
87
|
+
* the proposed tip moved. Consumers that only track the proposed tip can ignore `blocks-added` entirely and
|
|
88
|
+
* anchor on this event instead.
|
|
88
89
|
*/ {
|
|
89
90
|
type: 'chain-proposed';
|
|
90
91
|
block: L2BlockId;
|
|
92
|
+
header: BlockHeader;
|
|
91
93
|
}
|
|
92
94
|
| /**
|
|
93
95
|
* Reports a new checkpointed tip. Emitted at most once per sync pass when the source's checkpointed tip
|
|
@@ -3,6 +3,8 @@ import { AbortError } from '@aztec/foundation/error';
|
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
5
5
|
|
|
6
|
+
import type { BlockHeader } from '../../tx/block_header.js';
|
|
7
|
+
import { BlockHash } from '../block_hash.js';
|
|
6
8
|
import type { L2Block } from '../l2_block.js';
|
|
7
9
|
import { type L2BlockId, type L2BlockSource, type LocalL2Tips, makeL2BlockId } from '../l2_block_source.js';
|
|
8
10
|
import {
|
|
@@ -100,6 +102,13 @@ export class L2BlockStream {
|
|
|
100
102
|
// Baseline for the chain-proposed event; captured before the local store mutates during the pass.
|
|
101
103
|
const prePassProposed = localTips.proposed;
|
|
102
104
|
|
|
105
|
+
// In tips-only mode there is no download loop to supply the chain-proposed event's header, so it must be
|
|
106
|
+
// fetched. Start the read now so it runs in parallel with the walk-back below.
|
|
107
|
+
const prefetch: ProposedHeaderPrefetch | undefined =
|
|
108
|
+
this.opts.tipsOnly && localBlockIdDiffers(prePassProposed, sourceTips.proposed)
|
|
109
|
+
? { hash: sourceTips.proposed.hash, header: this.getHeaderFromSource(sourceTips.proposed.hash) }
|
|
110
|
+
: undefined;
|
|
111
|
+
|
|
103
112
|
// Walk back to find a reorg, floored at the local finalized tip (a legitimate reorg can never reach it, since
|
|
104
113
|
// finalized means the proving tx is itself L1-finalized). Seed the cache with ONLY the proposed tip: a stale
|
|
105
114
|
// tier seed at a reorged height equals the local old-fork hash, faking agreement and stopping the walk above the
|
|
@@ -169,17 +178,29 @@ export class L2BlockStream {
|
|
|
169
178
|
}
|
|
170
179
|
|
|
171
180
|
// Pass atomicity: a prune mid-download leaves the source unable to serve the planned blocks, so the snapshot's
|
|
172
|
-
// tier tips may reference blocks the consumer never saw —
|
|
173
|
-
// has no download plan (the snapshot is one atomic getL2Tips read), so it always reconciles.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
181
|
+
// tier tips may reference blocks the consumer never saw — downloadBlocks aborts the pass in that case.
|
|
182
|
+
// Tips-only mode has no download plan (the snapshot is one atomic getL2Tips read), so it always reconciles.
|
|
183
|
+
const deliveredProposedHeader = this.opts.tipsOnly
|
|
184
|
+
? undefined
|
|
185
|
+
: await this.downloadBlocks(latestBlockNumber, sourceTips);
|
|
177
186
|
|
|
178
187
|
// End-of-pass reconciliation: chain-proposed fires against the pre-pass baseline (a post-prune re-read would
|
|
179
188
|
// equal the source tip and suppress it), then the tiers highest-to-lowest so the finalized <= proven <=
|
|
180
189
|
// checkpointed <= proposed invariant holds mid-pass.
|
|
181
190
|
if (localBlockIdDiffers(prePassProposed, sourceTips.proposed)) {
|
|
182
|
-
|
|
191
|
+
const availableHeader =
|
|
192
|
+
prefetch?.hash === sourceTips.proposed.hash ? await prefetch.header : deliveredProposedHeader;
|
|
193
|
+
const header = availableHeader ?? (await this.getHeaderFromSource(sourceTips.proposed.hash));
|
|
194
|
+
if (header === undefined) {
|
|
195
|
+
// Abort the pass rather than skip just this event: the later tier events must not get ahead of a
|
|
196
|
+
// proposed tip the consumer never received. Nothing advanced, so the next pass retries.
|
|
197
|
+
this.log.warn(`No header for the proposed tip; aborting this sync pass`, {
|
|
198
|
+
blockNumber: sourceTips.proposed.number,
|
|
199
|
+
blockHash: sourceTips.proposed.hash,
|
|
200
|
+
});
|
|
201
|
+
throw new AbortError();
|
|
202
|
+
}
|
|
203
|
+
await this.emitEvent({ type: 'chain-proposed', block: sourceTips.proposed, header });
|
|
183
204
|
}
|
|
184
205
|
|
|
185
206
|
const reconcileTips = pruned ? await this.localData.getL2Tips() : localTips;
|
|
@@ -222,13 +243,15 @@ export class L2BlockStream {
|
|
|
222
243
|
}
|
|
223
244
|
|
|
224
245
|
/**
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* the
|
|
228
|
-
*
|
|
229
|
-
* the source no longer has a promised block, or served a fork at the proposed height mid-pass.
|
|
246
|
+
* Delivers every block from the agreed-on point through the advertised proposed tip as `blocks-added` events,
|
|
247
|
+
* aborting the pass when the source's own answers prove that tip is no longer real.
|
|
248
|
+
* @returns The delivered tip's header, so the caller can avoid a re-fetch; undefined when there was nothing to
|
|
249
|
+
* download (already at the tip, or startingBlock past it).
|
|
230
250
|
*/
|
|
231
|
-
private async downloadBlocks(
|
|
251
|
+
private async downloadBlocks(
|
|
252
|
+
latestBlockNumber: BlockNumber,
|
|
253
|
+
sourceTips: LocalL2Tips,
|
|
254
|
+
): Promise<BlockHeader | undefined> {
|
|
232
255
|
// The post-prune cursor: the highest block number both sides agree on. Block downloads resume from here.
|
|
233
256
|
let nextBlockNumber = latestBlockNumber + 1;
|
|
234
257
|
|
|
@@ -258,12 +281,12 @@ export class L2BlockStream {
|
|
|
258
281
|
if (blocks.length === 0) {
|
|
259
282
|
// The source no longer has a block the snapshot promised: the snapshot is provably stale, so report the plan
|
|
260
283
|
// incomplete and skip reconciliation this pass.
|
|
261
|
-
this.log.warn(`Block source returned no blocks for a promised range;
|
|
284
|
+
this.log.warn(`Block source returned no blocks for a promised range; aborting this sync pass`, {
|
|
262
285
|
from: nextBlockNumber,
|
|
263
286
|
limit,
|
|
264
287
|
sourceProposed: sourceTips.proposed.number,
|
|
265
288
|
});
|
|
266
|
-
|
|
289
|
+
throw new AbortError();
|
|
267
290
|
}
|
|
268
291
|
await this.emitEvent({ type: 'blocks-added', blocks });
|
|
269
292
|
lastDeliveredBlock = blocks.at(-1)!;
|
|
@@ -271,22 +294,23 @@ export class L2BlockStream {
|
|
|
271
294
|
}
|
|
272
295
|
|
|
273
296
|
if (lastDeliveredBlock === undefined) {
|
|
274
|
-
// Loop never ran
|
|
275
|
-
|
|
297
|
+
// Loop never ran (caught up before the plan started, or startingBlock past the tip, see A-1061), so nothing
|
|
298
|
+
// was downloaded that could disprove the snapshot.
|
|
299
|
+
return undefined;
|
|
276
300
|
}
|
|
277
301
|
|
|
278
|
-
//
|
|
279
|
-
//
|
|
302
|
+
// The block delivered at the proposed height must carry the snapshot's proposed hash; a different hash means a
|
|
303
|
+
// same-height fork swap happened mid-pass, so the snapshot is stale.
|
|
280
304
|
const deliveredHash = (await lastDeliveredBlock.hash()).toString();
|
|
281
305
|
if (deliveredHash !== sourceTips.proposed.hash) {
|
|
282
|
-
this.log.warn(`Delivered proposed-block hash differs from snapshot;
|
|
306
|
+
this.log.warn(`Delivered proposed-block hash differs from snapshot; aborting this sync pass`, {
|
|
283
307
|
blockNumber: lastDeliveredBlock.number,
|
|
284
308
|
deliveredHash,
|
|
285
309
|
snapshotHash: sourceTips.proposed.hash,
|
|
286
310
|
});
|
|
287
|
-
|
|
311
|
+
throw new AbortError();
|
|
288
312
|
}
|
|
289
|
-
return
|
|
313
|
+
return lastDeliveredBlock.header;
|
|
290
314
|
}
|
|
291
315
|
|
|
292
316
|
/**
|
|
@@ -342,6 +366,16 @@ export class L2BlockStream {
|
|
|
342
366
|
.then(hash => hash?.toString());
|
|
343
367
|
}
|
|
344
368
|
|
|
369
|
+
private getHeaderFromSource(hash: string): Promise<BlockHeader | undefined> {
|
|
370
|
+
return this.l2BlockSource
|
|
371
|
+
.getBlockData({ hash: BlockHash.fromString(hash) })
|
|
372
|
+
.then(data => data?.header)
|
|
373
|
+
.catch(err => {
|
|
374
|
+
this.log.error(`Failed to read header for block`, err, { blockHash: hash });
|
|
375
|
+
return undefined;
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
345
379
|
private async emitEvent(event: L2BlockStreamEvent) {
|
|
346
380
|
this.log.debug(
|
|
347
381
|
`Emitting ${event.type} (${
|
|
@@ -359,6 +393,9 @@ export class L2BlockStream {
|
|
|
359
393
|
}
|
|
360
394
|
}
|
|
361
395
|
|
|
396
|
+
/** A speculative proposed-tip header read, tagged with the hash it targets so a moved tip is detectable. */
|
|
397
|
+
type ProposedHeaderPrefetch = { hash: string; header: Promise<BlockHeader | undefined> };
|
|
398
|
+
|
|
362
399
|
class BlockHashCache {
|
|
363
400
|
private readonly cache: Map<number, string> = new Map();
|
|
364
401
|
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type L2TipId,
|
|
11
11
|
} from '@aztec/stdlib/block';
|
|
12
12
|
import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
13
|
+
import { BlockHeader } from '@aztec/stdlib/tx';
|
|
13
14
|
|
|
14
15
|
import { expect } from 'vitest';
|
|
15
16
|
|
|
@@ -132,6 +133,7 @@ export function testL2TipsStore(makeTipsStore: () => Promise<L2TipsStore>) {
|
|
|
132
133
|
await tipsStore.handleBlockStreamEvent({
|
|
133
134
|
type: 'chain-proposed',
|
|
134
135
|
block: { number: BlockNumber(5), hash: new Fr(500).toString() },
|
|
136
|
+
header: BlockHeader.empty(),
|
|
135
137
|
});
|
|
136
138
|
|
|
137
139
|
const tips = await tipsStore.getL2Tips();
|
|
@@ -145,10 +147,12 @@ export function testL2TipsStore(makeTipsStore: () => Promise<L2TipsStore>) {
|
|
|
145
147
|
await tipsStore.handleBlockStreamEvent({
|
|
146
148
|
type: 'chain-proposed',
|
|
147
149
|
block: { number: BlockNumber(4), hash: new Fr(400).toString() },
|
|
150
|
+
header: BlockHeader.empty(),
|
|
148
151
|
});
|
|
149
152
|
await tipsStore.handleBlockStreamEvent({
|
|
150
153
|
type: 'chain-proposed',
|
|
151
154
|
block: { number: BlockNumber(9), hash: new Fr(900).toString() },
|
|
155
|
+
header: BlockHeader.empty(),
|
|
152
156
|
});
|
|
153
157
|
|
|
154
158
|
// Both recorded heights resolve; the heights between them were never seen and stay undefined.
|
|
@@ -165,6 +169,7 @@ export function testL2TipsStore(makeTipsStore: () => Promise<L2TipsStore>) {
|
|
|
165
169
|
await tipsStore.handleBlockStreamEvent({
|
|
166
170
|
type: 'chain-proposed',
|
|
167
171
|
block: { number: BlockNumber(9), hash: new Fr(900).toString() },
|
|
172
|
+
header: BlockHeader.empty(),
|
|
168
173
|
});
|
|
169
174
|
|
|
170
175
|
// Record sparse witnesses at heights below the tip (e.g. a consumer materializing per-height state).
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { DEFAULT_MAX_DEBUG_LOG_MEMORY_READS } from '@aztec/constants';
|
|
2
1
|
import { type ConfigMappingsType, numberConfigHelper } from '@aztec/foundation/config';
|
|
3
2
|
|
|
3
|
+
import { DEFAULT_MAX_DEBUG_LOG_MEMORY_READS } from '../avm/avm.js';
|
|
4
|
+
|
|
4
5
|
export const nodeRpcConfigMappings: ConfigMappingsType<NodeRPCConfig> = {
|
|
5
6
|
rpcSimulatePublicMaxGasLimit: {
|
|
6
7
|
env: 'RPC_SIMULATE_PUBLIC_MAX_GAS_LIMIT',
|
|
@@ -6,7 +6,13 @@ import { MerkleTree, MerkleTreeCalculator } from '@aztec/foundation/trees';
|
|
|
6
6
|
|
|
7
7
|
import deterministicStringify from 'json-stringify-deterministic';
|
|
8
8
|
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
type ContractArtifact,
|
|
11
|
+
type FunctionArtifact,
|
|
12
|
+
FunctionSelector,
|
|
13
|
+
FunctionType,
|
|
14
|
+
getFunctionReturnType,
|
|
15
|
+
} from '../abi/index.js';
|
|
10
16
|
|
|
11
17
|
const VERSION = 1;
|
|
12
18
|
|
|
@@ -104,8 +110,14 @@ export async function computeFunctionArtifactHash(
|
|
|
104
110
|
return sha256Fr(Buffer.concat([numToUInt8(VERSION), selector.toBuffer(), metadataHash.toBuffer(), bytecodeHash]));
|
|
105
111
|
}
|
|
106
112
|
|
|
107
|
-
export function computeFunctionMetadataHash(fn: FunctionArtifact) {
|
|
108
|
-
|
|
113
|
+
export function computeFunctionMetadataHash(fn: Pick<FunctionArtifact, 'returnType' | 'returnTypes'>) {
|
|
114
|
+
// Wrap the type in a list (empty when the function returns nothing) so the hash preimage is identical to
|
|
115
|
+
// what it was when this hash consumed the deprecated `returnTypes` list. This hash is part of the
|
|
116
|
+
// artifact hash preimage, which contract class ids commit to - changing it would move the computed
|
|
117
|
+
// class id and address of every contract, and break artifact validation against already-registered
|
|
118
|
+
// classes.
|
|
119
|
+
const returnType = getFunctionReturnType(fn);
|
|
120
|
+
return sha256Fr(Buffer.from(deterministicStringify(returnType ? [returnType] : []), 'utf8'));
|
|
109
121
|
}
|
|
110
122
|
|
|
111
123
|
function getLogger() {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CircuitKind } from '@aztec/bb.js';
|
|
2
|
+
import { vkAsFields } from '@aztec/foundation/crypto/keys';
|
|
2
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
4
|
|
|
4
5
|
import { type ContractArtifact, type FunctionArtifact, FunctionSelector, FunctionType } from '../abi/index.js';
|
|
@@ -60,5 +61,5 @@ export async function computeVerificationKeyHash(f: FunctionArtifact) {
|
|
|
60
61
|
if (!f.verificationKey) {
|
|
61
62
|
throw new Error(`Private function ${f.name} must have a verification key`);
|
|
62
63
|
}
|
|
63
|
-
return hashVK(await
|
|
64
|
+
return hashVK(await vkAsFields(Buffer.from(f.verificationKey, 'base64'), CircuitKind.App));
|
|
64
65
|
}
|
package/src/contract/index.ts
CHANGED
package/src/gas/README.md
CHANGED
|
@@ -1,47 +1,69 @@
|
|
|
1
1
|
# Aztec Gas and Fee Model
|
|
2
2
|
|
|
3
3
|
The minimum fee per mana and its components are computed on L1 in
|
|
4
|
-
`l1-contracts/src/core/libraries/rollup/FeeLib.sol
|
|
5
|
-
|
|
4
|
+
`l1-contracts/src/core/libraries/rollup/FeeLib.sol` (`fee_math.ts` in this directory is a
|
|
5
|
+
TypeScript port of those formulas, used to predict fees a few slots ahead). This document
|
|
6
|
+
describes the formulas, the oracle lag/lifetime mechanism, how a transaction's fee is
|
|
7
|
+
derived from them, the gas and data limits, and the TypeScript types in this directory.
|
|
6
8
|
|
|
7
9
|
## Mana
|
|
8
10
|
|
|
9
|
-
Aztec
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
Aztec meters work as gas in two dimensions: **DA** (data availability, i.e. blob data
|
|
12
|
+
published to L1) and **L2** (execution). The L2 dimension is called **mana** (analogous to
|
|
13
|
+
Ethereum gas): block headers track `totalManaUsed`, and the fee model below prices one unit
|
|
14
|
+
of mana. The total fee is `gasUsed * feePerGas` summed across both dimensions.
|
|
15
|
+
|
|
16
|
+
### The DA dimension is priced at zero
|
|
17
|
+
|
|
18
|
+
Only the L2 dimension currently carries a price. When building checkpoint global variables,
|
|
19
|
+
the sequencer sets `feePerDaGas = 0` and sets `feePerL2Gas` to the L1-computed minimum fee
|
|
20
|
+
per mana (`sequencer-client/src/global_variable_builder/global_builder.ts` and
|
|
21
|
+
`fee_provider.ts` in the same directory). The cost of publishing data is still recovered:
|
|
22
|
+
the blob gas a checkpoint pays on L1 is part of the *sequencer cost* component of the mana
|
|
23
|
+
fee below. DA gas remains fully metered and limited (see
|
|
24
|
+
[Gas and Data Limits](#gas-and-data-limits)) — it bounds how much data a tx or checkpoint
|
|
25
|
+
may publish — it just contributes nothing to the fee today.
|
|
12
26
|
|
|
13
27
|
## Fee Components
|
|
14
28
|
|
|
15
|
-
The minimum fee per mana has four components
|
|
29
|
+
The minimum fee per mana has four components. All are computed in ETH (wei) per mana and
|
|
30
|
+
converted to the fee asset at the end (see [Fee Asset Price](#fee-asset-price)).
|
|
16
31
|
|
|
17
32
|
### Sequencer Cost
|
|
18
33
|
|
|
19
34
|
L1 cost to propose a checkpoint (calldata gas + blob data), amortized over `manaTarget`:
|
|
20
35
|
|
|
21
36
|
```
|
|
22
|
-
sequencerCost = ((L1_GAS_PER_CHECKPOINT_PROPOSED * baseFee)
|
|
37
|
+
sequencerCost = ceil(((L1_GAS_PER_CHECKPOINT_PROPOSED * baseFee)
|
|
23
38
|
+ (BLOBS_PER_CHECKPOINT * BLOB_GAS_PER_BLOB * blobFee))
|
|
24
|
-
/ manaTarget
|
|
39
|
+
/ manaTarget)
|
|
25
40
|
```
|
|
26
41
|
|
|
42
|
+
Note that `BLOBS_PER_CHECKPOINT` here is FeeLib's own constant (3), not the protocol blob
|
|
43
|
+
capacity of the same name (6) — see the note under [Key Constants](#key-constants).
|
|
44
|
+
|
|
27
45
|
### Prover Cost
|
|
28
46
|
|
|
29
47
|
L1 cost to verify an epoch proof, amortized over epoch duration and `manaTarget`, plus a
|
|
30
48
|
governance-set proving cost that compensates for off-chain proof generation:
|
|
31
49
|
|
|
32
50
|
```
|
|
33
|
-
proverCost = (L1_GAS_PER_EPOCH_VERIFIED * baseFee / epochDuration) / manaTarget
|
|
51
|
+
proverCost = ceil(ceil((L1_GAS_PER_EPOCH_VERIFIED * baseFee) / epochDuration) / manaTarget)
|
|
34
52
|
+ provingCostPerMana
|
|
35
53
|
```
|
|
36
54
|
|
|
55
|
+
Updates to `provingCostPerMana` are rate-limited on L1 (`FeeLib.updateProvingCostPerMana`):
|
|
56
|
+
at most one update every 30 days, each moving the value by at most ×1.5 (or ÷1.5), with a
|
|
57
|
+
floor of 2 wei per mana.
|
|
58
|
+
|
|
37
59
|
### Congestion Cost
|
|
38
60
|
|
|
39
61
|
An exponential surcharge when the network is congested (inspired by EIP-1559; the
|
|
40
62
|
implementation uses the `fakeExponential` Taylor series approximation from EIP-4844):
|
|
41
63
|
|
|
42
64
|
```
|
|
43
|
-
baseCost
|
|
44
|
-
congestionCost
|
|
65
|
+
baseCost = sequencerCost + proverCost
|
|
66
|
+
congestionCost = floor(baseCost * congestionMultiplier / MINIMUM_CONGESTION_MULTIPLIER) - baseCost
|
|
45
67
|
```
|
|
46
68
|
|
|
47
69
|
When there is no congestion the multiplier equals `MINIMUM_CONGESTION_MULTIPLIER` (1e9)
|
|
@@ -50,11 +72,15 @@ and congestion cost is zero.
|
|
|
50
72
|
### Congestion Multiplier
|
|
51
73
|
|
|
52
74
|
```
|
|
53
|
-
excessMana
|
|
54
|
-
|
|
75
|
+
excessMana = max(0, prevExcessMana + prevManaUsed - manaTarget)
|
|
76
|
+
denominator = manaTarget * 854,700,854 / 1e8 ≈ 8.547 * manaTarget
|
|
77
|
+
congestionMultiplier = fakeExponential(MINIMUM_CONGESTION_MULTIPLIER,
|
|
78
|
+
min(excessMana, 100 * denominator), denominator)
|
|
55
79
|
```
|
|
56
80
|
|
|
57
|
-
Each additional `manaTarget` of excess mana
|
|
81
|
+
Each additional `manaTarget` of excess mana multiplies the fee by `e^(1/8.547) ≈ 1.124`,
|
|
82
|
+
i.e. ~12.5%. The exponent is capped at 100 (multiplier ≤ ~2.7e43 × the minimum) to keep
|
|
83
|
+
the Taylor series from overflowing.
|
|
58
84
|
|
|
59
85
|
### Total
|
|
60
86
|
|
|
@@ -62,6 +88,11 @@ Each additional `manaTarget` of excess mana increases the multiplier by ~12.5%.
|
|
|
62
88
|
minFeePerMana = sequencerCost + proverCost + congestionCost
|
|
63
89
|
```
|
|
64
90
|
|
|
91
|
+
Each component is converted from ETH to the fee asset individually (rounding up) before
|
|
92
|
+
summing. The sum is capped at `type(uint128).max` (`FeeLib.summedMinFee`) so it always fits
|
|
93
|
+
the proposal header's `feePerL2Gas` field — without the cap, extreme congestion could
|
|
94
|
+
produce a fee no valid header can represent, halting the chain.
|
|
95
|
+
|
|
65
96
|
## L1 Gas Oracle: Lag and Lifetime
|
|
66
97
|
|
|
67
98
|
The oracle feeds Ethereum's `baseFee` and `blobFee` into the fee model using a two-phase
|
|
@@ -70,9 +101,9 @@ The oracle feeds Ethereum's `baseFee` and `blobFee` into the fee model using a t
|
|
|
70
101
|
- **LAG = 2 slots** — when new L1 fees are observed, they activate `LAG` slots later
|
|
71
102
|
(`slotOfChange = currentSlot + LAG`). This gives mempool transactions time to land
|
|
72
103
|
before fees change.
|
|
73
|
-
- **LIFETIME = 5 slots** — after an oracle update,
|
|
74
|
-
`slotOfChange + (LIFETIME - LAG)`
|
|
75
|
-
frequently L1 fee data can change.
|
|
104
|
+
- **LIFETIME = 5 slots** — after an oracle update, further updates are ignored
|
|
105
|
+
(`updateL1GasFeeOracle` returns without effect) until `slotOfChange + (LIFETIME - LAG)`
|
|
106
|
+
= 3 more slots have passed. This rate-limits how frequently L1 fee data can change.
|
|
76
107
|
|
|
77
108
|
Fee resolution at a given timestamp:
|
|
78
109
|
|
|
@@ -84,6 +115,12 @@ else → use post (new fees)
|
|
|
84
115
|
**Net effect**: L1 fee changes reach L2 with a 2-slot delay and can update at most once
|
|
85
116
|
every 5 slots.
|
|
86
117
|
|
|
118
|
+
Because queued values only activate `LAG` slots later, the min fee for the next `LAG`
|
|
119
|
+
slots is fully determined by current on-chain state. `fee_math.ts` ports the FeeLib
|
|
120
|
+
formulas so the sequencer can predict min fees over that window (`FeePredictor` in
|
|
121
|
+
`sequencer-client/src/global_variable_builder`), under a configurable mana-usage
|
|
122
|
+
assumption (`ManaUsageEstimate`: none / target / limit).
|
|
123
|
+
|
|
87
124
|
### Worked Example
|
|
88
125
|
|
|
89
126
|
Suppose the oracle is updated at slot 10 with new L1 fees. Here is the timeline:
|
|
@@ -117,34 +154,68 @@ Key observations:
|
|
|
117
154
|
|
|
118
155
|
## Fee Asset Price
|
|
119
156
|
|
|
120
|
-
Fees are computed in ETH internally
|
|
121
|
-
`ethPerFeeAsset` (1e12 precision)
|
|
122
|
-
|
|
157
|
+
Fees are computed in ETH (wei) internally and converted to the fee asset (Fee Juice) via
|
|
158
|
+
`ethPerFeeAsset` (1e12 precision), rounding up (`PriceLib.toFeeAsset` in
|
|
159
|
+
`l1-contracts/src/core/libraries/compressed-data/fees/FeeConfig.sol`).
|
|
160
|
+
|
|
161
|
+
Each checkpoint proposal carries a fee-asset price modifier (`OracleInput`) chosen by the
|
|
162
|
+
proposer, bounded to ±1% (±100 bps) per checkpoint:
|
|
123
163
|
|
|
124
164
|
```
|
|
125
165
|
newPrice = currentPrice * (10000 + modifierBps) / 10000
|
|
126
166
|
```
|
|
127
167
|
|
|
168
|
+
The result is clamped to [`MIN_ETH_PER_FEE_ASSET` = 100, `MAX_ETH_PER_FEE_ASSET` = 1e14],
|
|
169
|
+
i.e. 1e-10 to 100 ETH per fee asset. The floor of 100 guarantees a ±1% step always moves
|
|
170
|
+
the integer price by at least 1.
|
|
171
|
+
|
|
172
|
+
## Transaction Fees
|
|
173
|
+
|
|
174
|
+
The checkpoint's `gasFees` (the L1-computed min fee per mana, with DA priced at zero) act
|
|
175
|
+
as a base fee. Senders declare `GasSettings`: gas limits, teardown gas limits,
|
|
176
|
+
`maxFeesPerGas`, and `maxPriorityFeesPerGas`. A tx is only includable if `maxFeesPerGas`
|
|
177
|
+
covers the checkpoint's `gasFees` in both dimensions. The effective fee adds an
|
|
178
|
+
EIP-1559-style priority fee on top of the base, capped by the max
|
|
179
|
+
(`computeEffectiveGasFees` in `stdlib/src/fees/transaction_fee.ts`):
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
effectiveFeePerGas = gasFees + min(maxPriorityFeePerGas, maxFeesPerGas - gasFees) (per dimension)
|
|
183
|
+
transactionFee = billedGas.daGas * effectiveFeePerDaGas + billedGas.l2Gas * effectiveFeePerL2Gas
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
`billedGas` is actual consumption except for the teardown phase, which is billed at the
|
|
187
|
+
declared `teardownGasLimits` rather than actual usage — the fee is charged during teardown
|
|
188
|
+
itself, before actual teardown consumption is known.
|
|
189
|
+
|
|
128
190
|
## Maximum Fee Change Rate
|
|
129
191
|
|
|
130
|
-
| Component | Bound
|
|
131
|
-
| ---------------------- |
|
|
132
|
-
| L1 base fee / blob fee | At most once every 5 slots (oracle LIFETIME)
|
|
133
|
-
| Fee asset price | ±1% per checkpoint
|
|
192
|
+
| Component | Bound |
|
|
193
|
+
| ---------------------- | -------------------------------------------------------- |
|
|
194
|
+
| L1 base fee / blob fee | At most once every 5 slots (oracle LIFETIME) |
|
|
195
|
+
| Fee asset price | ±1% per checkpoint |
|
|
196
|
+
| Proving cost per mana | At most ×1.5 (or ÷1.5) per update, one update per 30 days |
|
|
134
197
|
| Congestion multiplier | Depends on excess mana accumulation/drain per checkpoint |
|
|
135
|
-
| Sequencer/prover costs | Scale linearly with L1 fees
|
|
198
|
+
| Sequencer/prover costs | Scale linearly with L1 fees |
|
|
136
199
|
|
|
137
200
|
## Key Constants
|
|
138
201
|
|
|
139
|
-
| Constant
|
|
140
|
-
|
|
|
141
|
-
| `L1_GAS_PER_CHECKPOINT_PROPOSED` | 300,000
|
|
142
|
-
| `L1_GAS_PER_EPOCH_VERIFIED` | 3,600,000
|
|
143
|
-
| `BLOBS_PER_CHECKPOINT`
|
|
144
|
-
| `BLOB_GAS_PER_BLOB` | 2^17
|
|
145
|
-
| `MINIMUM_CONGESTION_MULTIPLIER` | 1e9
|
|
146
|
-
| `LAG` | 2 slots
|
|
147
|
-
| `LIFETIME` | 5 slots
|
|
202
|
+
| Constant | Value |
|
|
203
|
+
| ------------------------------- | -------------- |
|
|
204
|
+
| `L1_GAS_PER_CHECKPOINT_PROPOSED` | 300,000 |
|
|
205
|
+
| `L1_GAS_PER_EPOCH_VERIFIED` | 3,600,000 |
|
|
206
|
+
| `BLOBS_PER_CHECKPOINT` (FeeLib) | 3 |
|
|
207
|
+
| `BLOB_GAS_PER_BLOB` | 2^17 |
|
|
208
|
+
| `MINIMUM_CONGESTION_MULTIPLIER` | 1e9 |
|
|
209
|
+
| `LAG` | 2 slots |
|
|
210
|
+
| `LIFETIME` | 5 slots |
|
|
211
|
+
| `MIN_ETH_PER_FEE_ASSET` | 100 (1e-10 ETH) |
|
|
212
|
+
| `MAX_ETH_PER_FEE_ASSET` | 1e14 (100 ETH) |
|
|
213
|
+
|
|
214
|
+
⚠️ Name clash: `FeeLib.sol` (and its port `fee_math.ts`) defines `BLOBS_PER_CHECKPOINT = 3`,
|
|
215
|
+
used only to price the sequencer's blob costs. The protocol constant of the same name in
|
|
216
|
+
`@aztec/constants` is **6** — the actual blob capacity of a checkpoint, used throughout the
|
|
217
|
+
limits section below. The FeeLib value is a holdover from the pre-checkpoint
|
|
218
|
+
`BLOBS_PER_BLOCK`, so the fee model prices half of a full checkpoint's blobs.
|
|
148
219
|
|
|
149
220
|
## Gas and Data Limits
|
|
150
221
|
|
|
@@ -196,7 +267,7 @@ advertises them in `NodeInfo.txsLimits` (a required field); wallets read it and
|
|
|
196
267
|
`GasSettings.fallback` as the default gas limits when sending without explicit limits, and they are enforced
|
|
197
268
|
by `GasLimitsValidator` (clamped to the per-tx protocol maxima) at three points: RPC tx acceptance
|
|
198
269
|
(`aztec-node/src/aztec-node/server.ts`), gossip validation (`p2p/src/services/libp2p/libp2p_service.ts`),
|
|
199
|
-
and pending-pool admission (`p2p/src/client/factory.ts`). They are deliberately *not* enforced at
|
|
270
|
+
and pending-pool admission (`p2p/src/client/factory.ts`). They are deliberately *not* enforced at req/resp or
|
|
200
271
|
block-proposal validation — admission is relay policy, not block validity.
|
|
201
272
|
|
|
202
273
|
### Per-block builder budgets
|
|
@@ -240,7 +311,8 @@ The outermost limits, enforced as proposal validity in `validateCheckpointLimits
|
|
|
240
311
|
|
|
241
312
|
## TypeScript Types
|
|
242
313
|
|
|
243
|
-
- **`Gas`** —
|
|
314
|
+
- **`Gas`** — gas quantity in two dimensions (`daGas`, `l2Gas`).
|
|
244
315
|
- **`GasFees`** — per-unit price in each dimension (`feePerDaGas`, `feePerL2Gas`).
|
|
245
316
|
- **`GasSettings`** — sender-chosen fee parameters: gas limits, teardown limits, max fees, priority fees.
|
|
246
317
|
- **`GasUsed`** — actual consumption after execution. Note: `billedGas` uses the teardown gas *limit*, not actual usage.
|
|
318
|
+
- **`fee_math.ts`** — TypeScript port of the FeeLib formulas, used for fee prediction over the oracle LAG window.
|