@aztec/archiver 0.0.0-test.1 → 0.0.1-commit.1142ef1

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 (151) hide show
  1. package/README.md +27 -6
  2. package/dest/archiver/archiver.d.ts +204 -94
  3. package/dest/archiver/archiver.d.ts.map +1 -1
  4. package/dest/archiver/archiver.js +1616 -414
  5. package/dest/archiver/archiver_store.d.ts +178 -83
  6. package/dest/archiver/archiver_store.d.ts.map +1 -1
  7. package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
  8. package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
  9. package/dest/archiver/archiver_store_test_suite.js +2373 -397
  10. package/dest/archiver/config.d.ts +7 -22
  11. package/dest/archiver/config.d.ts.map +1 -1
  12. package/dest/archiver/config.js +30 -14
  13. package/dest/archiver/errors.d.ts +33 -1
  14. package/dest/archiver/errors.d.ts.map +1 -1
  15. package/dest/archiver/errors.js +49 -0
  16. package/dest/archiver/index.d.ts +3 -4
  17. package/dest/archiver/index.d.ts.map +1 -1
  18. package/dest/archiver/index.js +1 -2
  19. package/dest/archiver/instrumentation.d.ts +14 -6
  20. package/dest/archiver/instrumentation.d.ts.map +1 -1
  21. package/dest/archiver/instrumentation.js +45 -41
  22. package/dest/archiver/kv_archiver_store/block_store.d.ts +98 -21
  23. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
  24. package/dest/archiver/kv_archiver_store/block_store.js +495 -86
  25. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +4 -4
  26. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
  27. package/dest/archiver/kv_archiver_store/contract_class_store.js +13 -19
  28. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +12 -9
  29. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
  30. package/dest/archiver/kv_archiver_store/contract_instance_store.js +30 -16
  31. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +81 -75
  32. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
  33. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +145 -83
  34. package/dest/archiver/kv_archiver_store/log_store.d.ts +12 -16
  35. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
  36. package/dest/archiver/kv_archiver_store/log_store.js +151 -114
  37. package/dest/archiver/kv_archiver_store/message_store.d.ts +25 -18
  38. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
  39. package/dest/archiver/kv_archiver_store/message_store.js +152 -49
  40. package/dest/archiver/l1/bin/retrieve-calldata.d.ts +3 -0
  41. package/dest/archiver/l1/bin/retrieve-calldata.d.ts.map +1 -0
  42. package/dest/archiver/l1/bin/retrieve-calldata.js +149 -0
  43. package/dest/archiver/l1/calldata_retriever.d.ts +112 -0
  44. package/dest/archiver/l1/calldata_retriever.d.ts.map +1 -0
  45. package/dest/archiver/l1/calldata_retriever.js +471 -0
  46. package/dest/archiver/l1/data_retrieval.d.ts +90 -0
  47. package/dest/archiver/l1/data_retrieval.d.ts.map +1 -0
  48. package/dest/archiver/l1/data_retrieval.js +331 -0
  49. package/dest/archiver/l1/debug_tx.d.ts +19 -0
  50. package/dest/archiver/l1/debug_tx.d.ts.map +1 -0
  51. package/dest/archiver/l1/debug_tx.js +73 -0
  52. package/dest/archiver/l1/spire_proposer.d.ts +70 -0
  53. package/dest/archiver/l1/spire_proposer.d.ts.map +1 -0
  54. package/dest/archiver/l1/spire_proposer.js +157 -0
  55. package/dest/archiver/l1/trace_tx.d.ts +97 -0
  56. package/dest/archiver/l1/trace_tx.d.ts.map +1 -0
  57. package/dest/archiver/l1/trace_tx.js +91 -0
  58. package/dest/archiver/l1/types.d.ts +12 -0
  59. package/dest/archiver/l1/types.d.ts.map +1 -0
  60. package/dest/archiver/l1/types.js +3 -0
  61. package/dest/archiver/l1/validate_trace.d.ts +29 -0
  62. package/dest/archiver/l1/validate_trace.d.ts.map +1 -0
  63. package/dest/archiver/l1/validate_trace.js +150 -0
  64. package/dest/archiver/structs/data_retrieval.d.ts +1 -1
  65. package/dest/archiver/structs/inbox_message.d.ts +15 -0
  66. package/dest/archiver/structs/inbox_message.d.ts.map +1 -0
  67. package/dest/archiver/structs/inbox_message.js +39 -0
  68. package/dest/archiver/structs/published.d.ts +2 -11
  69. package/dest/archiver/structs/published.d.ts.map +1 -1
  70. package/dest/archiver/structs/published.js +1 -1
  71. package/dest/archiver/validation.d.ts +17 -0
  72. package/dest/archiver/validation.d.ts.map +1 -0
  73. package/dest/archiver/validation.js +98 -0
  74. package/dest/factory.d.ts +9 -14
  75. package/dest/factory.d.ts.map +1 -1
  76. package/dest/factory.js +22 -52
  77. package/dest/index.d.ts +2 -2
  78. package/dest/index.d.ts.map +1 -1
  79. package/dest/index.js +1 -1
  80. package/dest/rpc/index.d.ts +2 -3
  81. package/dest/rpc/index.d.ts.map +1 -1
  82. package/dest/rpc/index.js +1 -4
  83. package/dest/test/index.d.ts +1 -1
  84. package/dest/test/mock_archiver.d.ts +16 -8
  85. package/dest/test/mock_archiver.d.ts.map +1 -1
  86. package/dest/test/mock_archiver.js +19 -14
  87. package/dest/test/mock_l1_to_l2_message_source.d.ts +9 -6
  88. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  89. package/dest/test/mock_l1_to_l2_message_source.js +30 -7
  90. package/dest/test/mock_l2_block_source.d.ts +56 -13
  91. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  92. package/dest/test/mock_l2_block_source.js +196 -25
  93. package/dest/test/mock_structs.d.ts +10 -0
  94. package/dest/test/mock_structs.d.ts.map +1 -0
  95. package/dest/test/mock_structs.js +38 -0
  96. package/package.json +29 -30
  97. package/src/archiver/archiver.ts +1596 -512
  98. package/src/archiver/archiver_store.ts +205 -88
  99. package/src/archiver/archiver_store_test_suite.ts +2386 -354
  100. package/src/archiver/config.ts +38 -46
  101. package/src/archiver/errors.ts +85 -0
  102. package/src/archiver/index.ts +2 -3
  103. package/src/archiver/instrumentation.ts +65 -45
  104. package/src/archiver/kv_archiver_store/block_store.ts +668 -101
  105. package/src/archiver/kv_archiver_store/contract_class_store.ts +14 -24
  106. package/src/archiver/kv_archiver_store/contract_instance_store.ts +36 -28
  107. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +197 -113
  108. package/src/archiver/kv_archiver_store/log_store.ts +204 -132
  109. package/src/archiver/kv_archiver_store/message_store.ts +213 -54
  110. package/src/archiver/l1/README.md +98 -0
  111. package/src/archiver/l1/bin/retrieve-calldata.ts +182 -0
  112. package/src/archiver/l1/calldata_retriever.ts +641 -0
  113. package/src/archiver/l1/data_retrieval.ts +512 -0
  114. package/src/archiver/l1/debug_tx.ts +99 -0
  115. package/src/archiver/l1/spire_proposer.ts +160 -0
  116. package/src/archiver/l1/trace_tx.ts +128 -0
  117. package/src/archiver/l1/types.ts +13 -0
  118. package/src/archiver/l1/validate_trace.ts +211 -0
  119. package/src/archiver/structs/inbox_message.ts +41 -0
  120. package/src/archiver/structs/published.ts +1 -11
  121. package/src/archiver/validation.ts +124 -0
  122. package/src/factory.ts +28 -69
  123. package/src/index.ts +1 -1
  124. package/src/rpc/index.ts +1 -5
  125. package/src/test/fixtures/debug_traceTransaction-multicall3.json +88 -0
  126. package/src/test/fixtures/debug_traceTransaction-multiplePropose.json +153 -0
  127. package/src/test/fixtures/debug_traceTransaction-proxied.json +122 -0
  128. package/src/test/fixtures/trace_transaction-multicall3.json +65 -0
  129. package/src/test/fixtures/trace_transaction-multiplePropose.json +319 -0
  130. package/src/test/fixtures/trace_transaction-proxied.json +128 -0
  131. package/src/test/fixtures/trace_transaction-randomRevert.json +216 -0
  132. package/src/test/mock_archiver.ts +22 -16
  133. package/src/test/mock_l1_to_l2_message_source.ts +26 -8
  134. package/src/test/mock_l2_block_source.ts +254 -31
  135. package/src/test/mock_structs.ts +50 -0
  136. package/dest/archiver/data_retrieval.d.ts +0 -74
  137. package/dest/archiver/data_retrieval.d.ts.map +0 -1
  138. package/dest/archiver/data_retrieval.js +0 -283
  139. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts +0 -12
  140. package/dest/archiver/kv_archiver_store/nullifier_store.d.ts.map +0 -1
  141. package/dest/archiver/kv_archiver_store/nullifier_store.js +0 -73
  142. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts +0 -23
  143. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.d.ts.map +0 -1
  144. package/dest/archiver/memory_archiver_store/l1_to_l2_message_store.js +0 -49
  145. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts +0 -175
  146. package/dest/archiver/memory_archiver_store/memory_archiver_store.d.ts.map +0 -1
  147. package/dest/archiver/memory_archiver_store/memory_archiver_store.js +0 -636
  148. package/src/archiver/data_retrieval.ts +0 -422
  149. package/src/archiver/kv_archiver_store/nullifier_store.ts +0 -97
  150. package/src/archiver/memory_archiver_store/l1_to_l2_message_store.ts +0 -61
  151. package/src/archiver/memory_archiver_store/memory_archiver_store.ts +0 -801
@@ -1,15 +1,21 @@
1
- import { INITIAL_L2_BLOCK_NUM, MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_DATA_SIZE_IN_FIELDS } from '@aztec/constants';
1
+ import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
2
+ import { BlockNumber } from '@aztec/foundation/branded-types';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
2
4
  import { createLogger } from '@aztec/foundation/log';
3
5
  import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize';
4
- import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, PrivateLog, PublicLog, TxScopedL2Log } from '@aztec/stdlib/logs';
6
+ import { L2BlockHash } from '@aztec/stdlib/block';
7
+ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, PublicLog, TxScopedL2Log } from '@aztec/stdlib/logs';
5
8
  /**
6
9
  * A store for logs
7
10
  */ export class LogStore {
8
11
  db;
9
12
  blockStore;
10
- #logsByTag;
11
- #logTagsByBlock;
12
- #privateLogsByBlock;
13
+ // `tag` --> private logs
14
+ #privateLogsByTag;
15
+ // `{contractAddress}_${tag}` --> public logs
16
+ #publicLogsByContractAndTag;
17
+ #privateLogKeysByBlock;
18
+ #publicLogKeysByBlock;
13
19
  #publicLogsByBlock;
14
20
  #contractClassLogsByBlock;
15
21
  #logsMaxPageSize;
@@ -18,100 +24,118 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
18
24
  this.db = db;
19
25
  this.blockStore = blockStore;
20
26
  this.#log = createLogger('archiver:log_store');
21
- this.#logsByTag = db.openMap('archiver_tagged_logs_by_tag');
22
- this.#logTagsByBlock = db.openMap('archiver_log_tags_by_block');
23
- this.#privateLogsByBlock = db.openMap('archiver_private_logs_by_block');
27
+ this.#privateLogsByTag = db.openMap('archiver_private_tagged_logs_by_tag');
28
+ this.#publicLogsByContractAndTag = db.openMap('archiver_public_tagged_logs_by_tag');
29
+ this.#privateLogKeysByBlock = db.openMap('archiver_private_log_keys_by_block');
30
+ this.#publicLogKeysByBlock = db.openMap('archiver_public_log_keys_by_block');
24
31
  this.#publicLogsByBlock = db.openMap('archiver_public_logs_by_block');
25
32
  this.#contractClassLogsByBlock = db.openMap('archiver_contract_class_logs_by_block');
26
33
  this.#logsMaxPageSize = logsMaxPageSize;
27
34
  }
28
- #extractTaggedLogsFromPrivate(block) {
29
- const taggedLogs = new Map();
30
- const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex - block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
31
- block.body.txEffects.forEach((txEffect, txIndex)=>{
35
+ /**
36
+ * Extracts tagged logs from a single block, grouping them into private and public maps.
37
+ *
38
+ * @param block - The L2 block to extract logs from.
39
+ * @returns An object containing the private and public tagged logs for the block.
40
+ */ #extractTaggedLogsFromBlock(block) {
41
+ // SiloedTag (as string) -> array of log buffers.
42
+ const privateTaggedLogs = new Map();
43
+ // "{contractAddress}_{tag}" (as string) -> array of log buffers.
44
+ const publicTaggedLogs = new Map();
45
+ block.body.txEffects.forEach((txEffect)=>{
32
46
  const txHash = txEffect.txHash;
33
- const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
34
47
  txEffect.privateLogs.forEach((log)=>{
48
+ // Private logs use SiloedTag (already siloed by kernel)
35
49
  const tag = log.fields[0];
36
- const currentLogs = taggedLogs.get(tag.toString()) ?? [];
37
- currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ false, log.toBuffer()).toBuffer());
38
- taggedLogs.set(tag.toString(), currentLogs);
50
+ this.#log.debug(`Found private log with tag ${tag.toString()} in block ${block.number}`);
51
+ const currentLogs = privateTaggedLogs.get(tag.toString()) ?? [];
52
+ currentLogs.push(new TxScopedL2Log(txHash, block.number, block.timestamp, log.getEmittedFields(), txEffect.noteHashes, txEffect.nullifiers[0]).toBuffer());
53
+ privateTaggedLogs.set(tag.toString(), currentLogs);
39
54
  });
40
- });
41
- return taggedLogs;
42
- }
43
- #extractTaggedLogsFromPublic(block) {
44
- const taggedLogs = new Map();
45
- const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex - block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
46
- block.body.txEffects.forEach((txEffect, txIndex)=>{
47
- const txHash = txEffect.txHash;
48
- const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
49
55
  txEffect.publicLogs.forEach((log)=>{
50
- // Check that each log stores 2 lengths in its first field. If not, it's not a tagged log:
51
- const firstFieldBuf = log.log[0].toBuffer();
52
- // See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
53
- // Search the codebase for "disgusting encoding" to see other hardcoded instances of this encoding, that you might need to change if you ever find yourself here.
54
- if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
55
- // See parseLogFromPublic - the first field of a tagged log is 5 bytes structured:
56
- // [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
57
- this.#log.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
58
- return;
59
- }
60
- // Check that the length values line up with the log contents
61
- const publicValuesLength = firstFieldBuf.subarray(-5).readUint16BE();
62
- const privateValuesLength = firstFieldBuf.subarray(-5).readUint16BE(3);
63
- // Add 1 for the first field holding lengths
64
- const totalLogLength = 1 + publicValuesLength + privateValuesLength;
65
- // Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
66
- if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find((f)=>!f.isZero())) {
67
- this.#log.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
68
- return;
69
- }
70
- // The first elt stores lengths as above => tag is in fields[1]
71
- const tag = log.log[1];
72
- this.#log.debug(`Found tagged public log with tag ${tag.toString()} in block ${block.number}`);
73
- const currentLogs = taggedLogs.get(tag.toString()) ?? [];
74
- currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, block.number, /* isFromPublic */ true, log.toBuffer()).toBuffer());
75
- taggedLogs.set(tag.toString(), currentLogs);
56
+ // Public logs use Tag directly (not siloed) and are stored with contract address
57
+ const tag = log.fields[0];
58
+ const contractAddress = log.contractAddress;
59
+ const key = `${contractAddress.toString()}_${tag.toString()}`;
60
+ this.#log.debug(`Found public log with tag ${tag.toString()} from contract ${contractAddress.toString()} in block ${block.number}`);
61
+ const currentLogs = publicTaggedLogs.get(key) ?? [];
62
+ currentLogs.push(new TxScopedL2Log(txHash, block.number, block.timestamp, log.getEmittedFields(), txEffect.noteHashes, txEffect.nullifiers[0]).toBuffer());
63
+ publicTaggedLogs.set(key, currentLogs);
76
64
  });
77
65
  });
78
- return taggedLogs;
66
+ return {
67
+ privateTaggedLogs,
68
+ publicTaggedLogs
69
+ };
79
70
  }
80
71
  /**
81
- * Append new logs to the store's list.
82
- * @param blocks - The blocks for which to add the logs.
83
- * @returns True if the operation is successful.
84
- */ addLogs(blocks) {
85
- const taggedLogsToAdd = blocks.flatMap((block)=>[
86
- this.#extractTaggedLogsFromPrivate(block),
87
- this.#extractTaggedLogsFromPublic(block)
88
- ]).reduce((acc, val)=>{
89
- for (const [tag, logs] of val.entries()){
72
+ * Extracts and aggregates tagged logs from a list of blocks.
73
+ * @param blocks - The blocks to extract logs from.
74
+ * @returns A map from tag (as string) to an array of serialized private logs belonging to that tag, and a map from
75
+ * "{contractAddress}_{tag}" (as string) to an array of serialized public logs belonging to that key.
76
+ */ #extractTaggedLogs(blocks) {
77
+ const taggedLogsInBlocks = blocks.map((block)=>this.#extractTaggedLogsFromBlock(block));
78
+ // Now we merge the maps from each block into a single map.
79
+ const privateTaggedLogs = taggedLogsInBlocks.reduce((acc, { privateTaggedLogs })=>{
80
+ for (const [tag, logs] of privateTaggedLogs.entries()){
90
81
  const currentLogs = acc.get(tag) ?? [];
91
82
  acc.set(tag, currentLogs.concat(logs));
92
83
  }
93
84
  return acc;
94
- });
95
- const tagsToUpdate = Array.from(taggedLogsToAdd.keys());
85
+ }, new Map());
86
+ const publicTaggedLogs = taggedLogsInBlocks.reduce((acc, { publicTaggedLogs })=>{
87
+ for (const [key, logs] of publicTaggedLogs.entries()){
88
+ const currentLogs = acc.get(key) ?? [];
89
+ acc.set(key, currentLogs.concat(logs));
90
+ }
91
+ return acc;
92
+ }, new Map());
93
+ return {
94
+ privateTaggedLogs,
95
+ publicTaggedLogs
96
+ };
97
+ }
98
+ /**
99
+ * Append new logs to the store's list.
100
+ * @param blocks - The blocks for which to add the logs.
101
+ * @returns True if the operation is successful.
102
+ */ addLogs(blocks) {
103
+ const { privateTaggedLogs, publicTaggedLogs } = this.#extractTaggedLogs(blocks);
104
+ const keysOfPrivateLogsToUpdate = Array.from(privateTaggedLogs.keys());
105
+ const keysOfPublicLogsToUpdate = Array.from(publicTaggedLogs.keys());
96
106
  return this.db.transactionAsync(async ()=>{
97
- const currentTaggedLogs = await Promise.all(tagsToUpdate.map(async (tag)=>({
98
- tag,
99
- logBuffers: await this.#logsByTag.getAsync(tag)
107
+ const currentPrivateTaggedLogs = await Promise.all(keysOfPrivateLogsToUpdate.map(async (key)=>({
108
+ tag: key,
109
+ logBuffers: await this.#privateLogsByTag.getAsync(key)
100
110
  })));
101
- currentTaggedLogs.forEach((taggedLogBuffer)=>{
111
+ currentPrivateTaggedLogs.forEach((taggedLogBuffer)=>{
102
112
  if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
103
- taggedLogsToAdd.set(taggedLogBuffer.tag, taggedLogBuffer.logBuffers.concat(taggedLogsToAdd.get(taggedLogBuffer.tag)));
113
+ privateTaggedLogs.set(taggedLogBuffer.tag, taggedLogBuffer.logBuffers.concat(privateTaggedLogs.get(taggedLogBuffer.tag)));
114
+ }
115
+ });
116
+ const currentPublicTaggedLogs = await Promise.all(keysOfPublicLogsToUpdate.map(async (key)=>({
117
+ key,
118
+ logBuffers: await this.#publicLogsByContractAndTag.getAsync(key)
119
+ })));
120
+ currentPublicTaggedLogs.forEach((taggedLogBuffer)=>{
121
+ if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
122
+ publicTaggedLogs.set(taggedLogBuffer.key, taggedLogBuffer.logBuffers.concat(publicTaggedLogs.get(taggedLogBuffer.key)));
104
123
  }
105
124
  });
106
125
  for (const block of blocks){
107
- const tagsInBlock = [];
108
- for (const [tag, logs] of taggedLogsToAdd.entries()){
109
- await this.#logsByTag.set(tag, logs);
110
- tagsInBlock.push(tag);
126
+ const blockHash = await block.hash();
127
+ const privateTagsInBlock = [];
128
+ for (const [tag, logs] of privateTaggedLogs.entries()){
129
+ await this.#privateLogsByTag.set(tag, logs);
130
+ privateTagsInBlock.push(tag);
131
+ }
132
+ await this.#privateLogKeysByBlock.set(block.number, privateTagsInBlock);
133
+ const publicKeysInBlock = [];
134
+ for (const [key, logs] of publicTaggedLogs.entries()){
135
+ await this.#publicLogsByContractAndTag.set(key, logs);
136
+ publicKeysInBlock.push(key);
111
137
  }
112
- await this.#logTagsByBlock.set(block.number, tagsInBlock);
113
- const privateLogsInBlock = block.body.txEffects.map((txEffect)=>txEffect.privateLogs).flat().map((log)=>log.toBuffer());
114
- await this.#privateLogsByBlock.set(block.number, Buffer.concat(privateLogsInBlock));
138
+ await this.#publicLogKeysByBlock.set(block.number, publicKeysInBlock);
115
139
  const publicLogsInBlock = block.body.txEffects.map((txEffect, txIndex)=>[
116
140
  numToUInt32BE(txIndex),
117
141
  numToUInt32BE(txEffect.publicLogs.length),
@@ -122,53 +146,60 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
122
146
  numToUInt32BE(txEffect.contractClassLogs.length),
123
147
  txEffect.contractClassLogs.map((log)=>log.toBuffer())
124
148
  ].flat()).flat();
125
- await this.#publicLogsByBlock.set(block.number, Buffer.concat(publicLogsInBlock));
126
- await this.#contractClassLogsByBlock.set(block.number, Buffer.concat(contractClassLogsInBlock));
149
+ await this.#publicLogsByBlock.set(block.number, this.#packWithBlockHash(blockHash, publicLogsInBlock));
150
+ await this.#contractClassLogsByBlock.set(block.number, this.#packWithBlockHash(blockHash, contractClassLogsInBlock));
127
151
  }
128
152
  return true;
129
153
  });
130
154
  }
155
+ #packWithBlockHash(blockHash, data) {
156
+ return Buffer.concat([
157
+ blockHash.toBuffer(),
158
+ ...data
159
+ ]);
160
+ }
161
+ #unpackBlockHash(reader) {
162
+ const blockHash = reader.remainingBytes() > 0 ? reader.readObject(Fr) : undefined;
163
+ if (!blockHash) {
164
+ throw new Error('Failed to read block hash from log entry buffer');
165
+ }
166
+ return L2BlockHash.fromField(blockHash);
167
+ }
131
168
  deleteLogs(blocks) {
132
169
  return this.db.transactionAsync(async ()=>{
133
- const tagsToDelete = (await Promise.all(blocks.map(async (block)=>{
134
- const tags = await this.#logTagsByBlock.getAsync(block.number);
135
- return tags ?? [];
136
- }))).flat();
170
+ await Promise.all(blocks.map(async (block)=>{
171
+ // Delete private logs
172
+ const privateKeys = await this.#privateLogKeysByBlock.getAsync(block.number) ?? [];
173
+ await Promise.all(privateKeys.map((tag)=>this.#privateLogsByTag.delete(tag)));
174
+ // Delete public logs
175
+ const publicKeys = await this.#publicLogKeysByBlock.getAsync(block.number) ?? [];
176
+ await Promise.all(publicKeys.map((key)=>this.#publicLogsByContractAndTag.delete(key)));
177
+ }));
137
178
  await Promise.all(blocks.map((block)=>Promise.all([
138
- this.#privateLogsByBlock.delete(block.number),
139
179
  this.#publicLogsByBlock.delete(block.number),
140
- this.#logTagsByBlock.delete(block.number)
180
+ this.#privateLogKeysByBlock.delete(block.number),
181
+ this.#publicLogKeysByBlock.delete(block.number),
182
+ this.#contractClassLogsByBlock.delete(block.number)
141
183
  ])));
142
- await Promise.all(tagsToDelete.map((tag)=>this.#logsByTag.delete(tag.toString())));
143
184
  return true;
144
185
  });
145
186
  }
146
187
  /**
147
- * Retrieves all private logs from up to `limit` blocks, starting from the block number `start`.
148
- * @param start - The block number from which to begin retrieving logs.
149
- * @param limit - The maximum number of blocks to retrieve logs from.
150
- * @returns An array of private logs from the specified range of blocks.
151
- */ async getPrivateLogs(start, limit) {
152
- const logs = [];
153
- for await (const buffer of this.#privateLogsByBlock.valuesAsync({
154
- start,
155
- limit
156
- })){
157
- const reader = new BufferReader(buffer);
158
- while(reader.remainingBytes() > 0){
159
- logs.push(reader.readObject(PrivateLog));
160
- }
161
- }
162
- return logs;
188
+ * Gets all private logs that match any of the `tags`. For each tag, an array of matching logs is returned. An empty
189
+ * array implies no logs match that tag.
190
+ */ async getPrivateLogsByTags(tags) {
191
+ const logs = await Promise.all(tags.map((tag)=>this.#privateLogsByTag.getAsync(tag.toString())));
192
+ return logs.map((logBuffers)=>logBuffers?.map((logBuffer)=>TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
163
193
  }
164
194
  /**
165
- * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
166
- * @param tags - The tags to filter the logs by.
167
- * @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
168
- * that tag.
169
- */ async getLogsByTags(tags) {
170
- const logs = await Promise.all(tags.map((tag)=>this.#logsByTag.getAsync(tag.toString())));
171
- return logs.map((noteLogBuffers)=>noteLogBuffers?.map((noteLogBuffer)=>TxScopedL2Log.fromBuffer(noteLogBuffer)) ?? []);
195
+ * Gets all public logs that match any of the `tags` from the specified contract. For each tag, an array of matching
196
+ * logs is returned. An empty array implies no logs match that tag.
197
+ */ async getPublicLogsByTagsFromContract(contractAddress, tags) {
198
+ const logs = await Promise.all(tags.map((tag)=>{
199
+ const key = `${contractAddress.toString()}_${tag.value.toString()}`;
200
+ return this.#publicLogsByContractAndTag.getAsync(key);
201
+ }));
202
+ return logs.map((logBuffers)=>logBuffers?.map((logBuffer)=>TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
172
203
  }
173
204
  /**
174
205
  * Gets public logs based on the provided filter.
@@ -199,6 +230,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
199
230
  []
200
231
  ];
201
232
  const reader = new BufferReader(buffer);
233
+ const blockHash = this.#unpackBlockHash(reader);
202
234
  while(reader.remainingBytes() > 0){
203
235
  const indexOfTx = reader.readNumber();
204
236
  const numLogsInTx = reader.readNumber();
@@ -209,7 +241,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
209
241
  }
210
242
  const txLogs = publicLogsInBlock[txIndex];
211
243
  const logs = [];
212
- const maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
244
+ const maxLogsHit = this.#accumulateLogs(logs, blockNumber, blockHash, txIndex, txLogs, filter);
213
245
  return {
214
246
  logs,
215
247
  maxLogsHit
@@ -234,6 +266,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
234
266
  []
235
267
  ];
236
268
  const reader = new BufferReader(logBuffer);
269
+ const blockHash = this.#unpackBlockHash(reader);
237
270
  while(reader.remainingBytes() > 0){
238
271
  const indexOfTx = reader.readNumber();
239
272
  const numLogsInTx = reader.readNumber();
@@ -244,7 +277,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
244
277
  }
245
278
  for(let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < publicLogsInBlock.length; txIndex++){
246
279
  const txLogs = publicLogsInBlock[txIndex];
247
- maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
280
+ maxLogsHit = this.#accumulateLogs(logs, blockNumber, blockHash, txIndex, txLogs, filter);
248
281
  if (maxLogsHit) {
249
282
  this.#log.debug(`Max logs hit at block ${blockNumber}`);
250
283
  break loopOverBlocks;
@@ -285,6 +318,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
285
318
  []
286
319
  ];
287
320
  const reader = new BufferReader(contractClassLogsBuffer);
321
+ const blockHash = this.#unpackBlockHash(reader);
288
322
  while(reader.remainingBytes() > 0){
289
323
  const indexOfTx = reader.readNumber();
290
324
  const numLogsInTx = reader.readNumber();
@@ -295,7 +329,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
295
329
  }
296
330
  const txLogs = contractClassLogsInBlock[txIndex];
297
331
  const logs = [];
298
- const maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
332
+ const maxLogsHit = this.#accumulateLogs(logs, blockNumber, blockHash, txIndex, txLogs, filter);
299
333
  return {
300
334
  logs,
301
335
  maxLogsHit
@@ -320,6 +354,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
320
354
  []
321
355
  ];
322
356
  const reader = new BufferReader(logBuffer);
357
+ const blockHash = this.#unpackBlockHash(reader);
323
358
  while(reader.remainingBytes() > 0){
324
359
  const indexOfTx = reader.readNumber();
325
360
  const numLogsInTx = reader.readNumber();
@@ -330,7 +365,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
330
365
  }
331
366
  for(let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < contractClassLogsInBlock.length; txIndex++){
332
367
  const txLogs = contractClassLogsInBlock[txIndex];
333
- maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
368
+ maxLogsHit = this.#accumulateLogs(logs, blockNumber, blockHash, txIndex, txLogs, filter);
334
369
  if (maxLogsHit) {
335
370
  this.#log.debug(`Max logs hit at block ${blockNumber}`);
336
371
  break loopOverBlocks;
@@ -342,16 +377,18 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
342
377
  maxLogsHit
343
378
  };
344
379
  }
345
- #accumulateLogs(results, blockNumber, txIndex, txLogs, filter) {
380
+ #accumulateLogs(results, blockNumber, blockHash, txIndex, txLogs, filter = {}) {
346
381
  let maxLogsHit = false;
347
382
  let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0;
348
383
  for(; logIndex < txLogs.length; logIndex++){
349
384
  const log = txLogs[logIndex];
350
385
  if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) {
351
386
  if (log instanceof ContractClassLog) {
352
- results.push(new ExtendedContractClassLog(new LogId(blockNumber, txIndex, logIndex), log));
387
+ results.push(new ExtendedContractClassLog(new LogId(BlockNumber(blockNumber), blockHash, txIndex, logIndex), log));
388
+ } else if (log instanceof PublicLog) {
389
+ results.push(new ExtendedPublicLog(new LogId(BlockNumber(blockNumber), blockHash, txIndex, logIndex), log));
353
390
  } else {
354
- results.push(new ExtendedPublicLog(new LogId(blockNumber, txIndex, logIndex), log));
391
+ throw new Error('Unknown log type');
355
392
  }
356
393
  if (results.length >= this.#logsMaxPageSize) {
357
394
  maxLogsHit = true;
@@ -1,33 +1,40 @@
1
- import { Fr } from '@aztec/foundation/fields';
2
- import type { AztecAsyncKVStore } from '@aztec/kv-store';
3
- import { InboxLeaf } from '@aztec/stdlib/messaging';
4
- import type { DataRetrieval } from '../structs/data_retrieval.js';
5
- /**
6
- * LMDB implementation of the ArchiverDataStore interface.
7
- */
1
+ import type { L1BlockId } from '@aztec/ethereum/l1-types';
2
+ import { CheckpointNumber } from '@aztec/foundation/branded-types';
3
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
+ import { type AztecAsyncKVStore, type CustomRange } from '@aztec/kv-store';
5
+ import { type InboxMessage } from '../structs/inbox_message.js';
6
+ export declare class MessageStoreError extends Error {
7
+ readonly inboxMessage: InboxMessage;
8
+ constructor(message: string, inboxMessage: InboxMessage);
9
+ }
8
10
  export declare class MessageStore {
9
11
  #private;
10
12
  private db;
11
13
  constructor(db: AztecAsyncKVStore);
12
14
  getTotalL1ToL2MessageCount(): Promise<bigint>;
13
- /**
14
- * Gets the last L1 block number that emitted new messages.
15
- * @returns The last L1 block number processed
16
- */
17
- getSynchedL1BlockNumber(): Promise<bigint | undefined>;
18
- setSynchedL1BlockNumber(l1BlockNumber: bigint): Promise<void>;
15
+ /** Gets the last L1 block synced. */
16
+ getSynchedL1Block(): Promise<L1BlockId | undefined>;
17
+ /** Sets the last L1 block synced */
18
+ setSynchedL1Block(l1Block: L1BlockId): Promise<void>;
19
19
  /**
20
20
  * Append L1 to L2 messages to the store.
21
- * @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block.
22
- * @returns True if the operation is successful.
21
+ * Requires new messages to be in order and strictly after the last message added.
22
+ * Throws if out of order messages are added or if the rolling hash is invalid.
23
23
  */
24
- addL1ToL2Messages(messages: DataRetrieval<InboxLeaf>): Promise<boolean>;
24
+ addL1ToL2Messages(messages: InboxMessage[]): Promise<void>;
25
25
  /**
26
26
  * Gets the L1 to L2 message index in the L1 to L2 message tree.
27
27
  * @param l1ToL2Message - The L1 to L2 message.
28
28
  * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found).
29
29
  */
30
30
  getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined>;
31
- getL1ToL2Messages(blockNumber: bigint): Promise<Fr[]>;
31
+ getLastMessage(): Promise<InboxMessage | undefined>;
32
+ getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]>;
33
+ iterateL1ToL2Messages(range?: CustomRange<bigint>): AsyncIterableIterator<InboxMessage>;
34
+ removeL1ToL2Messages(startIndex: bigint): Promise<void>;
35
+ rollbackL1ToL2MessagesToCheckpoint(targetCheckpointNumber: CheckpointNumber): Promise<void>;
36
+ private indexToKey;
37
+ private leafToIndexKey;
38
+ private increaseTotalMessageCount;
32
39
  }
33
- //# sourceMappingURL=message_store.d.ts.map
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZV9zdG9yZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FyY2hpdmVyL2t2X2FyY2hpdmVyX3N0b3JlL21lc3NhZ2Vfc3RvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsU0FBUyxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDMUQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFbkUsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBSXBELE9BQU8sRUFDTCxLQUFLLGlCQUFpQixFQUd0QixLQUFLLFdBQVcsRUFFakIsTUFBTSxpQkFBaUIsQ0FBQztBQUd6QixPQUFPLEVBQ0wsS0FBSyxZQUFZLEVBSWxCLE1BQU0sNkJBQTZCLENBQUM7QUFFckMscUJBQWEsaUJBQWtCLFNBQVEsS0FBSzthQUd4QixZQUFZLEVBQUUsWUFBWTtJQUY1QyxZQUNFLE9BQU8sRUFBRSxNQUFNLEVBQ0MsWUFBWSxFQUFFLFlBQVksRUFJM0M7Q0FDRjtBQUVELHFCQUFhLFlBQVk7O0lBWVgsT0FBTyxDQUFDLEVBQUU7SUFBdEIsWUFBb0IsRUFBRSxFQUFFLGlCQUFpQixFQUt4QztJQUVZLDBCQUEwQixJQUFJLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FFekQ7SUFFRCxxQ0FBcUM7SUFDeEIsaUJBQWlCLElBQUksT0FBTyxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUMsQ0FRL0Q7SUFFRCxvQ0FBb0M7SUFDdkIsaUJBQWlCLENBQUMsT0FBTyxFQUFFLFNBQVMsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBR2hFO0lBRUQ7Ozs7T0FJRztJQUNJLGlCQUFpQixDQUFDLFFBQVEsRUFBRSxZQUFZLEVBQUUsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBNkZoRTtJQUVEOzs7O09BSUc7SUFDSSxxQkFBcUIsQ0FBQyxhQUFhLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDLENBRTNFO0lBRVksY0FBYyxJQUFJLE9BQU8sQ0FBQyxZQUFZLEdBQUcsU0FBUyxDQUFDLENBRy9EO0lBRVksaUJBQWlCLENBQUMsZ0JBQWdCLEVBQUUsZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBdUJoRjtJQUVhLHFCQUFxQixDQUFDLEtBQUssR0FBRSxXQUFXLENBQUMsTUFBTSxDQUFNLEdBQUcscUJBQXFCLENBQUMsWUFBWSxDQUFDLENBS3hHO0lBRU0sb0JBQW9CLENBQUMsVUFBVSxFQUFFLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBZ0I3RDtJQUVNLGtDQUFrQyxDQUFDLHNCQUFzQixFQUFFLGdCQUFnQixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FJakc7SUFFRCxPQUFPLENBQUMsVUFBVTtJQUlsQixPQUFPLENBQUMsY0FBYztZQUlSLHlCQUF5QjtDQVN4QyJ9
@@ -1 +1 @@
1
- {"version":3,"file":"message_store.d.ts","sourceRoot":"","sources":["../../../src/archiver/kv_archiver_store/message_store.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAE9C,OAAO,KAAK,EAAE,iBAAiB,EAAsC,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE;;GAEG;AACH,qBAAa,YAAY;;IAUX,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,iBAAiB;IAOnC,0BAA0B,IAAI,OAAO,CAAC,MAAM,CAAC;IAInD;;;OAGG;IACH,uBAAuB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAIhD,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInE;;;;OAIG;IACH,iBAAiB,CAAC,QAAQ,EAAE,aAAa,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBvE;;;;OAIG;IACH,qBAAqB,CAAC,aAAa,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAI/D,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,EAAE,CAAC;CAqB5D"}
1
+ {"version":3,"file":"message_store.d.ts","sourceRoot":"","sources":["../../../src/archiver/kv_archiver_store/message_store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AAIpD,OAAO,EACL,KAAK,iBAAiB,EAGtB,KAAK,WAAW,EAEjB,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,6BAA6B,CAAC;AAErC,qBAAa,iBAAkB,SAAQ,KAAK;aAGxB,YAAY,EAAE,YAAY;IAF5C,YACE,OAAO,EAAE,MAAM,EACC,YAAY,EAAE,YAAY,EAI3C;CACF;AAED,qBAAa,YAAY;;IAYX,OAAO,CAAC,EAAE;IAAtB,YAAoB,EAAE,EAAE,iBAAiB,EAKxC;IAEY,0BAA0B,IAAI,OAAO,CAAC,MAAM,CAAC,CAEzD;IAED,qCAAqC;IACxB,iBAAiB,IAAI,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAQ/D;IAED,oCAAoC;IACvB,iBAAiB,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhE;IAED;;;;OAIG;IACI,iBAAiB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6FhE;IAED;;;;OAIG;IACI,qBAAqB,CAAC,aAAa,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE3E;IAEY,cAAc,IAAI,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAG/D;IAEY,iBAAiB,CAAC,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAAC,EAAE,EAAE,CAAC,CAuBhF;IAEa,qBAAqB,CAAC,KAAK,GAAE,WAAW,CAAC,MAAM,CAAM,GAAG,qBAAqB,CAAC,YAAY,CAAC,CAKxG;IAEM,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB7D;IAEM,kCAAkC,CAAC,sBAAsB,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIjG;IAED,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,cAAc;YAIR,yBAAyB;CASxC"}