@aztec/p2p 0.0.1-commit.f504929 → 0.0.1-commit.f81dbcf

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.
Files changed (139) hide show
  1. package/dest/client/factory.d.ts +1 -1
  2. package/dest/client/factory.d.ts.map +1 -1
  3. package/dest/client/factory.js +7 -2
  4. package/dest/client/p2p_client.d.ts +1 -1
  5. package/dest/client/p2p_client.d.ts.map +1 -1
  6. package/dest/client/p2p_client.js +8 -26
  7. package/dest/config.d.ts +24 -2
  8. package/dest/config.d.ts.map +1 -1
  9. package/dest/config.js +65 -6
  10. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts +1 -1
  11. package/dest/mem_pools/attestation_pool/attestation_pool.d.ts.map +1 -1
  12. package/dest/mem_pools/attestation_pool/attestation_pool.js +1 -5
  13. package/dest/mem_pools/instrumentation.d.ts +2 -4
  14. package/dest/mem_pools/instrumentation.d.ts.map +1 -1
  15. package/dest/mem_pools/instrumentation.js +14 -16
  16. package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
  17. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  18. package/dest/mem_pools/tx_pool/priority.js +4 -4
  19. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  20. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  21. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +3 -1
  22. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
  23. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  24. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
  25. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  26. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
  27. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
  28. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  29. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
  30. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +3 -3
  31. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  32. package/dest/mem_pools/tx_pool_v2/interfaces.js +1 -1
  33. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +13 -4
  34. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  35. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +26 -9
  36. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +1 -1
  37. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  38. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +0 -3
  39. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +1 -2
  40. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  41. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +2 -11
  42. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +5 -4
  43. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  44. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  45. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +5 -4
  46. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  47. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  48. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +12 -9
  49. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  50. package/dest/msg_validators/proposal_validator/proposal_validator.js +46 -44
  51. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +1 -1
  52. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  53. package/dest/msg_validators/tx_validator/allowed_public_setup.js +21 -32
  54. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  55. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  56. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  57. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  58. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  59. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  60. package/dest/msg_validators/tx_validator/factory.d.ts +15 -4
  61. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  62. package/dest/msg_validators/tx_validator/factory.js +21 -8
  63. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  64. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  65. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  66. package/dest/msg_validators/tx_validator/gas_validator.d.ts +13 -4
  67. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  68. package/dest/msg_validators/tx_validator/gas_validator.js +39 -9
  69. package/dest/msg_validators/tx_validator/index.d.ts +2 -1
  70. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  71. package/dest/msg_validators/tx_validator/index.js +1 -0
  72. package/dest/msg_validators/tx_validator/phases_validator.d.ts +1 -1
  73. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  74. package/dest/msg_validators/tx_validator/phases_validator.js +21 -1
  75. package/dest/services/libp2p/libp2p_service.d.ts +1 -1
  76. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  77. package/dest/services/libp2p/libp2p_service.js +20 -14
  78. package/dest/services/peer-manager/metrics.d.ts +1 -3
  79. package/dest/services/peer-manager/metrics.d.ts.map +1 -1
  80. package/dest/services/peer-manager/metrics.js +0 -6
  81. package/dest/services/peer-manager/peer_manager.d.ts +1 -1
  82. package/dest/services/peer-manager/peer_manager.d.ts.map +1 -1
  83. package/dest/services/peer-manager/peer_manager.js +1 -2
  84. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts +1 -1
  85. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.d.ts.map +1 -1
  86. package/dest/services/reqresp/batch-tx-requester/batch_tx_requester.js +37 -14
  87. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts +11 -17
  88. package/dest/services/reqresp/batch-tx-requester/peer_collection.d.ts.map +1 -1
  89. package/dest/services/reqresp/batch-tx-requester/peer_collection.js +15 -49
  90. package/dest/services/reqresp/reqresp.d.ts +1 -1
  91. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  92. package/dest/services/reqresp/reqresp.js +1 -2
  93. package/dest/test-helpers/testbench-utils.d.ts +1 -1
  94. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  95. package/dest/test-helpers/testbench-utils.js +2 -1
  96. package/dest/testbench/p2p_client_testbench_worker.js +2 -1
  97. package/dest/testbench/worker_client_manager.d.ts +3 -1
  98. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  99. package/dest/testbench/worker_client_manager.js +4 -1
  100. package/package.json +14 -14
  101. package/src/client/factory.ts +7 -1
  102. package/src/client/p2p_client.ts +5 -26
  103. package/src/config.ts +92 -4
  104. package/src/mem_pools/attestation_pool/attestation_pool.ts +4 -5
  105. package/src/mem_pools/instrumentation.ts +13 -17
  106. package/src/mem_pools/tx_pool/priority.ts +4 -4
  107. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
  108. package/src/mem_pools/tx_pool_v2/README.md +9 -1
  109. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
  110. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
  111. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
  112. package/src/mem_pools/tx_pool_v2/interfaces.ts +3 -3
  113. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +37 -7
  114. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +0 -3
  115. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +3 -12
  116. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +13 -3
  117. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +19 -6
  118. package/src/msg_validators/proposal_validator/proposal_validator.ts +57 -48
  119. package/src/msg_validators/tx_validator/allowed_public_setup.ts +16 -35
  120. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  121. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  122. package/src/msg_validators/tx_validator/factory.ts +22 -2
  123. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  124. package/src/msg_validators/tx_validator/gas_validator.ts +41 -8
  125. package/src/msg_validators/tx_validator/index.ts +1 -0
  126. package/src/msg_validators/tx_validator/phases_validator.ts +29 -0
  127. package/src/services/libp2p/libp2p_service.ts +21 -13
  128. package/src/services/peer-manager/metrics.ts +0 -7
  129. package/src/services/peer-manager/peer_manager.ts +1 -2
  130. package/src/services/reqresp/batch-tx-requester/batch_tx_requester.ts +42 -14
  131. package/src/services/reqresp/batch-tx-requester/peer_collection.ts +24 -63
  132. package/src/services/reqresp/reqresp.ts +1 -3
  133. package/src/test-helpers/testbench-utils.ts +1 -0
  134. package/src/testbench/p2p_client_testbench_worker.ts +1 -0
  135. package/src/testbench/worker_client_manager.ts +11 -4
  136. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -24
  137. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  138. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -378
  139. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -373
@@ -1,15 +1,21 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { NoCommitteeError } from '@aztec/ethereum/contracts';
3
3
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
- import { BlockProposal, CheckpointProposal, PeerErrorSeverity, type ValidationResult } from '@aztec/stdlib/p2p';
4
+ import {
5
+ type BlockProposal,
6
+ type CheckpointProposalCore,
7
+ PeerErrorSeverity,
8
+ type ValidationResult,
9
+ } from '@aztec/stdlib/p2p';
5
10
 
6
11
  import { isWithinClockTolerance } from '../clock_tolerance.js';
7
12
 
8
- export abstract class ProposalValidator<TProposal extends BlockProposal | CheckpointProposal> {
9
- protected epochCache: EpochCacheInterface;
10
- protected logger: Logger;
11
- protected txsPermitted: boolean;
12
- protected maxTxsPerBlock?: number;
13
+ /** Validates header-level and tx-level fields of block and checkpoint proposals. */
14
+ export class ProposalValidator {
15
+ private epochCache: EpochCacheInterface;
16
+ private logger: Logger;
17
+ private txsPermitted: boolean;
18
+ private maxTxsPerBlock?: number;
13
19
 
14
20
  constructor(
15
21
  epochCache: EpochCacheInterface,
@@ -22,7 +28,8 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
22
28
  this.logger = createLogger(loggerName);
23
29
  }
24
30
 
25
- public async validate(proposal: TProposal): Promise<ValidationResult> {
31
+ /** Validates header-level fields: slot, signature, and proposer. */
32
+ public async validate(proposal: BlockProposal | CheckpointProposalCore): Promise<ValidationResult> {
26
33
  try {
27
34
  // Slot check
28
35
  const { currentSlot, nextSlot } = this.epochCache.getCurrentAndNextSlot();
@@ -44,38 +51,6 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
44
51
  return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
45
52
  }
46
53
 
47
- // Transactions permitted check
48
- const embeddedTxCount = proposal.txs?.length ?? 0;
49
- if (!this.txsPermitted && (proposal.txHashes.length > 0 || embeddedTxCount > 0)) {
50
- this.logger.warn(
51
- `Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when transactions are not permitted`,
52
- );
53
- return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
54
- }
55
-
56
- // Max txs per block check
57
- if (this.maxTxsPerBlock !== undefined && proposal.txHashes.length > this.maxTxsPerBlock) {
58
- this.logger.warn(
59
- `Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when max is ${this.maxTxsPerBlock}`,
60
- );
61
- return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
62
- }
63
-
64
- // Embedded txs must be listed in txHashes
65
- const hashSet = new Set(proposal.txHashes.map(h => h.toString()));
66
- const missingTxHashes =
67
- embeddedTxCount > 0
68
- ? proposal.txs!.filter(tx => !hashSet.has(tx.getTxHash().toString())).map(tx => tx.getTxHash().toString())
69
- : [];
70
- if (embeddedTxCount > 0 && missingTxHashes.length > 0) {
71
- this.logger.warn('Penalizing peer for embedded transaction(s) not included in txHashes', {
72
- embeddedTxCount,
73
- txHashesLength: proposal.txHashes.length,
74
- missingTxHashes,
75
- });
76
- return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
77
- }
78
-
79
54
  // Proposer check
80
55
  const expectedProposer = await this.epochCache.getProposerAttesterAddressInSlot(slotNumber);
81
56
  if (expectedProposer !== undefined && !proposer.equals(expectedProposer)) {
@@ -86,15 +61,6 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
86
61
  return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
87
62
  }
88
63
 
89
- // Validate tx hashes for all txs embedded in the proposal
90
- if (!(await Promise.all(proposal.txs?.map(tx => tx.validateTxHash()) ?? [])).every(v => v)) {
91
- this.logger.warn(`Penalizing peer for invalid tx hashes in proposal`, {
92
- proposer,
93
- slotNumber,
94
- });
95
- return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
96
- }
97
-
98
64
  return { result: 'accept' };
99
65
  } catch (e) {
100
66
  if (e instanceof NoCommitteeError) {
@@ -103,4 +69,47 @@ export abstract class ProposalValidator<TProposal extends BlockProposal | Checkp
103
69
  throw e;
104
70
  }
105
71
  }
72
+
73
+ /** Validates transaction-related fields of a block proposal. */
74
+ public async validateTxs(proposal: BlockProposal): Promise<ValidationResult> {
75
+ // Transactions permitted check
76
+ const embeddedTxCount = proposal.txs?.length ?? 0;
77
+ if (!this.txsPermitted && (proposal.txHashes.length > 0 || embeddedTxCount > 0)) {
78
+ this.logger.warn(
79
+ `Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when transactions are not permitted`,
80
+ );
81
+ return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
82
+ }
83
+
84
+ // Max txs per block check
85
+ if (this.maxTxsPerBlock !== undefined && proposal.txHashes.length > this.maxTxsPerBlock) {
86
+ this.logger.warn(
87
+ `Penalizing peer for proposal with ${proposal.txHashes.length} transaction(s) when max is ${this.maxTxsPerBlock}`,
88
+ );
89
+ return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
90
+ }
91
+
92
+ // Embedded txs must be listed in txHashes
93
+ const hashSet = new Set(proposal.txHashes.map(h => h.toString()));
94
+ const missingTxHashes =
95
+ embeddedTxCount > 0
96
+ ? proposal.txs!.filter(tx => !hashSet.has(tx.getTxHash().toString())).map(tx => tx.getTxHash().toString())
97
+ : [];
98
+ if (embeddedTxCount > 0 && missingTxHashes.length > 0) {
99
+ this.logger.warn('Penalizing peer for embedded transaction(s) not included in txHashes', {
100
+ embeddedTxCount,
101
+ txHashesLength: proposal.txHashes.length,
102
+ missingTxHashes,
103
+ });
104
+ return { result: 'reject', severity: PeerErrorSeverity.MidToleranceError };
105
+ }
106
+
107
+ // Validate tx hashes for all txs embedded in the proposal
108
+ if (!(await Promise.all(proposal.txs?.map(tx => tx.validateTxHash()) ?? [])).every(v => v)) {
109
+ this.logger.warn(`Penalizing peer for invalid tx hashes in proposal`);
110
+ return { result: 'reject', severity: PeerErrorSeverity.LowToleranceError };
111
+ }
112
+
113
+ return { result: 'accept' };
114
+ }
106
115
  }
@@ -1,49 +1,30 @@
1
- import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token';
2
1
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
3
- import { FunctionSelector } from '@aztec/stdlib/abi';
4
- import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
2
+ import { AuthRegistryArtifact } from '@aztec/protocol-contracts/auth-registry';
3
+ import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
5
4
  import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
6
5
 
6
+ import { buildAllowedElement } from './allowed_setup_helpers.js';
7
+
7
8
  let defaultAllowedSetupFunctions: AllowedElement[] | undefined;
8
9
 
9
10
  /** Returns the default list of functions allowed to run in the setup phase of a transaction. */
10
11
  export async function getDefaultAllowedSetupFunctions(): Promise<AllowedElement[]> {
11
12
  if (defaultAllowedSetupFunctions === undefined) {
12
- const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id;
13
- const setAuthorizedInternalSelector = await FunctionSelector.fromSignature('_set_authorized((Field),Field,bool)');
14
- const setAuthorizedSelector = await FunctionSelector.fromSignature('set_authorized(Field,bool)');
15
- const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)');
16
- const transferInPublicSelector = await FunctionSelector.fromSignature(
17
- 'transfer_in_public((Field),(Field),u128,Field)',
18
- );
19
-
20
- defaultAllowedSetupFunctions = [
13
+ defaultAllowedSetupFunctions = await Promise.all([
21
14
  // AuthRegistry: needed for authwit support via private path (set_authorized_private enqueues _set_authorized)
22
- {
23
- address: ProtocolContractAddress.AuthRegistry,
24
- selector: setAuthorizedInternalSelector,
25
- },
15
+ buildAllowedElement(AuthRegistryArtifact, { address: ProtocolContractAddress.AuthRegistry }, '_set_authorized', {
16
+ onlySelf: true,
17
+ rejectNullMsgSender: true,
18
+ }),
26
19
  // AuthRegistry: needed for authwit support via public path (PublicFeePaymentMethod calls set_authorized directly)
27
- {
28
- address: ProtocolContractAddress.AuthRegistry,
29
- selector: setAuthorizedSelector,
30
- },
20
+ buildAllowedElement(AuthRegistryArtifact, { address: ProtocolContractAddress.AuthRegistry }, 'set_authorized', {
21
+ rejectNullMsgSender: true,
22
+ }),
31
23
  // FeeJuice: needed for claiming on the same tx as a spend (claim_and_end_setup enqueues this)
32
- {
33
- address: ProtocolContractAddress.FeeJuice,
34
- selector: increaseBalanceSelector,
35
- },
36
- // Token: needed for private transfers via FPC (transfer_to_public enqueues this)
37
- {
38
- classId: tokenClassId,
39
- selector: increaseBalanceSelector,
40
- },
41
- // Token: needed for public transfers via FPC (fee_entrypoint_public enqueues this)
42
- {
43
- classId: tokenClassId,
44
- selector: transferInPublicSelector,
45
- },
46
- ];
24
+ buildAllowedElement(FeeJuiceArtifact, { address: ProtocolContractAddress.FeeJuice }, '_increase_public_balance', {
25
+ onlySelf: true,
26
+ }),
27
+ ]);
47
28
  }
48
29
  return defaultAllowedSetupFunctions;
49
30
  }
@@ -0,0 +1,31 @@
1
+ import type { Fr } from '@aztec/foundation/curves/bn254';
2
+ import { FunctionSelector, countArgumentsSize, getAllFunctionAbis } from '@aztec/stdlib/abi';
3
+ import type { ContractArtifact } from '@aztec/stdlib/abi';
4
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
5
+ import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
6
+
7
+ /**
8
+ * Builds an AllowedElement from a contract artifact, deriving both the function selector
9
+ * and calldata length from the artifact instead of hardcoding signature strings.
10
+ */
11
+ export async function buildAllowedElement(
12
+ artifact: ContractArtifact,
13
+ target: { address: AztecAddress } | { classId: Fr },
14
+ functionName: string,
15
+ opts?: { onlySelf?: boolean; rejectNullMsgSender?: boolean },
16
+ ): Promise<AllowedElement> {
17
+ const allFunctions = getAllFunctionAbis(artifact);
18
+ const fn = allFunctions.find(f => f.name === functionName);
19
+ if (!fn) {
20
+ throw new Error(`Unknown function ${functionName} in artifact ${artifact.name}`);
21
+ }
22
+ const selector = await FunctionSelector.fromNameAndParameters(fn.name, fn.parameters);
23
+ const calldataLength = 1 + countArgumentsSize(fn);
24
+ return {
25
+ ...target,
26
+ selector,
27
+ calldataLength,
28
+ ...(opts?.onlySelf ? { onlySelf: true } : {}),
29
+ ...(opts?.rejectNullMsgSender ? { rejectNullMsgSender: true } : {}),
30
+ } as AllowedElement;
31
+ }
@@ -0,0 +1,56 @@
1
+ import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
2
+ import { ContractInstancePublishedEvent } from '@aztec/protocol-contracts/instance-registry';
3
+ import { computeContractAddressFromInstance } from '@aztec/stdlib/contract';
4
+ import {
5
+ TX_ERROR_INCORRECT_CONTRACT_ADDRESS,
6
+ TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG,
7
+ type Tx,
8
+ type TxValidationResult,
9
+ type TxValidator,
10
+ } from '@aztec/stdlib/tx';
11
+
12
+ /** Validates that contract instance deployment logs contain correct addresses. */
13
+ export class ContractInstanceTxValidator implements TxValidator<Tx> {
14
+ #log: Logger;
15
+
16
+ constructor(bindings?: LoggerBindings) {
17
+ this.#log = createLogger('p2p:tx_validator:contract_instance', bindings);
18
+ }
19
+
20
+ async validateTx(tx: Tx): Promise<TxValidationResult> {
21
+ const reason = await this.#hasCorrectContractInstanceAddresses(tx);
22
+ return reason ? { result: 'invalid', reason: [reason] } : { result: 'valid' };
23
+ }
24
+
25
+ async #hasCorrectContractInstanceAddresses(tx: Tx): Promise<string | undefined> {
26
+ const privateLogs = tx.data.getNonEmptyPrivateLogs();
27
+ for (const log of privateLogs) {
28
+ if (!ContractInstancePublishedEvent.isContractInstancePublishedEvent(log)) {
29
+ continue;
30
+ }
31
+
32
+ let event;
33
+ try {
34
+ event = ContractInstancePublishedEvent.fromLog(log);
35
+ } catch (e) {
36
+ this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to parse contract instance event: ${e}`);
37
+ return TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG;
38
+ }
39
+
40
+ try {
41
+ const instance = event.toContractInstance();
42
+ const computedAddress = await computeContractAddressFromInstance(instance);
43
+ if (!computedAddress.equals(instance.address)) {
44
+ this.#log.warn(
45
+ `Rejecting tx ${tx.getTxHash()}: contract instance address mismatch. Claimed ${instance.address}, computed ${computedAddress}`,
46
+ );
47
+ return TX_ERROR_INCORRECT_CONTRACT_ADDRESS;
48
+ }
49
+ } catch (e) {
50
+ this.#log.warn(`Rejecting tx ${tx.getTxHash()}: failed to compute contract instance address: ${e}`);
51
+ return TX_ERROR_MALFORMED_CONTRACT_INSTANCE_LOG;
52
+ }
53
+ }
54
+ return undefined;
55
+ }
56
+ }
@@ -53,6 +53,7 @@ import type { TxMetaData } from '../../mem_pools/tx_pool_v2/tx_metadata.js';
53
53
  import { AggregateTxValidator } from './aggregate_tx_validator.js';
54
54
  import { ArchiveCache } from './archive_cache.js';
55
55
  import { type ArchiveSource, BlockHeaderTxValidator } from './block_header_validator.js';
56
+ import { ContractInstanceTxValidator } from './contract_instance_validator.js';
56
57
  import { DataTxValidator } from './data_validator.js';
57
58
  import { DoubleSpendTxValidator, type NullifierSource } from './double_spend_validator.js';
58
59
  import { GasLimitsValidator, GasTxValidator } from './gas_validator.js';
@@ -97,6 +98,7 @@ export function createFirstStageTxValidationsForGossipedTransactions(
97
98
  txsPermitted: boolean,
98
99
  allowedInSetup: AllowedElement[] = [],
99
100
  bindings?: LoggerBindings,
101
+ gasLimitOpts?: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number },
100
102
  ): Record<string, TransactionValidator> {
101
103
  const merkleTree = worldStateSynchronizer.getCommitted();
102
104
 
@@ -158,6 +160,7 @@ export function createFirstStageTxValidationsForGossipedTransactions(
158
160
  ProtocolContractAddress.FeeJuice,
159
161
  gasFees,
160
162
  bindings,
163
+ gasLimitOpts,
161
164
  ),
162
165
  severity: PeerErrorSeverity.MidToleranceError,
163
166
  },
@@ -165,6 +168,10 @@ export function createFirstStageTxValidationsForGossipedTransactions(
165
168
  validator: new DataTxValidator(bindings),
166
169
  severity: PeerErrorSeverity.MidToleranceError,
167
170
  },
171
+ contractInstanceValidator: {
172
+ validator: new ContractInstanceTxValidator(bindings),
173
+ severity: PeerErrorSeverity.MidToleranceError,
174
+ },
168
175
  };
169
176
  }
170
177
 
@@ -216,6 +223,7 @@ function createTxValidatorForMinimumTxIntegrityChecks(
216
223
  ),
217
224
  new SizeTxValidator(bindings),
218
225
  new DataTxValidator(bindings),
226
+ new ContractInstanceTxValidator(bindings),
219
227
  new TxProofValidator(verifier, bindings),
220
228
  );
221
229
  }
@@ -278,6 +286,9 @@ export function createTxValidatorForAcceptingTxsOverRPC(
278
286
  timestamp,
279
287
  blockNumber,
280
288
  txsPermitted,
289
+ rollupManaLimit,
290
+ maxBlockL2Gas,
291
+ maxBlockDAGas,
281
292
  }: {
282
293
  l1ChainId: number;
283
294
  rollupVersion: number;
@@ -287,6 +298,9 @@ export function createTxValidatorForAcceptingTxsOverRPC(
287
298
  timestamp: UInt64;
288
299
  blockNumber: BlockNumber;
289
300
  txsPermitted: boolean;
301
+ rollupManaLimit: number;
302
+ maxBlockL2Gas?: number;
303
+ maxBlockDAGas?: number;
290
304
  },
291
305
  bindings?: LoggerBindings,
292
306
  ): TxValidator<Tx> {
@@ -313,11 +327,16 @@ export function createTxValidatorForAcceptingTxsOverRPC(
313
327
  new BlockHeaderTxValidator(new ArchiveCache(db), bindings),
314
328
  new DoubleSpendTxValidator(new NullifierCache(db), bindings),
315
329
  new DataTxValidator(bindings),
330
+ new ContractInstanceTxValidator(bindings),
316
331
  ];
317
332
 
318
333
  if (!skipFeeEnforcement) {
319
334
  validators.push(
320
- new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees, bindings),
335
+ new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees, bindings, {
336
+ rollupManaLimit,
337
+ maxBlockL2Gas,
338
+ maxBlockDAGas,
339
+ }),
321
340
  );
322
341
  }
323
342
 
@@ -403,6 +422,7 @@ export async function createTxValidatorForTransactionsEnteringPendingTxPool(
403
422
  worldStateSynchronizer: WorldStateSynchronizer,
404
423
  timestamp: bigint,
405
424
  blockNumber: BlockNumber,
425
+ gasLimitOpts: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number },
406
426
  bindings?: LoggerBindings,
407
427
  ): Promise<TxValidator<TxMetaData>> {
408
428
  await worldStateSynchronizer.syncImmediate();
@@ -419,7 +439,7 @@ export async function createTxValidatorForTransactionsEnteringPendingTxPool(
419
439
  },
420
440
  };
421
441
  return new AggregateTxValidator<TxMetaData>(
422
- new GasLimitsValidator<TxMetaData>(bindings),
442
+ new GasLimitsValidator<TxMetaData>({ ...gasLimitOpts, bindings }),
423
443
  new TimestampTxValidator<TxMetaData>({ timestamp, blockNumber }, bindings),
424
444
  new DoubleSpendTxValidator<TxMetaData>(nullifierSource, bindings),
425
445
  new BlockHeaderTxValidator<TxMetaData>(archiveSource, bindings),
@@ -1,5 +1,6 @@
1
+ import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice';
1
2
  import { getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server';
2
- import { FunctionSelector } from '@aztec/stdlib/abi';
3
+ import { FunctionSelector, getAllFunctionAbis } from '@aztec/stdlib/abi';
3
4
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
5
  import { type Tx, TxExecutionPhase } from '@aztec/stdlib/tx';
5
6
 
@@ -8,7 +9,10 @@ export type FeePayerBalanceDelta = {
8
9
  claimAmount: bigint;
9
10
  };
10
11
 
11
- const increasePublicBalanceSelectorPromise = FunctionSelector.fromSignature('_increase_public_balance((Field),u128)');
12
+ const increasePublicBalanceSelectorPromise = (() => {
13
+ const fn = getAllFunctionAbis(FeeJuiceArtifact).find(f => f.name === '_increase_public_balance')!;
14
+ return FunctionSelector.fromNameAndParameters(fn.name, fn.parameters);
15
+ })();
12
16
 
13
17
  export function getTxFeeLimit(tx: Tx): bigint {
14
18
  return tx.data.constants.txContext.gasSettings.getFeeLimit().toBigInt();
@@ -1,4 +1,5 @@
1
1
  import {
2
+ MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT,
2
3
  MAX_PROCESSABLE_L2_GAS,
3
4
  PRIVATE_TX_L2_GAS_OVERHEAD,
4
5
  PUBLIC_TX_L2_GAS_OVERHEAD,
@@ -49,16 +50,31 @@ export interface HasGasLimitData {
49
50
  */
50
51
  export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidator<T> {
51
52
  #log: Logger;
52
-
53
- constructor(bindings?: LoggerBindings) {
54
- this.#log = createLogger('sequencer:tx_validator:tx_gas', bindings);
53
+ #effectiveMaxL2Gas: number;
54
+ #effectiveMaxDAGas: number;
55
+ #rollupManaLimit: number;
56
+ #maxBlockL2Gas: number;
57
+ #maxBlockDAGas: number;
58
+
59
+ constructor(opts?: {
60
+ rollupManaLimit?: number;
61
+ maxBlockL2Gas?: number;
62
+ maxBlockDAGas?: number;
63
+ bindings?: LoggerBindings;
64
+ }) {
65
+ this.#log = createLogger('sequencer:tx_validator:tx_gas', opts?.bindings);
66
+ this.#rollupManaLimit = opts?.rollupManaLimit ?? Infinity;
67
+ this.#maxBlockL2Gas = opts?.maxBlockL2Gas ?? Infinity;
68
+ this.#maxBlockDAGas = opts?.maxBlockDAGas ?? Infinity;
69
+ this.#effectiveMaxL2Gas = Math.min(MAX_PROCESSABLE_L2_GAS, this.#rollupManaLimit, this.#maxBlockL2Gas);
70
+ this.#effectiveMaxDAGas = Math.min(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, this.#maxBlockDAGas);
55
71
  }
56
72
 
57
73
  validateTx(tx: T): Promise<TxValidationResult> {
58
74
  return Promise.resolve(this.validateGasLimit(tx));
59
75
  }
60
76
 
61
- /** Checks gas limits are >= fixed minimums and <= AVM max processable L2 gas. */
77
+ /** Checks gas limits are >= fixed minimums and <= effective max gas (L2 and DA). */
62
78
  validateGasLimit(tx: T): TxValidationResult {
63
79
  const gasLimits = tx.data.constants.txContext.gasSettings.gasLimits;
64
80
  const minGasLimits = new Gas(
@@ -74,10 +90,21 @@ export class GasLimitsValidator<T extends HasGasLimitData> implements TxValidato
74
90
  return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_GAS_LIMIT] };
75
91
  }
76
92
 
77
- if (gasLimits.l2Gas > MAX_PROCESSABLE_L2_GAS) {
78
- this.#log.verbose(`Rejecting transaction due to the gas limit(s) being higher than the maximum processable gas`, {
93
+ if (gasLimits.l2Gas > this.#effectiveMaxL2Gas) {
94
+ this.#log.verbose(`Rejecting transaction due to the L2 gas limit being higher than the effective maximum`, {
79
95
  gasLimits,
80
- minGasLimits,
96
+ effectiveMaxL2Gas: this.#effectiveMaxL2Gas,
97
+ rollupManaLimit: this.#rollupManaLimit,
98
+ maxBlockL2Gas: this.#maxBlockL2Gas,
99
+ });
100
+ return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] };
101
+ }
102
+
103
+ if (gasLimits.daGas > this.#effectiveMaxDAGas) {
104
+ this.#log.verbose(`Rejecting transaction due to the DA gas limit being higher than the effective maximum`, {
105
+ gasLimits,
106
+ effectiveMaxDAGas: this.#effectiveMaxDAGas,
107
+ maxBlockDAGas: this.#maxBlockDAGas,
81
108
  });
82
109
  return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] };
83
110
  }
@@ -106,21 +133,27 @@ export class GasTxValidator implements TxValidator<Tx> {
106
133
  #publicDataSource: PublicStateSource;
107
134
  #feeJuiceAddress: AztecAddress;
108
135
  #gasFees: GasFees;
136
+ #gasLimitOpts?: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number };
109
137
 
110
138
  constructor(
111
139
  publicDataSource: PublicStateSource,
112
140
  feeJuiceAddress: AztecAddress,
113
141
  gasFees: GasFees,
114
142
  private bindings?: LoggerBindings,
143
+ opts?: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number },
115
144
  ) {
116
145
  this.#log = createLogger('sequencer:tx_validator:tx_gas', bindings);
117
146
  this.#publicDataSource = publicDataSource;
118
147
  this.#feeJuiceAddress = feeJuiceAddress;
119
148
  this.#gasFees = gasFees;
149
+ this.#gasLimitOpts = opts;
120
150
  }
121
151
 
122
152
  async validateTx(tx: Tx): Promise<TxValidationResult> {
123
- const gasLimitValidation = new GasLimitsValidator(this.bindings).validateGasLimit(tx);
153
+ const gasLimitValidation = new GasLimitsValidator({
154
+ ...this.#gasLimitOpts,
155
+ bindings: this.bindings,
156
+ }).validateGasLimit(tx);
124
157
  if (gasLimitValidation.result === 'invalid') {
125
158
  return Promise.resolve(gasLimitValidation);
126
159
  }
@@ -8,6 +8,7 @@ export * from './gas_validator.js';
8
8
  export * from './phases_validator.js';
9
9
  export * from './test_utils.js';
10
10
  export * from './allowed_public_setup.js';
11
+ export * from './allowed_setup_helpers.js';
11
12
  export * from './archive_cache.js';
12
13
  export * from './tx_permitted_validator.js';
13
14
  export * from './timestamp_validator.js';
@@ -1,5 +1,7 @@
1
+ import { NULL_MSG_SENDER_CONTRACT_ADDRESS } from '@aztec/constants';
1
2
  import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
2
3
  import { PublicContractsDB, getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server';
4
+ import { AztecAddress } from '@aztec/stdlib/aztec-address';
3
5
  import type { ContractDataSource } from '@aztec/stdlib/contract';
4
6
  import type { AllowedElement } from '@aztec/stdlib/interfaces/server';
5
7
  import {
@@ -7,6 +9,9 @@ import {
7
9
  TX_ERROR_DURING_VALIDATION,
8
10
  TX_ERROR_SETUP_FUNCTION_NOT_ALLOWED,
9
11
  TX_ERROR_SETUP_FUNCTION_UNKNOWN_CONTRACT,
12
+ TX_ERROR_SETUP_NULL_MSG_SENDER,
13
+ TX_ERROR_SETUP_ONLY_SELF_WRONG_SENDER,
14
+ TX_ERROR_SETUP_WRONG_CALLDATA_LENGTH,
10
15
  Tx,
11
16
  TxExecutionPhase,
12
17
  type TxValidationResult,
@@ -84,6 +89,18 @@ export class PhasesTxValidator implements TxValidator<Tx> {
84
89
  for (const entry of allowList) {
85
90
  if ('address' in entry) {
86
91
  if (contractAddress.equals(entry.address) && entry.selector.equals(functionSelector)) {
92
+ if (entry.calldataLength !== undefined && publicCall.calldata.length !== entry.calldataLength) {
93
+ return TX_ERROR_SETUP_WRONG_CALLDATA_LENGTH;
94
+ }
95
+ if (entry.onlySelf && !publicCall.request.msgSender.equals(contractAddress)) {
96
+ return TX_ERROR_SETUP_ONLY_SELF_WRONG_SENDER;
97
+ }
98
+ if (
99
+ entry.rejectNullMsgSender &&
100
+ publicCall.request.msgSender.equals(AztecAddress.fromBigInt(NULL_MSG_SENDER_CONTRACT_ADDRESS))
101
+ ) {
102
+ return TX_ERROR_SETUP_NULL_MSG_SENDER;
103
+ }
87
104
  return undefined;
88
105
  }
89
106
  }
@@ -105,6 +122,18 @@ export class PhasesTxValidator implements TxValidator<Tx> {
105
122
  }
106
123
 
107
124
  if (contractClassId.value === entry.classId.toString() && entry.selector.equals(functionSelector)) {
125
+ if (entry.calldataLength !== undefined && publicCall.calldata.length !== entry.calldataLength) {
126
+ return TX_ERROR_SETUP_WRONG_CALLDATA_LENGTH;
127
+ }
128
+ if (entry.onlySelf && !publicCall.request.msgSender.equals(contractAddress)) {
129
+ return TX_ERROR_SETUP_ONLY_SELF_WRONG_SENDER;
130
+ }
131
+ if (
132
+ entry.rejectNullMsgSender &&
133
+ publicCall.request.msgSender.equals(AztecAddress.fromBigInt(NULL_MSG_SENDER_CONTRACT_ADDRESS))
134
+ ) {
135
+ return TX_ERROR_SETUP_NULL_MSG_SENDER;
136
+ }
108
137
  return undefined;
109
138
  }
110
139
  }
@@ -1,5 +1,6 @@
1
1
  import type { EpochCacheInterface } from '@aztec/epoch-cache';
2
2
  import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { maxBy } from '@aztec/foundation/collection';
3
4
  import { Fr } from '@aztec/foundation/curves/bn254';
4
5
  import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log';
5
6
  import { RunningPromise } from '@aztec/foundation/running-promise';
@@ -19,6 +20,7 @@ import {
19
20
  P2PMessage,
20
21
  type ValidationResult as P2PValidationResult,
21
22
  PeerErrorSeverity,
23
+ PeerErrorSeverityByHarshness,
22
24
  TopicType,
23
25
  createTopicString,
24
26
  getTopicsForConfig,
@@ -222,14 +224,12 @@ export class LibP2PService extends WithTracer implements P2PService {
222
224
  this.protocolVersion,
223
225
  );
224
226
 
225
- this.blockProposalValidator = new BlockProposalValidator(epochCache, {
227
+ const proposalValidatorOpts = {
226
228
  txsPermitted: !config.disableTransactions,
227
- maxTxsPerBlock: config.maxTxsPerBlock,
228
- });
229
- this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, {
230
- txsPermitted: !config.disableTransactions,
231
- maxTxsPerBlock: config.maxTxsPerBlock,
232
- });
229
+ maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint,
230
+ };
231
+ this.blockProposalValidator = new BlockProposalValidator(epochCache, proposalValidatorOpts);
232
+ this.checkpointProposalValidator = new CheckpointProposalValidator(epochCache, proposalValidatorOpts);
233
233
  this.checkpointAttestationValidator = config.fishermanMode
234
234
  ? new FishermanAttestationValidator(epochCache, mempools.attestationPool, telemetry)
235
235
  : new CheckpointAttestationValidator(epochCache);
@@ -237,11 +237,11 @@ export class LibP2PService extends WithTracer implements P2PService {
237
237
  this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this);
238
238
 
239
239
  this.blockReceivedCallback = async (block: BlockProposal): Promise<boolean> => {
240
- this.logger.debug(
241
- `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`,
240
+ this.logger.warn(
241
+ `Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`,
242
242
  { p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() },
243
243
  );
244
- return false;
244
+ return true;
245
245
  };
246
246
 
247
247
  this.checkpointReceivedCallback = (
@@ -1192,7 +1192,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1192
1192
  // Note: Validators do NOT attest to individual blocks, only to checkpoint proposals.
1193
1193
  const isValid = await this.blockReceivedCallback(block, sender);
1194
1194
  if (!isValid) {
1195
- this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1195
+ this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo());
1196
1196
  }
1197
1197
  }
1198
1198
 
@@ -1626,6 +1626,7 @@ export class LibP2PService extends WithTracer implements P2PService {
1626
1626
  ...(this.config.txPublicSetupAllowListExtend ?? []),
1627
1627
  ];
1628
1628
  const blockNumber = BlockNumber(currentBlockNumber + 1);
1629
+ const l1Constants = await this.archiver.getL1Constants();
1629
1630
 
1630
1631
  return createFirstStageTxValidationsForGossipedTransactions(
1631
1632
  nextSlotTimestamp,
@@ -1639,6 +1640,11 @@ export class LibP2PService extends WithTracer implements P2PService {
1639
1640
  !this.config.disableTransactions,
1640
1641
  allowedInSetup,
1641
1642
  this.logger.getBindings(),
1643
+ {
1644
+ rollupManaLimit: l1Constants.rollupManaLimit,
1645
+ maxBlockL2Gas: this.config.validateMaxL2BlockGas,
1646
+ maxBlockDAGas: this.config.validateMaxDABlockGas,
1647
+ },
1642
1648
  );
1643
1649
  }
1644
1650
 
@@ -1664,8 +1670,10 @@ export class LibP2PService extends WithTracer implements P2PService {
1664
1670
 
1665
1671
  // A promise that resolves when all validations have been run
1666
1672
  const allValidations = await Promise.all(validationPromises);
1667
- const failed = allValidations.find(x => !x.isValid);
1668
- if (failed) {
1673
+ const failures = allValidations.filter(x => !x.isValid);
1674
+ if (failures.length > 0) {
1675
+ // Pick the most severe failure (lowest tolerance = harshest penalty)
1676
+ const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!;
1669
1677
  return {
1670
1678
  allPassed: false,
1671
1679
  failure: {