@aztec/p2p 4.0.0-devnet.2-patch.4 → 4.0.0-devnet.3-patch.1

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 (212) hide show
  1. package/README.md +129 -3
  2. package/dest/client/factory.d.ts +4 -5
  3. package/dest/client/factory.d.ts.map +1 -1
  4. package/dest/client/factory.js +30 -28
  5. package/dest/client/interface.d.ts +8 -13
  6. package/dest/client/interface.d.ts.map +1 -1
  7. package/dest/client/p2p_client.d.ts +6 -13
  8. package/dest/client/p2p_client.d.ts.map +1 -1
  9. package/dest/client/p2p_client.js +22 -88
  10. package/dest/client/test/tx_proposal_collector/proposal_tx_collector_worker.js +2 -4
  11. package/dest/config.d.ts +29 -10
  12. package/dest/config.d.ts.map +1 -1
  13. package/dest/config.js +80 -31
  14. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  15. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  16. package/dest/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.js +2 -1
  17. package/dest/mem_pools/tx_pool/priority.d.ts +2 -2
  18. package/dest/mem_pools/tx_pool/priority.d.ts.map +1 -1
  19. package/dest/mem_pools/tx_pool/priority.js +4 -4
  20. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts +1 -1
  21. package/dest/mem_pools/tx_pool/tx_pool_test_suite.d.ts.map +1 -1
  22. package/dest/mem_pools/tx_pool/tx_pool_test_suite.js +3 -1
  23. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts +1 -1
  24. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.d.ts.map +1 -1
  25. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.js +3 -2
  26. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts +1 -1
  27. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.d.ts.map +1 -1
  28. package/dest/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.js +2 -0
  29. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts +7 -1
  30. package/dest/mem_pools/tx_pool_v2/eviction/interfaces.d.ts.map +1 -1
  31. package/dest/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.js +2 -2
  32. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts +2 -2
  33. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.d.ts.map +1 -1
  34. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.js +10 -6
  35. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts +1 -1
  36. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.d.ts.map +1 -1
  37. package/dest/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.js +8 -6
  38. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts +2 -2
  39. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.d.ts.map +1 -1
  40. package/dest/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.js +2 -2
  41. package/dest/mem_pools/tx_pool_v2/index.d.ts +2 -2
  42. package/dest/mem_pools/tx_pool_v2/index.d.ts.map +1 -1
  43. package/dest/mem_pools/tx_pool_v2/index.js +1 -1
  44. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts +9 -5
  45. package/dest/mem_pools/tx_pool_v2/interfaces.d.ts.map +1 -1
  46. package/dest/mem_pools/tx_pool_v2/interfaces.js +2 -1
  47. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts +46 -8
  48. package/dest/mem_pools/tx_pool_v2/tx_metadata.d.ts.map +1 -1
  49. package/dest/mem_pools/tx_pool_v2/tx_metadata.js +81 -17
  50. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts +1 -1
  51. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.d.ts.map +1 -1
  52. package/dest/mem_pools/tx_pool_v2/tx_pool_indices.js +9 -10
  53. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts +5 -3
  54. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.d.ts.map +1 -1
  55. package/dest/mem_pools/tx_pool_v2/tx_pool_v2.js +3 -0
  56. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts +2 -2
  57. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.d.ts.map +1 -1
  58. package/dest/mem_pools/tx_pool_v2/tx_pool_v2_impl.js +179 -151
  59. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts +6 -4
  60. package/dest/msg_validators/proposal_validator/block_proposal_validator.d.ts.map +1 -1
  61. package/dest/msg_validators/proposal_validator/block_proposal_validator.js +10 -2
  62. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts +6 -4
  63. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.d.ts.map +1 -1
  64. package/dest/msg_validators/proposal_validator/checkpoint_proposal_validator.js +16 -2
  65. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts +13 -8
  66. package/dest/msg_validators/proposal_validator/proposal_validator.d.ts.map +1 -1
  67. package/dest/msg_validators/proposal_validator/proposal_validator.js +48 -36
  68. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts +2 -2
  69. package/dest/msg_validators/tx_validator/aggregate_tx_validator.d.ts.map +1 -1
  70. package/dest/msg_validators/tx_validator/aggregate_tx_validator.js +3 -3
  71. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts +2 -1
  72. package/dest/msg_validators/tx_validator/allowed_public_setup.d.ts.map +1 -1
  73. package/dest/msg_validators/tx_validator/allowed_public_setup.js +24 -20
  74. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts +17 -0
  75. package/dest/msg_validators/tx_validator/allowed_setup_helpers.d.ts.map +1 -0
  76. package/dest/msg_validators/tx_validator/allowed_setup_helpers.js +24 -0
  77. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts +9 -0
  78. package/dest/msg_validators/tx_validator/contract_instance_validator.d.ts.map +1 -0
  79. package/dest/msg_validators/tx_validator/contract_instance_validator.js +48 -0
  80. package/dest/msg_validators/tx_validator/data_validator.d.ts +1 -1
  81. package/dest/msg_validators/tx_validator/data_validator.d.ts.map +1 -1
  82. package/dest/msg_validators/tx_validator/data_validator.js +35 -2
  83. package/dest/msg_validators/tx_validator/factory.d.ts +133 -6
  84. package/dest/msg_validators/tx_validator/factory.d.ts.map +1 -1
  85. package/dest/msg_validators/tx_validator/factory.js +247 -60
  86. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts +1 -1
  87. package/dest/msg_validators/tx_validator/fee_payer_balance.d.ts.map +1 -1
  88. package/dest/msg_validators/tx_validator/fee_payer_balance.js +6 -2
  89. package/dest/msg_validators/tx_validator/gas_validator.d.ts +67 -3
  90. package/dest/msg_validators/tx_validator/gas_validator.d.ts.map +1 -1
  91. package/dest/msg_validators/tx_validator/gas_validator.js +104 -37
  92. package/dest/msg_validators/tx_validator/index.d.ts +3 -1
  93. package/dest/msg_validators/tx_validator/index.d.ts.map +1 -1
  94. package/dest/msg_validators/tx_validator/index.js +2 -0
  95. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts +14 -0
  96. package/dest/msg_validators/tx_validator/nullifier_cache.d.ts.map +1 -0
  97. package/dest/msg_validators/tx_validator/nullifier_cache.js +24 -0
  98. package/dest/msg_validators/tx_validator/phases_validator.d.ts +22 -2
  99. package/dest/msg_validators/tx_validator/phases_validator.d.ts.map +1 -1
  100. package/dest/msg_validators/tx_validator/phases_validator.js +72 -24
  101. package/dest/services/dummy_service.d.ts +4 -4
  102. package/dest/services/dummy_service.d.ts.map +1 -1
  103. package/dest/services/dummy_service.js +4 -4
  104. package/dest/services/encoding.d.ts +6 -2
  105. package/dest/services/encoding.d.ts.map +1 -1
  106. package/dest/services/encoding.js +14 -8
  107. package/dest/services/gossipsub/topic_score_params.d.ts +18 -6
  108. package/dest/services/gossipsub/topic_score_params.d.ts.map +1 -1
  109. package/dest/services/gossipsub/topic_score_params.js +32 -10
  110. package/dest/services/libp2p/libp2p_service.d.ts +16 -13
  111. package/dest/services/libp2p/libp2p_service.d.ts.map +1 -1
  112. package/dest/services/libp2p/libp2p_service.js +97 -93
  113. package/dest/services/reqresp/batch-tx-requester/tx_validator.js +2 -2
  114. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts +5 -4
  115. package/dest/services/reqresp/rate-limiter/rate_limiter.d.ts.map +1 -1
  116. package/dest/services/reqresp/rate-limiter/rate_limiter.js +10 -8
  117. package/dest/services/reqresp/reqresp.d.ts +1 -1
  118. package/dest/services/reqresp/reqresp.d.ts.map +1 -1
  119. package/dest/services/reqresp/reqresp.js +16 -8
  120. package/dest/services/service.d.ts +5 -3
  121. package/dest/services/service.d.ts.map +1 -1
  122. package/dest/services/tx_collection/file_store_tx_source.d.ts +5 -4
  123. package/dest/services/tx_collection/file_store_tx_source.d.ts.map +1 -1
  124. package/dest/services/tx_collection/file_store_tx_source.js +39 -29
  125. package/dest/services/tx_collection/tx_source.d.ts +6 -5
  126. package/dest/services/tx_collection/tx_source.d.ts.map +1 -1
  127. package/dest/services/tx_collection/tx_source.js +9 -7
  128. package/dest/services/tx_provider.d.ts +3 -3
  129. package/dest/services/tx_provider.d.ts.map +1 -1
  130. package/dest/services/tx_provider.js +4 -4
  131. package/dest/test-helpers/make-test-p2p-clients.d.ts +5 -6
  132. package/dest/test-helpers/make-test-p2p-clients.d.ts.map +1 -1
  133. package/dest/test-helpers/make-test-p2p-clients.js +1 -2
  134. package/dest/test-helpers/mock-pubsub.d.ts +4 -4
  135. package/dest/test-helpers/mock-pubsub.d.ts.map +1 -1
  136. package/dest/test-helpers/mock-pubsub.js +8 -2
  137. package/dest/test-helpers/reqresp-nodes.d.ts +2 -3
  138. package/dest/test-helpers/reqresp-nodes.d.ts.map +1 -1
  139. package/dest/test-helpers/reqresp-nodes.js +2 -2
  140. package/dest/test-helpers/testbench-utils.d.ts +2 -2
  141. package/dest/test-helpers/testbench-utils.d.ts.map +1 -1
  142. package/dest/test-helpers/testbench-utils.js +2 -1
  143. package/dest/testbench/p2p_client_testbench_worker.js +7 -6
  144. package/dest/testbench/worker_client_manager.d.ts +3 -1
  145. package/dest/testbench/worker_client_manager.d.ts.map +1 -1
  146. package/dest/testbench/worker_client_manager.js +4 -1
  147. package/dest/util.d.ts +2 -2
  148. package/dest/util.d.ts.map +1 -1
  149. package/package.json +14 -14
  150. package/src/client/factory.ts +49 -45
  151. package/src/client/interface.ts +8 -13
  152. package/src/client/p2p_client.ts +24 -117
  153. package/src/client/test/tx_proposal_collector/proposal_tx_collector_worker.ts +2 -3
  154. package/src/config.ts +115 -33
  155. package/src/mem_pools/tx_pool/eviction/fee_payer_balance_eviction_rule.ts +2 -1
  156. package/src/mem_pools/tx_pool/priority.ts +4 -4
  157. package/src/mem_pools/tx_pool/tx_pool_test_suite.ts +3 -1
  158. package/src/mem_pools/tx_pool_v2/README.md +9 -1
  159. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_eviction_rule.ts +3 -2
  160. package/src/mem_pools/tx_pool_v2/eviction/fee_payer_balance_pre_add_rule.ts +3 -0
  161. package/src/mem_pools/tx_pool_v2/eviction/interfaces.ts +11 -1
  162. package/src/mem_pools/tx_pool_v2/eviction/invalid_txs_after_reorg_rule.ts +2 -2
  163. package/src/mem_pools/tx_pool_v2/eviction/low_priority_eviction_rule.ts +10 -6
  164. package/src/mem_pools/tx_pool_v2/eviction/low_priority_pre_add_rule.ts +15 -6
  165. package/src/mem_pools/tx_pool_v2/eviction/nullifier_conflict_rule.ts +2 -1
  166. package/src/mem_pools/tx_pool_v2/index.ts +1 -1
  167. package/src/mem_pools/tx_pool_v2/interfaces.ts +9 -4
  168. package/src/mem_pools/tx_pool_v2/tx_metadata.ts +113 -18
  169. package/src/mem_pools/tx_pool_v2/tx_pool_indices.ts +11 -11
  170. package/src/mem_pools/tx_pool_v2/tx_pool_v2.ts +14 -2
  171. package/src/mem_pools/tx_pool_v2/tx_pool_v2_impl.ts +188 -153
  172. package/src/msg_validators/attestation_validator/README.md +49 -0
  173. package/src/msg_validators/proposal_validator/README.md +123 -0
  174. package/src/msg_validators/proposal_validator/block_proposal_validator.ts +14 -4
  175. package/src/msg_validators/proposal_validator/checkpoint_proposal_validator.ts +20 -7
  176. package/src/msg_validators/proposal_validator/proposal_validator.ts +63 -40
  177. package/src/msg_validators/tx_validator/README.md +119 -0
  178. package/src/msg_validators/tx_validator/aggregate_tx_validator.ts +3 -3
  179. package/src/msg_validators/tx_validator/allowed_public_setup.ts +22 -27
  180. package/src/msg_validators/tx_validator/allowed_setup_helpers.ts +31 -0
  181. package/src/msg_validators/tx_validator/contract_instance_validator.ts +56 -0
  182. package/src/msg_validators/tx_validator/data_validator.ts +42 -1
  183. package/src/msg_validators/tx_validator/factory.ts +394 -78
  184. package/src/msg_validators/tx_validator/fee_payer_balance.ts +6 -2
  185. package/src/msg_validators/tx_validator/gas_validator.ts +123 -27
  186. package/src/msg_validators/tx_validator/index.ts +2 -0
  187. package/src/msg_validators/tx_validator/nullifier_cache.ts +30 -0
  188. package/src/msg_validators/tx_validator/phases_validator.ts +82 -27
  189. package/src/services/dummy_service.ts +6 -6
  190. package/src/services/encoding.ts +14 -7
  191. package/src/services/gossipsub/README.md +29 -14
  192. package/src/services/gossipsub/topic_score_params.ts +49 -13
  193. package/src/services/libp2p/libp2p_service.ts +111 -101
  194. package/src/services/reqresp/README.md +229 -0
  195. package/src/services/reqresp/batch-tx-requester/tx_validator.ts +2 -2
  196. package/src/services/reqresp/rate-limiter/rate_limiter.ts +13 -9
  197. package/src/services/reqresp/reqresp.ts +18 -10
  198. package/src/services/service.ts +11 -2
  199. package/src/services/tx_collection/file_store_tx_source.ts +43 -31
  200. package/src/services/tx_collection/tx_source.ts +8 -7
  201. package/src/services/tx_provider.ts +2 -2
  202. package/src/test-helpers/make-test-p2p-clients.ts +0 -2
  203. package/src/test-helpers/mock-pubsub.ts +13 -6
  204. package/src/test-helpers/reqresp-nodes.ts +2 -5
  205. package/src/test-helpers/testbench-utils.ts +2 -1
  206. package/src/testbench/p2p_client_testbench_worker.ts +3 -6
  207. package/src/testbench/worker_client_manager.ts +11 -4
  208. package/src/util.ts +7 -1
  209. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts +0 -23
  210. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.d.ts.map +0 -1
  211. package/dest/msg_validators/proposal_validator/proposal_validator_test_suite.js +0 -212
  212. package/src/msg_validators/proposal_validator/proposal_validator_test_suite.ts +0 -230
@@ -2,7 +2,8 @@ import { BlockNumber } from '@aztec/foundation/branded-types';
2
2
  import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import { ProtocolContractAddress } from '@aztec/protocol-contracts';
4
4
  import { BlockHash, type L2BlockId } from '@aztec/stdlib/block';
5
- import type { Tx } from '@aztec/stdlib/tx';
5
+ import { Gas } from '@aztec/stdlib/gas';
6
+ import { type Tx, TxHash } from '@aztec/stdlib/tx';
6
7
 
7
8
  import { getFeePayerBalanceDelta } from '../../msg_validators/tx_validator/fee_payer_balance.js';
8
9
  import { getTxPriorityFee } from '../tx_pool/priority.js';
@@ -12,6 +13,8 @@ import { type PreAddResult, TxPoolRejectionCode } from './eviction/interfaces.js
12
13
  export type TxMetaValidationData = {
13
14
  getNonEmptyNullifiers(): Fr[];
14
15
  expirationTimestamp: bigint;
16
+ /** Whether the tx has public calls. Used to select the correct L2 gas minimum. */
17
+ forPublic?: unknown;
15
18
  constants: {
16
19
  anchorBlockHeader: {
17
20
  hash(): Promise<BlockHash>;
@@ -19,6 +22,9 @@ export type TxMetaValidationData = {
19
22
  blockNumber: BlockNumber;
20
23
  };
21
24
  };
25
+ txContext: {
26
+ gasSettings: { gasLimits: Gas };
27
+ };
22
28
  };
23
29
  };
24
30
 
@@ -34,6 +40,9 @@ export type TxMetaData = {
34
40
  /** The transaction hash as hex string */
35
41
  readonly txHash: string;
36
42
 
43
+ /** The transaction hash as bigint (for efficient Fr conversion in comparisons) */
44
+ readonly txHashBigInt: bigint;
45
+
37
46
  /** Block ID (number and hash) in which the transaction was mined (undefined if not mined) */
38
47
  minedL2BlockId?: L2BlockId;
39
48
 
@@ -58,6 +67,9 @@ export type TxMetaData = {
58
67
  /** Timestamp by which the transaction must be included (for expiration checks) */
59
68
  readonly expirationTimestamp: bigint;
60
69
 
70
+ /** Whether the tx's setup-phase calls pass the allow list check. Computed at receipt time. */
71
+ readonly allowedSetupCalls: boolean;
72
+
61
73
  /** Validator-compatible data, providing the same access patterns as Tx.data */
62
74
  readonly data: TxMetaValidationData;
63
75
 
@@ -75,9 +87,15 @@ export type TxState = 'pending' | 'protected' | 'mined' | 'deleted';
75
87
  * Builds TxMetaData from a full Tx object.
76
88
  * Extracts all relevant fields for efficient in-memory storage and querying.
77
89
  * Fr values are captured in closures for zero-cost re-validation.
90
+ *
91
+ * @param allowedSetupCalls - Whether the tx's setup-phase calls pass the allow list.
92
+ * For gossip/RPC txs this is always `true` (already validated by PhasesTxValidator).
93
+ * For req/resp txs this should be computed by the caller using the phases validator.
78
94
  */
79
- export async function buildTxMetaData(tx: Tx): Promise<TxMetaData> {
80
- const txHash = tx.getTxHash().toString();
95
+ export async function buildTxMetaData(tx: Tx, allowedSetupCalls: boolean = true): Promise<TxMetaData> {
96
+ const txHashObj = tx.getTxHash();
97
+ const txHash = txHashObj.toString();
98
+ const txHashBigInt = txHashObj.toBigInt();
81
99
  const nullifierFrs = tx.data.getNonEmptyNullifiers();
82
100
  const nullifiers = nullifierFrs.map(n => n.toString());
83
101
  const anchorBlockHeaderHashFr = await tx.data.constants.anchorBlockHeader.hash();
@@ -93,6 +111,7 @@ export async function buildTxMetaData(tx: Tx): Promise<TxMetaData> {
93
111
 
94
112
  return {
95
113
  txHash,
114
+ txHashBigInt,
96
115
  anchorBlockHeaderHash,
97
116
  priorityFee,
98
117
  feePayer,
@@ -100,16 +119,21 @@ export async function buildTxMetaData(tx: Tx): Promise<TxMetaData> {
100
119
  feeLimit,
101
120
  nullifiers,
102
121
  expirationTimestamp,
122
+ allowedSetupCalls,
103
123
  receivedAt: 0,
104
124
  estimatedSizeBytes,
105
125
  data: {
106
126
  getNonEmptyNullifiers: () => nullifierFrs,
107
127
  expirationTimestamp,
128
+ forPublic: !!tx.data.forPublic,
108
129
  constants: {
109
130
  anchorBlockHeader: {
110
131
  hash: () => Promise.resolve(anchorBlockHeaderHashFr),
111
132
  globalVariables: { blockNumber: anchorBlockNumber },
112
133
  },
134
+ txContext: {
135
+ gasSettings: { gasLimits: tx.data.constants.txContext.gasSettings.gasLimits },
136
+ },
113
137
  },
114
138
  },
115
139
  };
@@ -124,11 +148,11 @@ const HEX_STRING_BYTES = 98;
124
148
  const BIGINT_BYTES = 32;
125
149
  const FR_BYTES = 80;
126
150
  // Fixed cost: object shell + txHash + anchorBlockHeaderHash + feePayer (3 hex strings)
127
- // + priorityFee + claimAmount + feeLimit + includeByTimestamp (4 bigints)
151
+ // + txHashBigInt + priorityFee + claimAmount + feeLimit + includeByTimestamp (5 bigints)
128
152
  // + receivedAt (number, 8 bytes) + estimatedSizeBytes (number, 8 bytes)
129
153
  // + data closure object (~OBJECT_OVERHEAD + anchorBlockHeaderHashFr Fr + anchorBlockNumber number)
130
154
  const FIXED_METADATA_BYTES =
131
- OBJECT_OVERHEAD + 3 * HEX_STRING_BYTES + 4 * BIGINT_BYTES + 8 + 8 + OBJECT_OVERHEAD + FR_BYTES + 8;
155
+ OBJECT_OVERHEAD + 3 * HEX_STRING_BYTES + 5 * BIGINT_BYTES + 8 + 8 + OBJECT_OVERHEAD + FR_BYTES + 8;
132
156
 
133
157
  /** Estimates the in-memory size of a TxMetaData object based on the number of nullifiers. */
134
158
  function estimateTxMetaDataSize(nullifierCount: number): number {
@@ -136,8 +160,13 @@ function estimateTxMetaDataSize(nullifierCount: number): number {
136
160
  return FIXED_METADATA_BYTES + nullifierCount * (HEX_STRING_BYTES + FR_BYTES);
137
161
  }
138
162
 
163
+ /** Converts a txHash bigint back to the canonical 0x-prefixed 64-char hex string. */
164
+ export function txHashFromBigInt(value: bigint): string {
165
+ return TxHash.fromBigInt(value).toString();
166
+ }
167
+
139
168
  /** Minimal fields required for priority comparison. */
140
- type PriorityComparable = Pick<TxMetaData, 'txHash' | 'priorityFee'>;
169
+ type PriorityComparable = Pick<TxMetaData, 'txHashBigInt' | 'priorityFee'>;
141
170
 
142
171
  /**
143
172
  * Compares two priority fees in ascending order.
@@ -152,10 +181,8 @@ export function compareFee(a: bigint, b: bigint): number {
152
181
  * Uses field element comparison for deterministic ordering.
153
182
  * Returns negative if a < b, positive if a > b, 0 if equal.
154
183
  */
155
- export function compareTxHash(a: string, b: string): number {
156
- const fieldA = Fr.fromHexString(a);
157
- const fieldB = Fr.fromHexString(b);
158
- return fieldA.cmp(fieldB);
184
+ export function compareTxHash(a: bigint, b: bigint): number {
185
+ return Fr.cmpAsBigInt(a, b);
159
186
  }
160
187
 
161
188
  /**
@@ -168,24 +195,41 @@ export function comparePriority(a: PriorityComparable, b: PriorityComparable): n
168
195
  if (feeComparison !== 0) {
169
196
  return feeComparison;
170
197
  }
171
- return compareTxHash(a.txHash, b.txHash);
198
+ return compareTxHash(a.txHashBigInt, b.txHashBigInt);
199
+ }
200
+
201
+ /**
202
+ * Returns the minimum fee required to replace an existing tx with the given price bump percentage.
203
+ * Uses integer arithmetic: `existingFee + existingFee * priceBumpPercentage / 100`.
204
+ */
205
+ export function getMinimumPriceBumpFee(existingFee: bigint, priceBumpPercentage: bigint): bigint {
206
+ const bump = (existingFee * priceBumpPercentage) / 100n;
207
+ // Ensure the minimum bump is at least 1, so that replacement always requires
208
+ // paying strictly more — even with 0% bump or zero existing fee.
209
+ const effectiveBump = bump > 0n ? bump : 1n;
210
+ return existingFee + effectiveBump;
172
211
  }
173
212
 
174
213
  /**
175
214
  * Checks for nullifier conflicts between an incoming transaction and existing pool state.
176
215
  *
177
216
  * When the incoming tx shares nullifiers with existing pending txs:
178
- * - If the incoming tx has strictly higher priority, mark conflicting txs for eviction
179
- * - If any conflicting tx has equal or higher priority, ignore the incoming tx
217
+ * - If the incoming tx meets or exceeds the required priority, mark conflicting txs for eviction
218
+ * - Otherwise, ignore the incoming tx
219
+ *
220
+ * When `priceBumpPercentage` is provided (RPC path), uses fee-only comparison with the
221
+ * percentage bump instead of `comparePriority`.
180
222
  *
181
223
  * @param incomingMeta - Metadata for the incoming transaction
182
224
  * @param getTxHashByNullifier - Accessor to find which tx uses a nullifier
183
225
  * @param getMetadata - Accessor to get metadata for a tx hash
226
+ * @param priceBumpPercentage - Optional percentage bump required for fee-based replacement
184
227
  */
185
228
  export function checkNullifierConflict(
186
229
  incomingMeta: TxMetaData,
187
230
  getTxHashByNullifier: (nullifier: string) => string | undefined,
188
231
  getMetadata: (txHash: string) => TxMetaData | undefined,
232
+ priceBumpPercentage?: bigint,
189
233
  ): PreAddResult {
190
234
  const txHashesToEvict: string[] = [];
191
235
 
@@ -206,19 +250,32 @@ export function checkNullifierConflict(
206
250
  continue;
207
251
  }
208
252
 
209
- // If incoming tx has strictly higher priority, mark for eviction
210
- // Otherwise, ignore incoming tx (ties go to existing tx)
211
- // Use comparePriority for deterministic ordering (includes txHash as tiebreaker)
212
- if (comparePriority(incomingMeta, conflictingMeta) > 0) {
253
+ // When price bump is set (RPC path), require the incoming fee to meet the bumped threshold.
254
+ // Otherwise (P2P path), use full comparePriority with tx hash tiebreaker.
255
+ const isHigherPriority =
256
+ priceBumpPercentage !== undefined
257
+ ? incomingMeta.priorityFee >= getMinimumPriceBumpFee(conflictingMeta.priorityFee, priceBumpPercentage)
258
+ : comparePriority(incomingMeta, conflictingMeta) > 0;
259
+
260
+ if (isHigherPriority) {
213
261
  txHashesToEvict.push(conflictingHashStr);
214
262
  } else {
263
+ const minimumFee =
264
+ priceBumpPercentage !== undefined
265
+ ? getMinimumPriceBumpFee(conflictingMeta.priorityFee, priceBumpPercentage)
266
+ : undefined;
215
267
  return {
216
268
  shouldIgnore: true,
217
269
  txHashesToEvict: [],
218
270
  reason: {
219
271
  code: TxPoolRejectionCode.NULLIFIER_CONFLICT,
220
- message: `Nullifier conflict with existing tx ${conflictingHashStr}`,
272
+ message:
273
+ minimumFee !== undefined
274
+ ? `Nullifier conflict with existing tx ${conflictingHashStr}. Minimum required fee: ${minimumFee}, got: ${incomingMeta.priorityFee}`
275
+ : `Nullifier conflict with existing tx ${conflictingHashStr}`,
221
276
  conflictingTxHash: conflictingHashStr,
277
+ minimumPriceBumpFee: minimumFee,
278
+ txPriorityFee: minimumFee !== undefined ? incomingMeta.priorityFee : undefined,
222
279
  },
223
280
  };
224
281
  }
@@ -237,6 +294,44 @@ export function stubTxMetaValidationData(overrides: { expirationTimestamp?: bigi
237
294
  hash: () => Promise.resolve(new BlockHash(Fr.ZERO)),
238
295
  globalVariables: { blockNumber: BlockNumber(0) },
239
296
  },
297
+ txContext: {
298
+ gasSettings: { gasLimits: Gas.empty() },
299
+ },
240
300
  },
241
301
  };
242
302
  }
303
+
304
+ /** Creates a stub TxMetaData for tests. All fields have sensible defaults and can be overridden. */
305
+ export function stubTxMetaData(
306
+ txHash: string,
307
+ overrides: {
308
+ priorityFee?: bigint;
309
+ feePayer?: string;
310
+ claimAmount?: bigint;
311
+ feeLimit?: bigint;
312
+ nullifiers?: string[];
313
+ expirationTimestamp?: bigint;
314
+ anchorBlockHeaderHash?: string;
315
+ allowedSetupCalls?: boolean;
316
+ } = {},
317
+ ): TxMetaData {
318
+ const txHashBigInt = Fr.fromHexString(txHash).toBigInt();
319
+ // Normalize to canonical zero-padded hex so txHashFromBigInt(txHashBigInt) === normalizedTxHash
320
+ const normalizedTxHash = txHashFromBigInt(txHashBigInt);
321
+ const expirationTimestamp = overrides.expirationTimestamp ?? 0n;
322
+ return {
323
+ txHash: normalizedTxHash,
324
+ txHashBigInt,
325
+ anchorBlockHeaderHash: overrides.anchorBlockHeaderHash ?? '0x1234',
326
+ priorityFee: overrides.priorityFee ?? 100n,
327
+ feePayer: overrides.feePayer ?? '0xfeepayer',
328
+ claimAmount: overrides.claimAmount ?? 0n,
329
+ feeLimit: overrides.feeLimit ?? 100n,
330
+ nullifiers: overrides.nullifiers ?? [`0x${normalizedTxHash.slice(2)}null1`],
331
+ expirationTimestamp,
332
+ allowedSetupCalls: overrides.allowedSetupCalls ?? true,
333
+ receivedAt: 0,
334
+ estimatedSizeBytes: 0,
335
+ data: stubTxMetaValidationData({ expirationTimestamp }),
336
+ };
337
+ }
@@ -1,7 +1,7 @@
1
1
  import { SlotNumber } from '@aztec/foundation/branded-types';
2
2
  import type { L2BlockId } from '@aztec/stdlib/block';
3
3
 
4
- import { type TxMetaData, type TxState, compareFee, compareTxHash } from './tx_metadata.js';
4
+ import { type TxMetaData, type TxState, compareFee, compareTxHash, txHashFromBigInt } from './tx_metadata.js';
5
5
 
6
6
  /**
7
7
  * Manages in-memory indices for the transaction pool.
@@ -22,8 +22,8 @@ export class TxPoolIndices {
22
22
  #nullifierToTxHash: Map<string, string> = new Map();
23
23
  /** Fee payer to txHashes index (pending txs only) */
24
24
  #feePayerToTxHashes: Map<string, Set<string>> = new Map();
25
- /** Pending txHashes grouped by priority fee */
26
- #pendingByPriority: Map<bigint, Set<string>> = new Map();
25
+ /** Pending txHash bigints grouped by priority fee */
26
+ #pendingByPriority: Map<bigint, Set<bigint>> = new Map();
27
27
  /** Protected transactions: txHash -> slotNumber */
28
28
  #protectedTransactions: Map<string, SlotNumber> = new Map();
29
29
 
@@ -73,17 +73,17 @@ export class TxPoolIndices {
73
73
  * @param order - 'desc' for highest priority first, 'asc' for lowest priority first
74
74
  */
75
75
  *iteratePendingByPriority(order: 'asc' | 'desc', filter?: (hash: string) => boolean): Generator<string> {
76
- // Use compareFee from tx_metadata, swap args for descending order
77
76
  const feeCompareFn = order === 'desc' ? (a: bigint, b: bigint) => compareFee(b, a) : compareFee;
78
- const hashCompareFn = order === 'desc' ? (a: string, b: string) => compareTxHash(b, a) : compareTxHash;
77
+ const hashCompareFn =
78
+ order === 'desc' ? (a: bigint, b: bigint) => compareTxHash(b, a) : (a: bigint, b: bigint) => compareTxHash(a, b);
79
79
 
80
80
  const sortedFees = [...this.#pendingByPriority.keys()].sort(feeCompareFn);
81
81
 
82
82
  for (const fee of sortedFees) {
83
83
  const hashesAtFee = this.#pendingByPriority.get(fee)!;
84
- // Use compareTxHash from tx_metadata, swap args for descending order
85
84
  const sortedHashes = [...hashesAtFee].sort(hashCompareFn);
86
- for (const hash of sortedHashes) {
85
+ for (const hashBigInt of sortedHashes) {
86
+ const hash = txHashFromBigInt(hashBigInt);
87
87
  if (filter === undefined || filter(hash)) {
88
88
  yield hash;
89
89
  }
@@ -265,8 +265,8 @@ export class TxPoolIndices {
265
265
  getPendingTxs(): TxMetaData[] {
266
266
  const result: TxMetaData[] = [];
267
267
  for (const hashSet of this.#pendingByPriority.values()) {
268
- for (const txHash of hashSet) {
269
- const meta = this.#metadata.get(txHash);
268
+ for (const txHashBigInt of hashSet) {
269
+ const meta = this.#metadata.get(txHashFromBigInt(txHashBigInt));
270
270
  if (meta) {
271
271
  result.push(meta);
272
272
  }
@@ -414,7 +414,7 @@ export class TxPoolIndices {
414
414
  prioritySet = new Set();
415
415
  this.#pendingByPriority.set(meta.priorityFee, prioritySet);
416
416
  }
417
- prioritySet.add(meta.txHash);
417
+ prioritySet.add(meta.txHashBigInt);
418
418
  }
419
419
 
420
420
  #removeFromPendingIndices(meta: TxMetaData): void {
@@ -435,7 +435,7 @@ export class TxPoolIndices {
435
435
  // Remove from priority map
436
436
  const hashSet = this.#pendingByPriority.get(meta.priorityFee);
437
437
  if (hashSet) {
438
- hashSet.delete(meta.txHash);
438
+ hashSet.delete(meta.txHashBigInt);
439
439
  if (hashSet.size === 0) {
440
440
  this.#pendingByPriority.delete(meta.priorityFee);
441
441
  }
@@ -11,7 +11,14 @@ import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-clien
11
11
  import EventEmitter from 'node:events';
12
12
 
13
13
  import { PoolInstrumentation, PoolName } from '../instrumentation.js';
14
- import type { AddTxsResult, TxPoolV2, TxPoolV2Config, TxPoolV2Dependencies, TxPoolV2Events } from './interfaces.js';
14
+ import type {
15
+ AddTxsResult,
16
+ PoolReadAccess,
17
+ TxPoolV2,
18
+ TxPoolV2Config,
19
+ TxPoolV2Dependencies,
20
+ TxPoolV2Events,
21
+ } from './interfaces.js';
15
22
  import type { TxState } from './tx_metadata.js';
16
23
  import { TxPoolV2Impl } from './tx_pool_v2_impl.js';
17
24
 
@@ -74,7 +81,7 @@ export class AztecKVTxPoolV2 extends (EventEmitter as new () => TypedEventEmitte
74
81
  return this.#queue.put(() => this.#impl.addPendingTxs(txs, opts));
75
82
  }
76
83
 
77
- canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored' | 'rejected'> {
84
+ canAddPendingTx(tx: Tx): Promise<'accepted' | 'ignored'> {
78
85
  return this.#queue.put(() => this.#impl.canAddPendingTx(tx));
79
86
  }
80
87
 
@@ -162,6 +169,11 @@ export class AztecKVTxPoolV2 extends (EventEmitter as new () => TypedEventEmitte
162
169
  return this.#queue.put(() => Promise.resolve(this.#impl.getLowestPriorityPending(limit)));
163
170
  }
164
171
 
172
+ /** Returns read-only access to the pool. Used for testing. */
173
+ getPoolReadAccess(): PoolReadAccess {
174
+ return this.#impl.getPoolReadAccess();
175
+ }
176
+
165
177
  // === Configuration ===
166
178
 
167
179
  updateConfig(config: Partial<TxPoolV2Config>): Promise<void> {