@aztec/pxe 5.0.0-rc.1 → 5.0.0-rc.2

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 (218) hide show
  1. package/dest/block_synchronizer/block_stream_source.d.ts +5 -5
  2. package/dest/block_synchronizer/block_stream_source.d.ts.map +1 -1
  3. package/dest/block_synchronizer/block_stream_source.js +4 -29
  4. package/dest/block_synchronizer/block_synchronizer.d.ts +13 -11
  5. package/dest/block_synchronizer/block_synchronizer.d.ts.map +1 -1
  6. package/dest/block_synchronizer/block_synchronizer.js +43 -15
  7. package/dest/config/index.d.ts +2 -1
  8. package/dest/config/index.d.ts.map +1 -1
  9. package/dest/config/index.js +1 -0
  10. package/dest/contract_function_simulator/contract_function_simulator.d.ts +11 -16
  11. package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
  12. package/dest/contract_function_simulator/contract_function_simulator.js +22 -18
  13. package/dest/contract_function_simulator/index.d.ts +15 -9
  14. package/dest/contract_function_simulator/index.d.ts.map +1 -1
  15. package/dest/contract_function_simulator/index.js +3 -7
  16. package/dest/contract_function_simulator/noir-structs/bounded_vec.d.ts +8 -27
  17. package/dest/contract_function_simulator/noir-structs/bounded_vec.d.ts.map +1 -1
  18. package/dest/contract_function_simulator/noir-structs/bounded_vec.js +8 -23
  19. package/dest/contract_function_simulator/noir-structs/contract_class_log_data.d.ts +9 -0
  20. package/dest/contract_function_simulator/noir-structs/contract_class_log_data.d.ts.map +1 -0
  21. package/dest/contract_function_simulator/noir-structs/contract_class_log_data.js +1 -0
  22. package/dest/contract_function_simulator/noir-structs/embedded_curve_point.d.ts +7 -0
  23. package/dest/contract_function_simulator/noir-structs/embedded_curve_point.d.ts.map +1 -0
  24. package/dest/contract_function_simulator/noir-structs/embedded_curve_point.js +1 -0
  25. package/dest/contract_function_simulator/noir-structs/event_validation_request.js +1 -1
  26. package/dest/contract_function_simulator/noir-structs/fact.d.ts +16 -0
  27. package/dest/contract_function_simulator/noir-structs/fact.d.ts.map +1 -0
  28. package/dest/contract_function_simulator/noir-structs/fact.js +6 -0
  29. package/dest/contract_function_simulator/noir-structs/fact_collection.d.ts +27 -0
  30. package/dest/contract_function_simulator/noir-structs/fact_collection.d.ts.map +1 -0
  31. package/dest/contract_function_simulator/noir-structs/fact_collection.js +29 -0
  32. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.d.ts +11 -12
  33. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.d.ts.map +1 -1
  34. package/dest/contract_function_simulator/noir-structs/log_retrieval_request.js +6 -49
  35. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts +4 -8
  36. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.d.ts.map +1 -1
  37. package/dest/contract_function_simulator/noir-structs/log_retrieval_response.js +1 -60
  38. package/dest/contract_function_simulator/noir-structs/note_validation_request.js +2 -2
  39. package/dest/contract_function_simulator/noir-structs/option.d.ts +9 -11
  40. package/dest/contract_function_simulator/noir-structs/option.d.ts.map +1 -1
  41. package/dest/contract_function_simulator/noir-structs/option.js +18 -13
  42. package/dest/contract_function_simulator/noir-structs/origin_block.d.ts +11 -0
  43. package/dest/contract_function_simulator/noir-structs/origin_block.d.ts.map +1 -0
  44. package/dest/contract_function_simulator/noir-structs/origin_block.js +5 -0
  45. package/dest/contract_function_simulator/noir-structs/provided_secret.d.ts +5 -8
  46. package/dest/contract_function_simulator/noir-structs/provided_secret.d.ts.map +1 -1
  47. package/dest/contract_function_simulator/noir-structs/provided_secret.js +1 -14
  48. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.d.ts +21 -0
  49. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.d.ts.map +1 -0
  50. package/dest/contract_function_simulator/noir-structs/resolved_tagging_strategy.js +33 -0
  51. package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts +21 -0
  52. package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts.map +1 -0
  53. package/dest/contract_function_simulator/noir-structs/resolved_tx.js +50 -0
  54. package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts +14 -0
  55. package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts.map +1 -0
  56. package/dest/contract_function_simulator/noir-structs/tx_effect_data.js +5 -0
  57. package/dest/contract_function_simulator/noir-structs/utility_context.d.ts +6 -11
  58. package/dest/contract_function_simulator/noir-structs/utility_context.d.ts.map +1 -1
  59. package/dest/contract_function_simulator/noir-structs/utility_context.js +1 -20
  60. package/dest/contract_function_simulator/oracle/message_load_oracle_inputs.d.ts +3 -14
  61. package/dest/contract_function_simulator/oracle/message_load_oracle_inputs.d.ts.map +1 -1
  62. package/dest/contract_function_simulator/oracle/message_load_oracle_inputs.js +1 -24
  63. package/dest/contract_function_simulator/oracle/oracle_registry.d.ts +81 -6
  64. package/dest/contract_function_simulator/oracle/oracle_registry.d.ts.map +1 -1
  65. package/dest/contract_function_simulator/oracle/oracle_registry.js +128 -9
  66. package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts +80 -36
  67. package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts.map +1 -1
  68. package/dest/contract_function_simulator/oracle/oracle_type_mappings.js +926 -264
  69. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +13 -8
  70. package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
  71. package/dest/contract_function_simulator/oracle/private_execution_oracle.js +80 -11
  72. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +46 -20
  73. package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
  74. package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +119 -55
  75. package/dest/contract_sync/helpers.d.ts +7 -6
  76. package/dest/contract_sync/helpers.d.ts.map +1 -1
  77. package/dest/contract_sync/helpers.js +11 -16
  78. package/dest/entrypoints/client/bundle/utils.d.ts +1 -1
  79. package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
  80. package/dest/entrypoints/client/bundle/utils.js +1 -0
  81. package/dest/entrypoints/client/lazy/utils.d.ts +1 -1
  82. package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
  83. package/dest/entrypoints/client/lazy/utils.js +1 -0
  84. package/dest/entrypoints/pxe_creation_options.d.ts +8 -2
  85. package/dest/entrypoints/pxe_creation_options.d.ts.map +1 -1
  86. package/dest/entrypoints/server/index.d.ts +1 -2
  87. package/dest/entrypoints/server/index.d.ts.map +1 -1
  88. package/dest/entrypoints/server/index.js +0 -1
  89. package/dest/entrypoints/server/utils.d.ts +1 -1
  90. package/dest/entrypoints/server/utils.d.ts.map +1 -1
  91. package/dest/entrypoints/server/utils.js +3 -1
  92. package/dest/error_enriching.js +1 -1
  93. package/dest/hooks/execution_hooks.d.ts +16 -7
  94. package/dest/hooks/execution_hooks.d.ts.map +1 -1
  95. package/dest/hooks/execution_hooks.js +3 -3
  96. package/dest/hooks/index.d.ts +3 -3
  97. package/dest/hooks/index.d.ts.map +1 -1
  98. package/dest/hooks/resolve_tagging_secret_strategy.d.ts +41 -0
  99. package/dest/hooks/resolve_tagging_secret_strategy.d.ts.map +1 -0
  100. package/dest/hooks/resolve_tagging_secret_strategy.js +3 -0
  101. package/dest/logs/log_service.d.ts +6 -6
  102. package/dest/logs/log_service.d.ts.map +1 -1
  103. package/dest/logs/log_service.js +62 -28
  104. package/dest/messages/tx_resolver_service.d.ts +17 -0
  105. package/dest/messages/tx_resolver_service.d.ts.map +1 -0
  106. package/dest/messages/{message_context_service.js → tx_resolver_service.js} +8 -8
  107. package/dest/oracle_version.d.ts +2 -2
  108. package/dest/oracle_version.js +2 -2
  109. package/dest/private_kernel/hints/test_utils.js +1 -1
  110. package/dest/pxe.d.ts +46 -19
  111. package/dest/pxe.d.ts.map +1 -1
  112. package/dest/pxe.js +104 -52
  113. package/dest/storage/allowed_scopes.d.ts +6 -0
  114. package/dest/storage/allowed_scopes.d.ts.map +1 -0
  115. package/dest/storage/allowed_scopes.js +7 -0
  116. package/dest/storage/backwards_compatibility_tests/schema_tests.d.ts +1 -1
  117. package/dest/storage/backwards_compatibility_tests/schema_tests.d.ts.map +1 -1
  118. package/dest/storage/backwards_compatibility_tests/schema_tests.js +86 -33
  119. package/dest/storage/capsule_store/capsule_service.d.ts +1 -1
  120. package/dest/storage/capsule_store/capsule_service.d.ts.map +1 -1
  121. package/dest/storage/capsule_store/capsule_service.js +6 -9
  122. package/dest/storage/contract_store/contract_store.js +2 -2
  123. package/dest/storage/fact_store/fact_service.d.ts +20 -0
  124. package/dest/storage/fact_store/fact_service.d.ts.map +1 -0
  125. package/dest/storage/fact_store/fact_service.js +30 -0
  126. package/dest/storage/fact_store/fact_store.d.ts +95 -0
  127. package/dest/storage/fact_store/fact_store.d.ts.map +1 -0
  128. package/dest/storage/fact_store/fact_store.js +408 -0
  129. package/dest/storage/fact_store/fact_store_keys.d.ts +34 -0
  130. package/dest/storage/fact_store/fact_store_keys.d.ts.map +1 -0
  131. package/dest/storage/fact_store/fact_store_keys.js +50 -0
  132. package/dest/storage/fact_store/index.d.ts +5 -0
  133. package/dest/storage/fact_store/index.d.ts.map +1 -0
  134. package/dest/storage/fact_store/index.js +3 -0
  135. package/dest/storage/fact_store/stored_fact.d.ts +32 -0
  136. package/dest/storage/fact_store/stored_fact.d.ts.map +1 -0
  137. package/dest/storage/fact_store/stored_fact.js +64 -0
  138. package/dest/storage/index.d.ts +2 -1
  139. package/dest/storage/index.d.ts.map +1 -1
  140. package/dest/storage/index.js +1 -0
  141. package/dest/storage/metadata.d.ts +1 -1
  142. package/dest/storage/metadata.js +1 -1
  143. package/dest/storage/open_pxe_stores.d.ts +5 -3
  144. package/dest/storage/open_pxe_stores.d.ts.map +1 -1
  145. package/dest/storage/open_pxe_stores.js +5 -3
  146. package/dest/storage/tagging_store/index.d.ts +2 -2
  147. package/dest/storage/tagging_store/index.d.ts.map +1 -1
  148. package/dest/storage/tagging_store/index.js +1 -1
  149. package/dest/storage/tagging_store/tagging_secret_sources_store.d.ts +40 -0
  150. package/dest/storage/tagging_store/tagging_secret_sources_store.d.ts.map +1 -0
  151. package/dest/storage/tagging_store/tagging_secret_sources_store.js +92 -0
  152. package/package.json +17 -17
  153. package/src/block_synchronizer/block_stream_source.ts +6 -45
  154. package/src/block_synchronizer/block_synchronizer.ts +56 -23
  155. package/src/config/index.ts +1 -0
  156. package/src/contract_function_simulator/contract_function_simulator.ts +32 -31
  157. package/src/contract_function_simulator/index.ts +17 -8
  158. package/src/contract_function_simulator/noir-structs/bounded_vec.ts +12 -24
  159. package/src/contract_function_simulator/noir-structs/contract_class_log_data.ts +9 -0
  160. package/src/contract_function_simulator/noir-structs/embedded_curve_point.ts +4 -0
  161. package/src/contract_function_simulator/noir-structs/event_validation_request.ts +1 -1
  162. package/src/contract_function_simulator/noir-structs/fact.ts +13 -0
  163. package/src/contract_function_simulator/noir-structs/fact_collection.ts +59 -0
  164. package/src/contract_function_simulator/noir-structs/log_retrieval_request.ts +20 -46
  165. package/src/contract_function_simulator/noir-structs/log_retrieval_response.ts +7 -60
  166. package/src/contract_function_simulator/noir-structs/note_validation_request.ts +2 -2
  167. package/src/contract_function_simulator/noir-structs/option.ts +17 -11
  168. package/src/contract_function_simulator/noir-structs/origin_block.ts +8 -0
  169. package/src/contract_function_simulator/noir-structs/provided_secret.ts +3 -14
  170. package/src/contract_function_simulator/noir-structs/resolved_tagging_strategy.ts +45 -0
  171. package/src/contract_function_simulator/noir-structs/resolved_tx.ts +53 -0
  172. package/src/contract_function_simulator/noir-structs/tx_effect_data.ts +15 -0
  173. package/src/contract_function_simulator/noir-structs/utility_context.ts +5 -17
  174. package/src/contract_function_simulator/oracle/message_load_oracle_inputs.ts +6 -21
  175. package/src/contract_function_simulator/oracle/oracle_registry.ts +87 -79
  176. package/src/contract_function_simulator/oracle/oracle_type_mappings.ts +641 -247
  177. package/src/contract_function_simulator/oracle/private_execution_oracle.ts +94 -14
  178. package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +206 -66
  179. package/src/contract_sync/helpers.ts +11 -18
  180. package/src/entrypoints/client/bundle/utils.ts +1 -0
  181. package/src/entrypoints/client/lazy/utils.ts +1 -0
  182. package/src/entrypoints/pxe_creation_options.ts +7 -1
  183. package/src/entrypoints/server/index.ts +0 -1
  184. package/src/entrypoints/server/utils.ts +3 -1
  185. package/src/error_enriching.ts +1 -1
  186. package/src/hooks/execution_hooks.ts +17 -8
  187. package/src/hooks/index.ts +6 -2
  188. package/src/hooks/resolve_tagging_secret_strategy.ts +46 -0
  189. package/src/logs/log_service.ts +71 -37
  190. package/src/messages/{message_context_service.ts → tx_resolver_service.ts} +16 -9
  191. package/src/oracle_version.ts +2 -2
  192. package/src/private_kernel/hints/test_utils.ts +1 -1
  193. package/src/pxe.ts +150 -54
  194. package/src/storage/allowed_scopes.ts +14 -0
  195. package/src/storage/backwards_compatibility_tests/__snapshots__/FactStore.json +40 -0
  196. package/src/storage/backwards_compatibility_tests/__snapshots__/L2TipsKVStore.json +1 -1
  197. package/src/storage/backwards_compatibility_tests/__snapshots__/TaggingSecretSourcesStore.json +30 -0
  198. package/src/storage/backwards_compatibility_tests/__snapshots__/opened_stores.json +21 -5
  199. package/src/storage/backwards_compatibility_tests/schema_tests.ts +88 -33
  200. package/src/storage/capsule_store/capsule_service.ts +8 -13
  201. package/src/storage/contract_store/contract_store.ts +2 -2
  202. package/src/storage/fact_store/fact_service.ts +45 -0
  203. package/src/storage/fact_store/fact_store.ts +487 -0
  204. package/src/storage/fact_store/fact_store_keys.ts +75 -0
  205. package/src/storage/fact_store/index.ts +4 -0
  206. package/src/storage/fact_store/stored_fact.ts +80 -0
  207. package/src/storage/index.ts +1 -0
  208. package/src/storage/metadata.ts +1 -1
  209. package/src/storage/open_pxe_stores.ts +6 -3
  210. package/src/storage/tagging_store/index.ts +1 -1
  211. package/src/storage/tagging_store/tagging_secret_sources_store.ts +117 -0
  212. package/dest/messages/message_context_service.d.ts +0 -17
  213. package/dest/messages/message_context_service.d.ts.map +0 -1
  214. package/dest/storage/tagging_store/sender_address_book_store.d.ts +0 -14
  215. package/dest/storage/tagging_store/sender_address_book_store.d.ts.map +0 -1
  216. package/dest/storage/tagging_store/sender_address_book_store.js +0 -36
  217. package/src/storage/backwards_compatibility_tests/__snapshots__/SenderAddressBookStore.json +0 -16
  218. package/src/storage/tagging_store/sender_address_book_store.ts +0 -48
@@ -1,4 +1,5 @@
1
1
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
2
+ import { assertAllowedScope } from '../allowed_scopes.js';
2
3
  /**
3
4
  * Wraps a CapsuleStore with scope-based access control. Each operation asserts that the requested scope is in the
4
5
  * allowed scopes list before delegating to the underlying store.
@@ -7,7 +8,11 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address';
7
8
  allowedScopes;
8
9
  constructor(capsuleStore, allowedScopes){
9
10
  this.capsuleStore = capsuleStore;
10
- this.allowedScopes = allowedScopes;
11
+ // The zero address denotes the global capsule scope, which is always permitted.
12
+ this.allowedScopes = [
13
+ ...allowedScopes,
14
+ AztecAddress.ZERO
15
+ ];
11
16
  }
12
17
  setCapsule(contractAddress, slot, capsule, jobId, scope) {
13
18
  assertAllowedScope(scope, this.allowedScopes);
@@ -40,11 +45,3 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address';
40
45
  return this.capsuleStore.setCapsuleArray(contractAddress, baseSlot, content, jobId, scope);
41
46
  }
42
47
  }
43
- function assertAllowedScope(scope, allowedScopes) {
44
- if (scope.equals(AztecAddress.ZERO)) {
45
- return;
46
- }
47
- if (!allowedScopes.some((allowed)=>allowed.equals(scope))) {
48
- throw new Error(`Scope ${scope.toString()} is not in the allowed scopes list: [${allowedScopes.map((s)=>s.toString()).join(', ')}]. See https://docs.aztec.network/errors/10`);
49
- }
50
- }
@@ -135,7 +135,7 @@ const VERSION = 1;
135
135
  getContractsAddresses() {
136
136
  return this.#store.transactionAsync(async ()=>{
137
137
  const keys = await toArray(this.#contractInstances.keysAsync());
138
- return keys.map(AztecAddress.fromString);
138
+ return keys.map(AztecAddress.fromStringUnsafe);
139
139
  });
140
140
  }
141
141
  /** Returns a contract instance for a given address. */ getContractInstance(contractAddress) {
@@ -271,7 +271,7 @@ const VERSION = 1;
271
271
  async getFunctionCall(functionName, args, to) {
272
272
  const contract = await this.getContract(to);
273
273
  if (!contract) {
274
- throw new Error(`Unknown contract ${to}: add it to PXE by calling server.addContracts(...).\nSee docs for context: https://docs.aztec.network/developers/resources/debugging/aztecnr-errors#unknown-contract-0x0-add-it-to-pxe-by-calling-serveraddcontracts`);
274
+ throw new Error(`Unknown contract ${to}: register it by calling wallet.registerContract(...).\nSee docs for context: https://docs.aztec.network/errors/14`);
275
275
  }
276
276
  const functionDao = contract.functions.find((f)=>f.name === functionName);
277
277
  if (!functionDao) {
@@ -0,0 +1,20 @@
1
+ import type { Fr } from '@aztec/foundation/curves/bn254';
2
+ import type { AztecAddress } from '@aztec/stdlib/aztec-address';
3
+ import type { FactCollection, FactStore } from './fact_store.js';
4
+ import type { FactCollectionKey, FactCollectionTypeKey, OriginBlock } from './fact_store_keys.js';
5
+ /**
6
+ * Wraps a {@link FactStore} with scope-based access control.
7
+ *
8
+ * Each method asserts scope validity before delegating to FactStore, gating which accounts a contract may record facts
9
+ * under or read facts from.
10
+ */
11
+ export declare class FactService {
12
+ private readonly factStore;
13
+ private readonly allowedScopes;
14
+ constructor(factStore: FactStore, allowedScopes: AztecAddress[]);
15
+ recordFact(factCollectionKey: FactCollectionKey, factTypeId: Fr, payload: Fr[], originBlock: OriginBlock | undefined, jobId: string): Promise<void>;
16
+ deleteFactCollection(factCollectionKey: FactCollectionKey, jobId: string): Promise<void>;
17
+ getFactCollection(factCollectionKey: FactCollectionKey, jobId: string): Promise<FactCollection | undefined>;
18
+ getFactCollectionsByType(factCollectionTypeKey: FactCollectionTypeKey, jobId: string): Promise<FactCollection[]>;
19
+ }
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdF9zZXJ2aWNlLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3RvcmFnZS9mYWN0X3N0b3JlL2ZhY3Rfc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUN6RCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUdoRSxPQUFPLEtBQUssRUFBRSxjQUFjLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDakUsT0FBTyxLQUFLLEVBQUUsaUJBQWlCLEVBQUUscUJBQXFCLEVBQUUsV0FBVyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFbEc7Ozs7O0dBS0c7QUFDSCxxQkFBYSxXQUFXO0lBRXBCLE9BQU8sQ0FBQyxRQUFRLENBQUMsU0FBUztJQUMxQixPQUFPLENBQUMsUUFBUSxDQUFDLGFBQWE7SUFGaEMsWUFDbUIsU0FBUyxFQUFFLFNBQVMsRUFDcEIsYUFBYSxFQUFFLFlBQVksRUFBRSxFQUM1QztJQUVKLFVBQVUsQ0FDUixpQkFBaUIsRUFBRSxpQkFBaUIsRUFDcEMsVUFBVSxFQUFFLEVBQUUsRUFDZCxPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQ2IsV0FBVyxFQUFFLFdBQVcsR0FBRyxTQUFTLEVBQ3BDLEtBQUssRUFBRSxNQUFNLEdBQ1osT0FBTyxDQUFDLElBQUksQ0FBQyxDQUdmO0lBRUQsb0JBQW9CLENBQUMsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBR3ZGO0lBRUQsaUJBQWlCLENBQUMsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsY0FBYyxHQUFHLFNBQVMsQ0FBQyxDQUcxRztJQUVELHdCQUF3QixDQUFDLHFCQUFxQixFQUFFLHFCQUFxQixFQUFFLEtBQUssRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLGNBQWMsRUFBRSxDQUFDLENBRy9HO0NBQ0YifQ==
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fact_service.d.ts","sourceRoot":"","sources":["../../../src/storage/fact_store/fact_service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAElG;;;;;GAKG;AACH,qBAAa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAFhC,YACmB,SAAS,EAAE,SAAS,EACpB,aAAa,EAAE,YAAY,EAAE,EAC5C;IAEJ,UAAU,CACR,iBAAiB,EAAE,iBAAiB,EACpC,UAAU,EAAE,EAAE,EACd,OAAO,EAAE,EAAE,EAAE,EACb,WAAW,EAAE,WAAW,GAAG,SAAS,EACpC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAGf;IAED,oBAAoB,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvF;IAED,iBAAiB,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAG1G;IAED,wBAAwB,CAAC,qBAAqB,EAAE,qBAAqB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAG/G;CACF"}
@@ -0,0 +1,30 @@
1
+ import { assertAllowedScope } from '../allowed_scopes.js';
2
+ /**
3
+ * Wraps a {@link FactStore} with scope-based access control.
4
+ *
5
+ * Each method asserts scope validity before delegating to FactStore, gating which accounts a contract may record facts
6
+ * under or read facts from.
7
+ */ export class FactService {
8
+ factStore;
9
+ allowedScopes;
10
+ constructor(factStore, allowedScopes){
11
+ this.factStore = factStore;
12
+ this.allowedScopes = allowedScopes;
13
+ }
14
+ recordFact(factCollectionKey, factTypeId, payload, originBlock, jobId) {
15
+ assertAllowedScope(factCollectionKey.scope, this.allowedScopes);
16
+ return this.factStore.recordFact(factCollectionKey, factTypeId, payload, originBlock, jobId);
17
+ }
18
+ deleteFactCollection(factCollectionKey, jobId) {
19
+ assertAllowedScope(factCollectionKey.scope, this.allowedScopes);
20
+ return this.factStore.deleteFactCollection(factCollectionKey, jobId);
21
+ }
22
+ getFactCollection(factCollectionKey, jobId) {
23
+ assertAllowedScope(factCollectionKey.scope, this.allowedScopes);
24
+ return this.factStore.getFactCollection(factCollectionKey, jobId);
25
+ }
26
+ getFactCollectionsByType(factCollectionTypeKey, jobId) {
27
+ assertAllowedScope(factCollectionTypeKey.scope, this.allowedScopes);
28
+ return this.factStore.getFactCollectionsByType(factCollectionTypeKey, jobId);
29
+ }
30
+ }
@@ -0,0 +1,95 @@
1
+ import type { Fr } from '@aztec/foundation/curves/bn254';
2
+ import type { AztecAsyncKVStore } from '@aztec/kv-store';
3
+ import type { StagedStore } from '../../job_coordinator/job_coordinator.js';
4
+ import { FactCollectionKey, type FactCollectionTypeKey, type OriginBlock } from './fact_store_keys.js';
5
+ import { type Fact } from './stored_fact.js';
6
+ type BlockNum = number;
7
+ /** A fact collection as returned by the store. */
8
+ export type FactCollection = {
9
+ key: FactCollectionKey;
10
+ facts: Fact[];
11
+ };
12
+ /**
13
+ * Stores immutable facts grouped into collections, isolated by contract and scope.
14
+ *
15
+ * A fact collection is a contract-defined bag of facts identified by a {@link FactCollectionKey} (contract, scope,
16
+ * collection type, and id). A fact is a contract-defined immutable, typed datum in a collection. Collections are
17
+ * implicit: one comes into being when its first fact is recorded and ceases to exist once it has no facts left.
18
+ *
19
+ * What makes this store different to, for example, the `CapsuleStore`, is that it is designed to support use cases
20
+ * where resilience to reorgs is needed, via what we call _retractability_.
21
+ *
22
+ * Facts can be retractable or non-retractable. They are retractable if they are associated to an origin block.
23
+ * Retractable facts are removed from the store when their origin block is pruned (typically due to a reorg).
24
+ * Non-retractable facts survive reorgs: they must then be explicitly deleted, so as not to keep consuming resources
25
+ * (storage and compute) indefinitely.
26
+ *
27
+ * Fact collections are isolated by scope.
28
+ *
29
+ * This store is designed to enable Aztec.nr to implement complex workflows such as offchain reception or partial note
30
+ * processing by storing structured data that is guaranteed to exist conditionally to specific blocks being included in
31
+ * the chain, while leaving the complexity of ensuring said guarantees to PXE.
32
+ *
33
+ * A key design driver is that PXE knows nothing about the actual fact contents: it just manages enough metadata to
34
+ * provide the guarantees mentioned above. That way, concepts such as offchain delivery or partial notes are completely
35
+ * defined by Aztec.nr, opening the door to further extension without the need for ad-hoc PXE support.
36
+ *
37
+ * As with most other PXE stores, writes are staged per-job and flushed atomically on commit.
38
+ */
39
+ export declare class FactStore implements StagedStore {
40
+ #private;
41
+ readonly storeName: string;
42
+ logger: import("@aztec/foundation/log").Logger;
43
+ constructor(store: AztecAsyncKVStore);
44
+ /**
45
+ * Records a fact in a collection.
46
+ *
47
+ * The collection is created implicitly on the first fact recorded for its key: recording into an existing collection
48
+ * just adds to it.
49
+ *
50
+ * If `originBlock === undefined`, the fact is non-retractable: it survives reorgs. A defined origin block makes the
51
+ * fact retractable: on a prune below its block, it will be deleted.
52
+ *
53
+ * Idempotent: re-recording an identical fact (same collection, fact type, payload, and origin block) is a no-op.
54
+ * The same payload tied to a different origin block is a distinct fact.
55
+ */
56
+ recordFact(factCollectionKey: FactCollectionKey, factTypeId: Fr, payload: Fr[], originBlock: OriginBlock | undefined, jobId: string): Promise<void>;
57
+ /**
58
+ * Deletes a fact collection: removes every fact under the (scope-qualified) collection key.
59
+ *
60
+ * Idempotent: deleting a collection that does not exist is a no-op.
61
+ */
62
+ deleteFactCollection(factCollectionKey: FactCollectionKey, jobId: string): Promise<void>;
63
+ /**
64
+ * Returns the fact collection for the (scope-qualified) key, or undefined if it has no facts.
65
+ */
66
+ getFactCollection(factCollectionKey: FactCollectionKey, jobId: string): Promise<FactCollection | undefined>;
67
+ /**
68
+ * Returns every fact collection of the given type for the queried scope, each holding its facts.
69
+ */
70
+ getFactCollectionsByType(factCollectionTypeKey: FactCollectionTypeKey, jobId: string): Promise<FactCollection[]>;
71
+ /**
72
+ * Commits all staged operations for the given job to persistent storage.
73
+ *
74
+ * Must be called inside a transaction owned by the caller (JobCoordinator wraps all commits in a single
75
+ * transactionAsync, and IndexedDB does not support nested transactions).
76
+ *
77
+ * DO NOT call `#withJobLock` here: awaiting the lock creates a microtask boundary that causes IndexedDB to
78
+ * auto-commit the outer transaction.
79
+ */
80
+ commit(jobId: string): Promise<void>;
81
+ /** Discards all staged operations for the given job without persisting them. */
82
+ discardStaged(jobId: string): Promise<void>;
83
+ /**
84
+ * Removes every retractable fact originating from blocks over height `toBlock`, across all scopes.
85
+ *
86
+ * Non-retractable facts are untouched. Must run inside a caller-owned transaction (because it needs to share the
87
+ * transaction with other stores and IndexedDB has no nested transactions).
88
+ *
89
+ * Throws if any job is in flight (has accessed the store and not yet committed or discarded), since rolling back
90
+ * mid-job could re-introduce records originating from deleted blocks or change state underneath a job's view.
91
+ */
92
+ rollback(toBlock: BlockNum): Promise<void>;
93
+ }
94
+ export {};
95
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdF9zdG9yZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3N0b3JhZ2UvZmFjdF9zdG9yZS9mYWN0X3N0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBR3pELE9BQU8sS0FBSyxFQUFFLGlCQUFpQixFQUFxQyxNQUFNLGlCQUFpQixDQUFDO0FBRTVGLE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLDBDQUEwQyxDQUFDO0FBQzVFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxLQUFLLHFCQUFxQixFQUFFLEtBQUssV0FBVyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdkcsT0FBTyxFQUFFLEtBQUssSUFBSSxFQUE0QixNQUFNLGtCQUFrQixDQUFDO0FBR3ZFLEtBQUssUUFBUSxHQUFHLE1BQU0sQ0FBQztBQU12QixrREFBa0Q7QUFDbEQsTUFBTSxNQUFNLGNBQWMsR0FBRztJQUFFLEdBQUcsRUFBRSxpQkFBaUIsQ0FBQztJQUFDLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQTtDQUFFLENBQUM7QUFRdkU7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMEJHO0FBQ0gscUJBQWEsU0FBVSxZQUFXLFdBQVc7O0lBQzNDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFVO0lBbUJwQyxNQUFNLHlDQUE4QjtJQUVwQyxZQUFZLEtBQUssRUFBRSxpQkFBaUIsRUFPbkM7SUFFRDs7Ozs7Ozs7Ozs7T0FXRztJQUNILFVBQVUsQ0FDUixpQkFBaUIsRUFBRSxpQkFBaUIsRUFDcEMsVUFBVSxFQUFFLEVBQUUsRUFDZCxPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQ2IsV0FBVyxFQUFFLFdBQVcsR0FBRyxTQUFTLEVBQ3BDLEtBQUssRUFBRSxNQUFNLEdBQ1osT0FBTyxDQUFDLElBQUksQ0FBQyxDQVFmO0lBRUQ7Ozs7T0FJRztJQUNILG9CQUFvQixDQUFDLGlCQUFpQixFQUFFLGlCQUFpQixFQUFFLEtBQUssRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUt2RjtJQUVEOztPQUVHO0lBQ0csaUJBQWlCLENBQUMsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsY0FBYyxHQUFHLFNBQVMsQ0FBQyxDQVVoSDtJQUVEOztPQUVHO0lBQ0csd0JBQXdCLENBQzVCLHFCQUFxQixFQUFFLHFCQUFxQixFQUM1QyxLQUFLLEVBQUUsTUFBTSxHQUNaLE9BQU8sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQU8zQjtJQUVEOzs7Ozs7OztPQVFHO0lBQ0csTUFBTSxDQUFDLEtBQUssRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQWdCekM7SUFFRCxnRkFBZ0Y7SUFDaEYsYUFBYSxDQUFDLEtBQUssRUFBRSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUcxQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0csUUFBUSxDQUFDLE9BQU8sRUFBRSxRQUFRLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQVEvQztDQTJSRiJ9
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fact_store.d.ts","sourceRoot":"","sources":["../../../src/storage/fact_store/fact_store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAGzD,OAAO,KAAK,EAAE,iBAAiB,EAAqC,MAAM,iBAAiB,CAAC;AAE5F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0CAA0C,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,KAAK,qBAAqB,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACvG,OAAO,EAAE,KAAK,IAAI,EAA4B,MAAM,kBAAkB,CAAC;AAGvE,KAAK,QAAQ,GAAG,MAAM,CAAC;AAMvB,kDAAkD;AAClD,MAAM,MAAM,cAAc,GAAG;IAAE,GAAG,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC;AAQvE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,SAAU,YAAW,WAAW;;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAU;IAmBpC,MAAM,yCAA8B;IAEpC,YAAY,KAAK,EAAE,iBAAiB,EAOnC;IAED;;;;;;;;;;;OAWG;IACH,UAAU,CACR,iBAAiB,EAAE,iBAAiB,EACpC,UAAU,EAAE,EAAE,EACd,OAAO,EAAE,EAAE,EAAE,EACb,WAAW,EAAE,WAAW,GAAG,SAAS,EACpC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAQf;IAED;;;;OAIG;IACH,oBAAoB,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvF;IAED;;OAEG;IACG,iBAAiB,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC,CAUhH;IAED;;OAEG;IACG,wBAAwB,CAC5B,qBAAqB,EAAE,qBAAqB,EAC5C,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,EAAE,CAAC,CAO3B;IAED;;;;;;;;OAQG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBzC;IAED,gFAAgF;IAChF,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1C;IAED;;;;;;;;OAQG;IACG,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ/C;CA2RF"}
@@ -0,0 +1,408 @@
1
+ import { createLogger } from '@aztec/foundation/log';
2
+ import { Semaphore } from '@aztec/foundation/queue';
3
+ import { FactCollectionKey } from './fact_store_keys.js';
4
+ import { StoredFact, factKeyStrOf } from './stored_fact.js';
5
+ /**
6
+ * Stores immutable facts grouped into collections, isolated by contract and scope.
7
+ *
8
+ * A fact collection is a contract-defined bag of facts identified by a {@link FactCollectionKey} (contract, scope,
9
+ * collection type, and id). A fact is a contract-defined immutable, typed datum in a collection. Collections are
10
+ * implicit: one comes into being when its first fact is recorded and ceases to exist once it has no facts left.
11
+ *
12
+ * What makes this store different to, for example, the `CapsuleStore`, is that it is designed to support use cases
13
+ * where resilience to reorgs is needed, via what we call _retractability_.
14
+ *
15
+ * Facts can be retractable or non-retractable. They are retractable if they are associated to an origin block.
16
+ * Retractable facts are removed from the store when their origin block is pruned (typically due to a reorg).
17
+ * Non-retractable facts survive reorgs: they must then be explicitly deleted, so as not to keep consuming resources
18
+ * (storage and compute) indefinitely.
19
+ *
20
+ * Fact collections are isolated by scope.
21
+ *
22
+ * This store is designed to enable Aztec.nr to implement complex workflows such as offchain reception or partial note
23
+ * processing by storing structured data that is guaranteed to exist conditionally to specific blocks being included in
24
+ * the chain, while leaving the complexity of ensuring said guarantees to PXE.
25
+ *
26
+ * A key design driver is that PXE knows nothing about the actual fact contents: it just manages enough metadata to
27
+ * provide the guarantees mentioned above. That way, concepts such as offchain delivery or partial notes are completely
28
+ * defined by Aztec.nr, opening the door to further extension without the need for ad-hoc PXE support.
29
+ *
30
+ * As with most other PXE stores, writes are staged per-job and flushed atomically on commit.
31
+ */ export class FactStore {
32
+ storeName = 'fact';
33
+ #store;
34
+ /** Primary index of fact records. */ #facts;
35
+ /** Index for per-collection fact enumeration and by-type collection discovery. */ #factsByCollection;
36
+ /** Index for delete-on-prune of retractable facts (those with an origin block). */ #factsByBlock;
37
+ /** Job uncommitted data */ #opsForJob;
38
+ /** Per-job locks */ #jobLocks;
39
+ logger = createLogger('fact_store');
40
+ constructor(store){
41
+ this.#store = store;
42
+ this.#facts = store.openMap('facts');
43
+ this.#factsByCollection = store.openMultiMap('facts_by_collection');
44
+ this.#factsByBlock = store.openMultiMap('facts_by_block');
45
+ this.#opsForJob = new Map();
46
+ this.#jobLocks = new Map();
47
+ }
48
+ /**
49
+ * Records a fact in a collection.
50
+ *
51
+ * The collection is created implicitly on the first fact recorded for its key: recording into an existing collection
52
+ * just adds to it.
53
+ *
54
+ * If `originBlock === undefined`, the fact is non-retractable: it survives reorgs. A defined origin block makes the
55
+ * fact retractable: on a prune below its block, it will be deleted.
56
+ *
57
+ * Idempotent: re-recording an identical fact (same collection, fact type, payload, and origin block) is a no-op.
58
+ * The same payload tied to a different origin block is a distinct fact.
59
+ */ recordFact(factCollectionKey, factTypeId, payload, originBlock, jobId) {
60
+ return this.#withJobLock(jobId, ()=>{
61
+ this.#stagedOpsFor(jobId).push({
62
+ kind: 'recordFact',
63
+ fact: new StoredFact(factCollectionKey, factTypeId, payload, originBlock)
64
+ });
65
+ return Promise.resolve();
66
+ });
67
+ }
68
+ /**
69
+ * Deletes a fact collection: removes every fact under the (scope-qualified) collection key.
70
+ *
71
+ * Idempotent: deleting a collection that does not exist is a no-op.
72
+ */ deleteFactCollection(factCollectionKey, jobId) {
73
+ return this.#withJobLock(jobId, ()=>{
74
+ this.#stagedOpsFor(jobId).push({
75
+ kind: 'deleteFactCollection',
76
+ key: factCollectionKey
77
+ });
78
+ return Promise.resolve();
79
+ });
80
+ }
81
+ /**
82
+ * Returns the fact collection for the (scope-qualified) key, or undefined if it has no facts.
83
+ */ async getFactCollection(factCollectionKey, jobId) {
84
+ const collectionKey = factCollectionKey.toString();
85
+ const committed = await this.#store.transactionAsync(()=>this.#readCollectionsFromDb([
86
+ factCollectionKey
87
+ ]));
88
+ const collection = this.#foldStagedOps(committed, jobId).get(collectionKey);
89
+ if (!collection) {
90
+ return undefined;
91
+ }
92
+ const facts = [
93
+ ...collection.facts.values()
94
+ ];
95
+ return facts.length > 0 ? {
96
+ key: factCollectionKey,
97
+ facts
98
+ } : undefined;
99
+ }
100
+ /**
101
+ * Returns every fact collection of the given type for the queried scope, each holding its facts.
102
+ */ async getFactCollectionsByType(factCollectionTypeKey, jobId) {
103
+ const typeKey = factCollectionTypeKey.toString();
104
+ const committed = await this.#readCollectionsFromDbByType(typeKey);
105
+ return Array.from(this.#foldStagedOps(committed, jobId, typeKey).values()).map((collection)=>({
106
+ key: collection.key,
107
+ facts: [
108
+ ...collection.facts.values()
109
+ ]
110
+ })).filter((collection)=>collection.facts.length > 0);
111
+ }
112
+ /**
113
+ * Commits all staged operations for the given job to persistent storage.
114
+ *
115
+ * Must be called inside a transaction owned by the caller (JobCoordinator wraps all commits in a single
116
+ * transactionAsync, and IndexedDB does not support nested transactions).
117
+ *
118
+ * DO NOT call `#withJobLock` here: awaiting the lock creates a microtask boundary that causes IndexedDB to
119
+ * auto-commit the outer transaction.
120
+ */ async commit(jobId) {
121
+ for (const op of this.#stagedOpsFor(jobId)){
122
+ switch(op.kind){
123
+ case 'recordFact':
124
+ await this.#commitFact(op.fact);
125
+ break;
126
+ case 'deleteFactCollection':
127
+ await this.#deleteCollection(op.key.toString());
128
+ break;
129
+ default:
130
+ {
131
+ const _exhaustive = op;
132
+ throw new Error(`Unhandled FactStore staged op kind: ${JSON.stringify(_exhaustive)}`);
133
+ }
134
+ }
135
+ }
136
+ this.#clearJobData(jobId);
137
+ }
138
+ /** Discards all staged operations for the given job without persisting them. */ discardStaged(jobId) {
139
+ this.#clearJobData(jobId);
140
+ return Promise.resolve();
141
+ }
142
+ /**
143
+ * Removes every retractable fact originating from blocks over height `toBlock`, across all scopes.
144
+ *
145
+ * Non-retractable facts are untouched. Must run inside a caller-owned transaction (because it needs to share the
146
+ * transaction with other stores and IndexedDB has no nested transactions).
147
+ *
148
+ * Throws if any job is in flight (has accessed the store and not yet committed or discarded), since rolling back
149
+ * mid-job could re-introduce records originating from deleted blocks or change state underneath a job's view.
150
+ */ async rollback(toBlock) {
151
+ if (this.#opsForJob.size > 0) {
152
+ throw new Error('PXE fact store rollback is not allowed while jobs are running');
153
+ }
154
+ const removedFacts = await this.#retractFacts(toBlock);
155
+ this.logger.verbose('rolled back fact store', {
156
+ removedFacts,
157
+ toBlock
158
+ });
159
+ }
160
+ /**
161
+ * Deletes retractable facts originating above `toBlock`, returning the number of by-block entries scanned.
162
+ * Retraction is scope-agnostic: a reorg invalidates a fact regardless of which scope's collection it belongs to.
163
+ *
164
+ * Requires to be run in a transactionAsync context.
165
+ */ async #retractFacts(toBlock) {
166
+ // Snapshot the orphaned fact keys before mutating so we never delete from the cursor we are iterating, kicking off
167
+ // each fact-body read during the scan so a DB request stays pending across the cursor-to-delete boundary (a drained
168
+ // cursor with no read in flight would let the transaction auto-commit before the deletes).
169
+ const factReads = new Map();
170
+ for await (const [, factKey] of this.#factsByBlock.entriesAsync({
171
+ start: toBlock + 1
172
+ })){
173
+ factReads.set(factKey, this.#facts.getAsync(factKey));
174
+ }
175
+ await Promise.all(Array.from(factReads, async ([factKey, read])=>{
176
+ const buf = await read;
177
+ if (!buf) {
178
+ // The by-block index just yielded this factKey, so a missing primary record means the indexes are out of
179
+ // sync. Log as this should be unreachable unless there is a bug.
180
+ this.logger.warn('Skipping retraction of a fact missing from the primary store: by-block index is stale', {
181
+ factKey
182
+ });
183
+ return;
184
+ }
185
+ await this.#deleteFact(factKey, StoredFact.fromBuffer(buf));
186
+ }));
187
+ return factReads.size;
188
+ }
189
+ /**
190
+ * Reads the given collections (their facts) by key into a Map keyed by collection key, skipping
191
+ * keys with no committed facts.
192
+ *
193
+ * Reads are not wrapped in a transaction: the caller owns the transaction boundary.
194
+ */ async #readCollectionsFromDb(keys) {
195
+ const result = new Map();
196
+ for (const key of keys){
197
+ const collection = await this.#loadCommittedCollection(key);
198
+ if (collection) {
199
+ result.set(key.toString(), collection);
200
+ }
201
+ }
202
+ return result;
203
+ }
204
+ #readCollectionsFromDbByType(typeKey) {
205
+ return this.#store.transactionAsync(async ()=>{
206
+ const factReadsByCollection = new Map();
207
+ for await (const [collectionKey, factKey] of this.#factsByCollection.entriesAsync({
208
+ start: `${typeKey}:`,
209
+ end: `${typeKey};`
210
+ })){
211
+ let reads = factReadsByCollection.get(collectionKey);
212
+ if (!reads) {
213
+ reads = new Map();
214
+ factReadsByCollection.set(collectionKey, reads);
215
+ }
216
+ reads.set(factKey, this.#facts.getAsync(factKey));
217
+ }
218
+ const result = new Map();
219
+ for (const [collectionKey, reads] of factReadsByCollection){
220
+ const collection = await this.#assembleCollection(FactCollectionKey.fromString(collectionKey), reads);
221
+ result.set(collectionKey, collection);
222
+ }
223
+ return result;
224
+ });
225
+ }
226
+ async #loadCommittedCollection(collectionKey) {
227
+ // Kick off each fact read while iterating the index so a DB request is always pending. Draining the cursor and only
228
+ // then reading the facts one `await` at a time would let the IndexedDB transaction auto-commit at the boundary
229
+ // (IndexedDB auto-commits once control returns to the event loop with no pending request), throwing mid-read on the
230
+ // browser backend.
231
+ const factReads = new Map();
232
+ for await (const factKey of this.#factsByCollection.getValuesAsync(collectionKey.toString())){
233
+ factReads.set(factKey, this.#facts.getAsync(factKey));
234
+ }
235
+ if (factReads.size === 0) {
236
+ return undefined;
237
+ }
238
+ return this.#assembleCollection(collectionKey, factReads);
239
+ }
240
+ /**
241
+ * Assemble a collection's facts from a set of in-flight DB reads.
242
+ */ async #assembleCollection(collectionKey, reads) {
243
+ const factKeys = [
244
+ ...reads.keys()
245
+ ];
246
+ const bufs = await Promise.all(reads.values());
247
+ // Await-free tail: deserialize. No DB ops from here on.
248
+ const facts = new Map();
249
+ for(let i = 0; i < factKeys.length; i++){
250
+ const factKey = factKeys[i];
251
+ const buf = bufs[i];
252
+ if (!buf) {
253
+ // Defensive: a #factsByCollection entry must always reference a live #facts entry. A missing one means the
254
+ // indexes are corrupt.
255
+ throw new Error(`Fact not found for factKey ${factKey}`);
256
+ }
257
+ const stored = StoredFact.fromBuffer(buf);
258
+ if (stored.factCollectionKey.toString() !== collectionKey.toString()) {
259
+ // Defensive: every read fact must belong to the collection being assembled. A mismatch means the indexes are
260
+ // corrupt.
261
+ throw new Error(`Fact ${factKey} does not belong to collection ${collectionKey}`);
262
+ }
263
+ facts.set(factKey, stored.toFact());
264
+ }
265
+ return {
266
+ key: collectionKey,
267
+ facts
268
+ };
269
+ }
270
+ /**
271
+ * Assembles the current view of a collection of collections together with their facts, combining the committed with
272
+ * staged data.
273
+ *
274
+ * When `typeKey` is given, staged records of other types are ignored, so the result holds only that type.
275
+ */ #foldStagedOps(committed, jobId, typeKey) {
276
+ const result = new Map();
277
+ // Copy to avoid mutating the contents of `committed`.
278
+ for (const [collectionKey, { key, facts }] of committed){
279
+ result.set(collectionKey, {
280
+ key,
281
+ facts: new Map(facts)
282
+ });
283
+ }
284
+ for (const op of this.#stagedOpsFor(jobId)){
285
+ switch(op.kind){
286
+ case 'recordFact':
287
+ this.#foldRecordFact(result, op, typeKey);
288
+ break;
289
+ case 'deleteFactCollection':
290
+ this.#foldDeleteFactCollection(result, op);
291
+ break;
292
+ default:
293
+ {
294
+ const _exhaustive = op;
295
+ throw new Error(`Unhandled FactStore staged op kind: ${JSON.stringify(_exhaustive)}`);
296
+ }
297
+ }
298
+ }
299
+ return result;
300
+ }
301
+ /**
302
+ * Folds a staged `recordFact` op into view.
303
+ *
304
+ * When `typeKey` is given, an op of another type is ignored, keeping the view limited to that type.
305
+ */ #foldRecordFact(result, op, typeKey) {
306
+ const key = op.fact.factCollectionKey;
307
+ // Type filter doesn't match, nothing to do with this fact
308
+ if (typeKey !== undefined && key.factCollectionTypeKey().toString() !== typeKey) {
309
+ return;
310
+ }
311
+ const collectionKey = key.toString();
312
+ let collection = result.get(collectionKey);
313
+ // Collection didn't exist before this point, the created fact brings it into existence
314
+ if (!collection) {
315
+ collection = {
316
+ key,
317
+ facts: new Map()
318
+ };
319
+ result.set(collectionKey, collection);
320
+ }
321
+ const fKey = factKeyStrOf(op.fact);
322
+ if (!collection.facts.has(fKey)) {
323
+ collection.facts.set(fKey, op.fact.toFact());
324
+ }
325
+ }
326
+ /**
327
+ * Folds a staged `deleteFactCollection` op into the view: the scope-qualified collection is removed outright.
328
+ */ #foldDeleteFactCollection(result, op) {
329
+ result.delete(op.key.toString());
330
+ }
331
+ /**
332
+ * Writes a fact to persistent storage. Idempotent: an identical fact (same scope-qualified key) is left untouched.
333
+ */ async #commitFact(fact) {
334
+ const factKey = factKeyStrOf(fact);
335
+ if (await this.#facts.hasAsync(factKey)) {
336
+ this.logger.debug(`Ignoring already recorded fact`, {
337
+ factKey
338
+ });
339
+ return;
340
+ }
341
+ await this.#facts.set(factKey, fact.toBuffer());
342
+ await this.#factsByCollection.set(fact.factCollectionKey.toString(), factKey);
343
+ if (fact.originBlock !== undefined) {
344
+ await this.#factsByBlock.set(fact.originBlock.blockNumber, factKey);
345
+ }
346
+ }
347
+ /**
348
+ * Deletes every fact under the (scope-qualified) collection key.
349
+ *
350
+ * Caller must wrap in a transaction.
351
+ */ async #deleteCollection(collectionKey) {
352
+ // Snapshot the fact index before mutating so we never delete from the cursor we are iterating, kicking off each
353
+ // fact-body read during the scan so a DB request stays pending across the cursor-to-mutation boundary (a drained
354
+ // cursor with no read in flight would let the transaction auto-commit before the deletes).
355
+ const factReads = new Map();
356
+ for await (const factKey of this.#factsByCollection.getValuesAsync(collectionKey)){
357
+ factReads.set(factKey, this.#facts.getAsync(factKey));
358
+ }
359
+ await Promise.all(Array.from(factReads, async ([factKey, read])=>{
360
+ const buf = await read;
361
+ if (!buf) {
362
+ // A #factsByCollection entry must always reference a live #facts entry, a missing one means the indexes are
363
+ // corrupt.
364
+ throw new Error(`Fact not found for factKey ${factKey}`);
365
+ }
366
+ await this.#deleteFact(factKey, StoredFact.fromBuffer(buf));
367
+ }));
368
+ }
369
+ /**
370
+ * Deletes a fact from the primary store and all its indexes (`#factsByCollection`, plus `#factsByBlock` if
371
+ * retractable).
372
+ *
373
+ * Caller must wrap in a transaction.
374
+ */ async #deleteFact(factKey, fact) {
375
+ await this.#facts.delete(factKey);
376
+ await this.#factsByCollection.deleteValue(fact.factCollectionKey.toString(), factKey);
377
+ if (fact.originBlock !== undefined) {
378
+ await this.#factsByBlock.deleteValue(fact.originBlock.blockNumber, factKey);
379
+ }
380
+ }
381
+ /**
382
+ * Returns the job's staged-ops array, creating it on first access.
383
+ * */ #stagedOpsFor(jobId) {
384
+ let ops = this.#opsForJob.get(jobId);
385
+ if (ops === undefined) {
386
+ ops = [];
387
+ this.#opsForJob.set(jobId, ops);
388
+ }
389
+ return ops;
390
+ }
391
+ #clearJobData(jobId) {
392
+ this.#opsForJob.delete(jobId);
393
+ this.#jobLocks.delete(jobId);
394
+ }
395
+ async #withJobLock(jobId, fn) {
396
+ let lock = this.#jobLocks.get(jobId);
397
+ if (!lock) {
398
+ lock = new Semaphore(1);
399
+ this.#jobLocks.set(jobId, lock);
400
+ }
401
+ await lock.acquire();
402
+ try {
403
+ return await fn();
404
+ } finally{
405
+ lock.release();
406
+ }
407
+ }
408
+ }
@@ -0,0 +1,34 @@
1
+ import { Fr } from '@aztec/foundation/curves/bn254';
2
+ import type { FieldsOf } from '@aztec/foundation/types';
3
+ import { AztecAddress } from '@aztec/stdlib/aztec-address';
4
+ /**
5
+ * The block a retractable fact originates from.
6
+ */
7
+ export type OriginBlock = {
8
+ blockNumber: number;
9
+ blockHash: Fr;
10
+ };
11
+ /** Identifies all fact collections of one type within a contract, for one scope. */
12
+ export declare class FactCollectionTypeKey {
13
+ readonly contractAddress: AztecAddress;
14
+ readonly scope: AztecAddress;
15
+ readonly factCollectionTypeId: Fr;
16
+ constructor(contractAddress: AztecAddress, scope: AztecAddress, factCollectionTypeId: Fr);
17
+ static from(fields: FieldsOf<FactCollectionTypeKey>): FactCollectionTypeKey;
18
+ toString(): string;
19
+ }
20
+ /** Uniquely identifies a single fact collection, isolated by scope; all its facts share this key. */
21
+ export declare class FactCollectionKey {
22
+ readonly contractAddress: AztecAddress;
23
+ readonly scope: AztecAddress;
24
+ readonly factCollectionTypeId: Fr;
25
+ readonly factCollectionId: Fr;
26
+ constructor(contractAddress: AztecAddress, scope: AztecAddress, factCollectionTypeId: Fr, factCollectionId: Fr);
27
+ static from(fields: FieldsOf<FactCollectionKey>): FactCollectionKey;
28
+ /** Inverse of toString */
29
+ static fromString(str: string): FactCollectionKey;
30
+ /** The key grouping this collection with the other collections of its type within the same contract and scope. */
31
+ factCollectionTypeKey(): FactCollectionTypeKey;
32
+ toString(): string;
33
+ }
34
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdF9zdG9yZV9rZXlzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3RvcmFnZS9mYWN0X3N0b3JlL2ZhY3Rfc3RvcmVfa2V5cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEQsT0FBTyxLQUFLLEVBQUUsUUFBUSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDeEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRTNEOztHQUVHO0FBQ0gsTUFBTSxNQUFNLFdBQVcsR0FBRztJQUFFLFdBQVcsRUFBRSxNQUFNLENBQUM7SUFBQyxTQUFTLEVBQUUsRUFBRSxDQUFBO0NBQUUsQ0FBQztBQVNqRSxvRkFBb0Y7QUFDcEYscUJBQWEscUJBQXFCO2FBRWQsZUFBZSxFQUFFLFlBQVk7YUFDN0IsS0FBSyxFQUFFLFlBQVk7YUFDbkIsb0JBQW9CLEVBQUUsRUFBRTtJQUgxQyxZQUNrQixlQUFlLEVBQUUsWUFBWSxFQUM3QixLQUFLLEVBQUUsWUFBWSxFQUNuQixvQkFBb0IsRUFBRSxFQUFFLEVBR3pDO0lBRUQsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLHFCQUFxQixDQUFDLEdBQUcscUJBQXFCLENBRTFFO0lBRUQsUUFBUSxJQUFJLE1BQU0sQ0FFakI7Q0FDRjtBQUVELHFHQUFxRztBQUNyRyxxQkFBYSxpQkFBaUI7YUFFVixlQUFlLEVBQUUsWUFBWTthQUM3QixLQUFLLEVBQUUsWUFBWTthQUNuQixvQkFBb0IsRUFBRSxFQUFFO2FBQ3hCLGdCQUFnQixFQUFFLEVBQUU7SUFKdEMsWUFDa0IsZUFBZSxFQUFFLFlBQVksRUFDN0IsS0FBSyxFQUFFLFlBQVksRUFDbkIsb0JBQW9CLEVBQUUsRUFBRSxFQUN4QixnQkFBZ0IsRUFBRSxFQUFFLEVBR3JDO0lBRUQsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsaUJBQWlCLENBT2xFO0lBRUQsMEJBQTBCO0lBQzFCLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLE1BQU0sR0FBRyxpQkFBaUIsQ0FRaEQ7SUFFRCxrSEFBa0g7SUFDbEgscUJBQXFCLElBQUkscUJBQXFCLENBRTdDO0lBRUQsUUFBUSxJQUFJLE1BQU0sQ0FFakI7Q0FDRiJ9
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fact_store_keys.d.ts","sourceRoot":"","sources":["../../../src/storage/fact_store/fact_store_keys.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,EAAE,CAAA;CAAE,CAAC;AASjE,oFAAoF;AACpF,qBAAa,qBAAqB;aAEd,eAAe,EAAE,YAAY;aAC7B,KAAK,EAAE,YAAY;aACnB,oBAAoB,EAAE,EAAE;IAH1C,YACkB,eAAe,EAAE,YAAY,EAC7B,KAAK,EAAE,YAAY,EACnB,oBAAoB,EAAE,EAAE,EAGzC;IAED,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,GAAG,qBAAqB,CAE1E;IAED,QAAQ,IAAI,MAAM,CAEjB;CACF;AAED,qGAAqG;AACrG,qBAAa,iBAAiB;aAEV,eAAe,EAAE,YAAY;aAC7B,KAAK,EAAE,YAAY;aACnB,oBAAoB,EAAE,EAAE;aACxB,gBAAgB,EAAE,EAAE;IAJtC,YACkB,eAAe,EAAE,YAAY,EAC7B,KAAK,EAAE,YAAY,EACnB,oBAAoB,EAAE,EAAE,EACxB,gBAAgB,EAAE,EAAE,EAGrC;IAED,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GAAG,iBAAiB,CAOlE;IAED,0BAA0B;IAC1B,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAQhD;IAED,kHAAkH;IAClH,qBAAqB,IAAI,qBAAqB,CAE7C;IAED,QAAQ,IAAI,MAAM,CAEjB;CACF"}