@aztec/archiver 0.0.0-test.1 → 0.0.1-commit.03f7ef2

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 +201 -94
  3. package/dest/archiver/archiver.d.ts.map +1 -1
  4. package/dest/archiver/archiver.js +1141 -396
  5. package/dest/archiver/archiver_store.d.ts +171 -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 +2389 -393
  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 +69 -17
  22. package/dest/archiver/kv_archiver_store/block_store.d.ts +91 -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 +476 -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 +80 -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 +142 -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 +153 -113
  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 +21 -7
  90. package/dest/test/mock_l2_block_source.d.ts +52 -13
  91. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  92. package/dest/test/mock_l2_block_source.js +140 -15
  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 +1477 -501
  98. package/src/archiver/archiver_store.ts +197 -88
  99. package/src/archiver/archiver_store_test_suite.ts +2403 -350
  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 +91 -22
  104. package/src/archiver/kv_archiver_store/block_store.ts +640 -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 +193 -113
  108. package/src/archiver/kv_archiver_store/log_store.ts +205 -127
  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 +20 -8
  134. package/src/test/mock_l2_block_source.ts +186 -21
  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, MAX_NOTE_HASHES_PER_TX } 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,121 @@ 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();
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
+ */ async #extractTaggedLogsFromBlock(block) {
41
+ const blockHash = L2BlockHash.fromField(await block.hash());
42
+ // SiloedTag (as string) -> array of log buffers.
43
+ const privateTaggedLogs = new Map();
44
+ // "{contractAddress}_{tag}" (as string) -> array of log buffers.
45
+ const publicTaggedLogs = new Map();
30
46
  const dataStartIndexForBlock = block.header.state.partial.noteHashTree.nextAvailableLeafIndex - block.body.txEffects.length * MAX_NOTE_HASHES_PER_TX;
31
47
  block.body.txEffects.forEach((txEffect, txIndex)=>{
32
48
  const txHash = txEffect.txHash;
33
49
  const dataStartIndexForTx = dataStartIndexForBlock + txIndex * MAX_NOTE_HASHES_PER_TX;
34
- txEffect.privateLogs.forEach((log)=>{
50
+ txEffect.privateLogs.forEach((log, logIndex)=>{
51
+ // Private logs use SiloedTag (already siloed by kernel)
35
52
  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);
53
+ this.#log.debug(`Found private log with tag ${tag.toString()} in block ${block.number}`);
54
+ const currentLogs = privateTaggedLogs.get(tag.toString()) ?? [];
55
+ currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, logIndex, block.number, blockHash, block.timestamp, log).toBuffer());
56
+ privateTaggedLogs.set(tag.toString(), currentLogs);
39
57
  });
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
- 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);
58
+ txEffect.publicLogs.forEach((log, logIndex)=>{
59
+ // Public logs use Tag directly (not siloed) and are stored with contract address
60
+ const tag = log.fields[0];
61
+ const contractAddress = log.contractAddress;
62
+ const key = `${contractAddress.toString()}_${tag.toString()}`;
63
+ this.#log.debug(`Found public log with tag ${tag.toString()} from contract ${contractAddress.toString()} in block ${block.number}`);
64
+ const currentLogs = publicTaggedLogs.get(key) ?? [];
65
+ currentLogs.push(new TxScopedL2Log(txHash, dataStartIndexForTx, logIndex, block.number, blockHash, block.timestamp, log).toBuffer());
66
+ publicTaggedLogs.set(key, currentLogs);
76
67
  });
77
68
  });
78
- return taggedLogs;
69
+ return {
70
+ privateTaggedLogs,
71
+ publicTaggedLogs
72
+ };
79
73
  }
80
74
  /**
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()){
75
+ * Extracts and aggregates tagged logs from a list of blocks.
76
+ * @param blocks - The blocks to extract logs from.
77
+ * @returns A map from tag (as string) to an array of serialized private logs belonging to that tag, and a map from
78
+ * "{contractAddress}_{tag}" (as string) to an array of serialized public logs belonging to that key.
79
+ */ async #extractTaggedLogs(blocks) {
80
+ const taggedLogsInBlocks = await Promise.all(blocks.map((block)=>this.#extractTaggedLogsFromBlock(block)));
81
+ // Now we merge the maps from each block into a single map.
82
+ const privateTaggedLogs = taggedLogsInBlocks.reduce((acc, { privateTaggedLogs })=>{
83
+ for (const [tag, logs] of privateTaggedLogs.entries()){
90
84
  const currentLogs = acc.get(tag) ?? [];
91
85
  acc.set(tag, currentLogs.concat(logs));
92
86
  }
93
87
  return acc;
94
- });
95
- const tagsToUpdate = Array.from(taggedLogsToAdd.keys());
88
+ }, new Map());
89
+ const publicTaggedLogs = taggedLogsInBlocks.reduce((acc, { publicTaggedLogs })=>{
90
+ for (const [key, logs] of publicTaggedLogs.entries()){
91
+ const currentLogs = acc.get(key) ?? [];
92
+ acc.set(key, currentLogs.concat(logs));
93
+ }
94
+ return acc;
95
+ }, new Map());
96
+ return {
97
+ privateTaggedLogs,
98
+ publicTaggedLogs
99
+ };
100
+ }
101
+ /**
102
+ * Append new logs to the store's list.
103
+ * @param blocks - The blocks for which to add the logs.
104
+ * @returns True if the operation is successful.
105
+ */ async addLogs(blocks) {
106
+ const { privateTaggedLogs, publicTaggedLogs } = await this.#extractTaggedLogs(blocks);
107
+ const keysOfPrivateLogsToUpdate = Array.from(privateTaggedLogs.keys());
108
+ const keysOfPublicLogsToUpdate = Array.from(publicTaggedLogs.keys());
96
109
  return this.db.transactionAsync(async ()=>{
97
- const currentTaggedLogs = await Promise.all(tagsToUpdate.map(async (tag)=>({
98
- tag,
99
- logBuffers: await this.#logsByTag.getAsync(tag)
110
+ const currentPrivateTaggedLogs = await Promise.all(keysOfPrivateLogsToUpdate.map(async (key)=>({
111
+ tag: key,
112
+ logBuffers: await this.#privateLogsByTag.getAsync(key)
100
113
  })));
101
- currentTaggedLogs.forEach((taggedLogBuffer)=>{
114
+ currentPrivateTaggedLogs.forEach((taggedLogBuffer)=>{
102
115
  if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
103
- taggedLogsToAdd.set(taggedLogBuffer.tag, taggedLogBuffer.logBuffers.concat(taggedLogsToAdd.get(taggedLogBuffer.tag)));
116
+ privateTaggedLogs.set(taggedLogBuffer.tag, taggedLogBuffer.logBuffers.concat(privateTaggedLogs.get(taggedLogBuffer.tag)));
117
+ }
118
+ });
119
+ const currentPublicTaggedLogs = await Promise.all(keysOfPublicLogsToUpdate.map(async (key)=>({
120
+ key,
121
+ logBuffers: await this.#publicLogsByContractAndTag.getAsync(key)
122
+ })));
123
+ currentPublicTaggedLogs.forEach((taggedLogBuffer)=>{
124
+ if (taggedLogBuffer.logBuffers && taggedLogBuffer.logBuffers.length > 0) {
125
+ publicTaggedLogs.set(taggedLogBuffer.key, taggedLogBuffer.logBuffers.concat(publicTaggedLogs.get(taggedLogBuffer.key)));
104
126
  }
105
127
  });
106
128
  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);
129
+ const blockHash = await block.hash();
130
+ const privateTagsInBlock = [];
131
+ for (const [tag, logs] of privateTaggedLogs.entries()){
132
+ await this.#privateLogsByTag.set(tag, logs);
133
+ privateTagsInBlock.push(tag);
134
+ }
135
+ await this.#privateLogKeysByBlock.set(block.number, privateTagsInBlock);
136
+ const publicKeysInBlock = [];
137
+ for (const [key, logs] of publicTaggedLogs.entries()){
138
+ await this.#publicLogsByContractAndTag.set(key, logs);
139
+ publicKeysInBlock.push(key);
111
140
  }
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));
141
+ await this.#publicLogKeysByBlock.set(block.number, publicKeysInBlock);
115
142
  const publicLogsInBlock = block.body.txEffects.map((txEffect, txIndex)=>[
116
143
  numToUInt32BE(txIndex),
117
144
  numToUInt32BE(txEffect.publicLogs.length),
@@ -122,53 +149,60 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
122
149
  numToUInt32BE(txEffect.contractClassLogs.length),
123
150
  txEffect.contractClassLogs.map((log)=>log.toBuffer())
124
151
  ].flat()).flat();
125
- await this.#publicLogsByBlock.set(block.number, Buffer.concat(publicLogsInBlock));
126
- await this.#contractClassLogsByBlock.set(block.number, Buffer.concat(contractClassLogsInBlock));
152
+ await this.#publicLogsByBlock.set(block.number, this.#packWithBlockHash(blockHash, publicLogsInBlock));
153
+ await this.#contractClassLogsByBlock.set(block.number, this.#packWithBlockHash(blockHash, contractClassLogsInBlock));
127
154
  }
128
155
  return true;
129
156
  });
130
157
  }
158
+ #packWithBlockHash(blockHash, data) {
159
+ return Buffer.concat([
160
+ blockHash.toBuffer(),
161
+ ...data
162
+ ]);
163
+ }
164
+ #unpackBlockHash(reader) {
165
+ const blockHash = reader.remainingBytes() > 0 ? reader.readObject(Fr) : undefined;
166
+ if (!blockHash) {
167
+ throw new Error('Failed to read block hash from log entry buffer');
168
+ }
169
+ return L2BlockHash.fromField(blockHash);
170
+ }
131
171
  deleteLogs(blocks) {
132
172
  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();
173
+ await Promise.all(blocks.map(async (block)=>{
174
+ // Delete private logs
175
+ const privateKeys = await this.#privateLogKeysByBlock.getAsync(block.number) ?? [];
176
+ await Promise.all(privateKeys.map((tag)=>this.#privateLogsByTag.delete(tag)));
177
+ // Delete public logs
178
+ const publicKeys = await this.#publicLogKeysByBlock.getAsync(block.number) ?? [];
179
+ await Promise.all(publicKeys.map((key)=>this.#publicLogsByContractAndTag.delete(key)));
180
+ }));
137
181
  await Promise.all(blocks.map((block)=>Promise.all([
138
- this.#privateLogsByBlock.delete(block.number),
139
182
  this.#publicLogsByBlock.delete(block.number),
140
- this.#logTagsByBlock.delete(block.number)
183
+ this.#privateLogKeysByBlock.delete(block.number),
184
+ this.#publicLogKeysByBlock.delete(block.number),
185
+ this.#contractClassLogsByBlock.delete(block.number)
141
186
  ])));
142
- await Promise.all(tagsToDelete.map((tag)=>this.#logsByTag.delete(tag.toString())));
143
187
  return true;
144
188
  });
145
189
  }
146
190
  /**
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;
191
+ * Gets all private logs that match any of the `tags`. For each tag, an array of matching logs is returned. An empty
192
+ * array implies no logs match that tag.
193
+ */ async getPrivateLogsByTags(tags) {
194
+ const logs = await Promise.all(tags.map((tag)=>this.#privateLogsByTag.getAsync(tag.toString())));
195
+ return logs.map((logBuffers)=>logBuffers?.map((logBuffer)=>TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
163
196
  }
164
197
  /**
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)) ?? []);
198
+ * Gets all public logs that match any of the `tags` from the specified contract. For each tag, an array of matching
199
+ * logs is returned. An empty array implies no logs match that tag.
200
+ */ async getPublicLogsByTagsFromContract(contractAddress, tags) {
201
+ const logs = await Promise.all(tags.map((tag)=>{
202
+ const key = `${contractAddress.toString()}_${tag.value.toString()}`;
203
+ return this.#publicLogsByContractAndTag.getAsync(key);
204
+ }));
205
+ return logs.map((logBuffers)=>logBuffers?.map((logBuffer)=>TxScopedL2Log.fromBuffer(logBuffer)) ?? []);
172
206
  }
173
207
  /**
174
208
  * Gets public logs based on the provided filter.
@@ -199,6 +233,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
199
233
  []
200
234
  ];
201
235
  const reader = new BufferReader(buffer);
236
+ const blockHash = this.#unpackBlockHash(reader);
202
237
  while(reader.remainingBytes() > 0){
203
238
  const indexOfTx = reader.readNumber();
204
239
  const numLogsInTx = reader.readNumber();
@@ -209,7 +244,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
209
244
  }
210
245
  const txLogs = publicLogsInBlock[txIndex];
211
246
  const logs = [];
212
- const maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
247
+ const maxLogsHit = this.#accumulateLogs(logs, blockNumber, blockHash, txIndex, txLogs, filter);
213
248
  return {
214
249
  logs,
215
250
  maxLogsHit
@@ -234,6 +269,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
234
269
  []
235
270
  ];
236
271
  const reader = new BufferReader(logBuffer);
272
+ const blockHash = this.#unpackBlockHash(reader);
237
273
  while(reader.remainingBytes() > 0){
238
274
  const indexOfTx = reader.readNumber();
239
275
  const numLogsInTx = reader.readNumber();
@@ -244,7 +280,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
244
280
  }
245
281
  for(let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < publicLogsInBlock.length; txIndex++){
246
282
  const txLogs = publicLogsInBlock[txIndex];
247
- maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
283
+ maxLogsHit = this.#accumulateLogs(logs, blockNumber, blockHash, txIndex, txLogs, filter);
248
284
  if (maxLogsHit) {
249
285
  this.#log.debug(`Max logs hit at block ${blockNumber}`);
250
286
  break loopOverBlocks;
@@ -285,6 +321,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
285
321
  []
286
322
  ];
287
323
  const reader = new BufferReader(contractClassLogsBuffer);
324
+ const blockHash = this.#unpackBlockHash(reader);
288
325
  while(reader.remainingBytes() > 0){
289
326
  const indexOfTx = reader.readNumber();
290
327
  const numLogsInTx = reader.readNumber();
@@ -295,7 +332,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
295
332
  }
296
333
  const txLogs = contractClassLogsInBlock[txIndex];
297
334
  const logs = [];
298
- const maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
335
+ const maxLogsHit = this.#accumulateLogs(logs, blockNumber, blockHash, txIndex, txLogs, filter);
299
336
  return {
300
337
  logs,
301
338
  maxLogsHit
@@ -320,6 +357,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
320
357
  []
321
358
  ];
322
359
  const reader = new BufferReader(logBuffer);
360
+ const blockHash = this.#unpackBlockHash(reader);
323
361
  while(reader.remainingBytes() > 0){
324
362
  const indexOfTx = reader.readNumber();
325
363
  const numLogsInTx = reader.readNumber();
@@ -330,7 +368,7 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
330
368
  }
331
369
  for(let txIndex = filter.afterLog?.txIndex ?? 0; txIndex < contractClassLogsInBlock.length; txIndex++){
332
370
  const txLogs = contractClassLogsInBlock[txIndex];
333
- maxLogsHit = this.#accumulateLogs(logs, blockNumber, txIndex, txLogs, filter);
371
+ maxLogsHit = this.#accumulateLogs(logs, blockNumber, blockHash, txIndex, txLogs, filter);
334
372
  if (maxLogsHit) {
335
373
  this.#log.debug(`Max logs hit at block ${blockNumber}`);
336
374
  break loopOverBlocks;
@@ -342,16 +380,18 @@ import { ContractClassLog, ExtendedContractClassLog, ExtendedPublicLog, LogId, P
342
380
  maxLogsHit
343
381
  };
344
382
  }
345
- #accumulateLogs(results, blockNumber, txIndex, txLogs, filter) {
383
+ #accumulateLogs(results, blockNumber, blockHash, txIndex, txLogs, filter = {}) {
346
384
  let maxLogsHit = false;
347
385
  let logIndex = typeof filter.afterLog?.logIndex === 'number' ? filter.afterLog.logIndex + 1 : 0;
348
386
  for(; logIndex < txLogs.length; logIndex++){
349
387
  const log = txLogs[logIndex];
350
388
  if (!filter.contractAddress || log.contractAddress.equals(filter.contractAddress)) {
351
389
  if (log instanceof ContractClassLog) {
352
- results.push(new ExtendedContractClassLog(new LogId(blockNumber, txIndex, logIndex), log));
390
+ results.push(new ExtendedContractClassLog(new LogId(BlockNumber(blockNumber), blockHash, txIndex, logIndex), log));
391
+ } else if (log instanceof PublicLog) {
392
+ results.push(new ExtendedPublicLog(new LogId(BlockNumber(blockNumber), blockHash, txIndex, logIndex), log));
353
393
  } else {
354
- results.push(new ExtendedPublicLog(new LogId(blockNumber, txIndex, logIndex), log));
394
+ throw new Error('Unknown log type');
355
395
  }
356
396
  if (results.length >= this.#logsMaxPageSize) {
357
397
  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"}