@aztec/archiver 0.0.1-commit.d3ec352c → 0.0.1-commit.e3c1de76

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 (205) hide show
  1. package/README.md +156 -22
  2. package/dest/archiver.d.ts +136 -0
  3. package/dest/archiver.d.ts.map +1 -0
  4. package/dest/archiver.js +781 -0
  5. package/dest/config.d.ts +30 -0
  6. package/dest/config.d.ts.map +1 -0
  7. package/dest/{archiver/config.js → config.js} +21 -5
  8. package/dest/errors.d.ts +41 -0
  9. package/dest/errors.d.ts.map +1 -0
  10. package/dest/errors.js +62 -0
  11. package/dest/factory.d.ts +9 -7
  12. package/dest/factory.d.ts.map +1 -1
  13. package/dest/factory.js +89 -11
  14. package/dest/index.d.ts +10 -4
  15. package/dest/index.d.ts.map +1 -1
  16. package/dest/index.js +8 -3
  17. package/dest/interfaces.d.ts +9 -0
  18. package/dest/interfaces.d.ts.map +1 -0
  19. package/dest/interfaces.js +3 -0
  20. package/dest/l1/bin/retrieve-calldata.d.ts +3 -0
  21. package/dest/l1/bin/retrieve-calldata.d.ts.map +1 -0
  22. package/dest/l1/bin/retrieve-calldata.js +149 -0
  23. package/dest/l1/calldata_retriever.d.ts +112 -0
  24. package/dest/l1/calldata_retriever.d.ts.map +1 -0
  25. package/dest/l1/calldata_retriever.js +471 -0
  26. package/dest/l1/data_retrieval.d.ts +88 -0
  27. package/dest/l1/data_retrieval.d.ts.map +1 -0
  28. package/dest/{archiver → l1}/data_retrieval.js +75 -150
  29. package/dest/l1/debug_tx.d.ts +19 -0
  30. package/dest/l1/debug_tx.d.ts.map +1 -0
  31. package/dest/l1/debug_tx.js +73 -0
  32. package/dest/l1/spire_proposer.d.ts +70 -0
  33. package/dest/l1/spire_proposer.d.ts.map +1 -0
  34. package/dest/l1/spire_proposer.js +157 -0
  35. package/dest/l1/trace_tx.d.ts +97 -0
  36. package/dest/l1/trace_tx.d.ts.map +1 -0
  37. package/dest/l1/trace_tx.js +91 -0
  38. package/dest/l1/types.d.ts +12 -0
  39. package/dest/l1/types.d.ts.map +1 -0
  40. package/dest/l1/types.js +3 -0
  41. package/dest/l1/validate_trace.d.ts +32 -0
  42. package/dest/l1/validate_trace.d.ts.map +1 -0
  43. package/dest/l1/validate_trace.js +154 -0
  44. package/dest/modules/data_source_base.d.ts +84 -0
  45. package/dest/modules/data_source_base.d.ts.map +1 -0
  46. package/dest/modules/data_source_base.js +260 -0
  47. package/dest/modules/data_store_updater.d.ts +73 -0
  48. package/dest/modules/data_store_updater.d.ts.map +1 -0
  49. package/dest/modules/data_store_updater.js +302 -0
  50. package/dest/modules/instrumentation.d.ts +37 -0
  51. package/dest/modules/instrumentation.d.ts.map +1 -0
  52. package/dest/{archiver → modules}/instrumentation.js +30 -60
  53. package/dest/modules/l1_synchronizer.d.ts +75 -0
  54. package/dest/modules/l1_synchronizer.d.ts.map +1 -0
  55. package/dest/modules/l1_synchronizer.js +1112 -0
  56. package/dest/modules/validation.d.ts +17 -0
  57. package/dest/modules/validation.d.ts.map +1 -0
  58. package/dest/{archiver → modules}/validation.js +7 -1
  59. package/dest/store/block_store.d.ts +192 -0
  60. package/dest/store/block_store.d.ts.map +1 -0
  61. package/dest/store/block_store.js +721 -0
  62. package/dest/store/contract_class_store.d.ts +18 -0
  63. package/dest/store/contract_class_store.d.ts.map +1 -0
  64. package/dest/{archiver/kv_archiver_store → store}/contract_class_store.js +13 -9
  65. package/dest/store/contract_instance_store.d.ts +24 -0
  66. package/dest/store/contract_instance_store.d.ts.map +1 -0
  67. package/dest/{archiver/kv_archiver_store → store}/contract_instance_store.js +1 -1
  68. package/dest/store/kv_archiver_store.d.ts +340 -0
  69. package/dest/store/kv_archiver_store.d.ts.map +1 -0
  70. package/dest/store/kv_archiver_store.js +446 -0
  71. package/dest/store/log_store.d.ts +54 -0
  72. package/dest/store/log_store.d.ts.map +1 -0
  73. package/dest/store/log_store.js +436 -0
  74. package/dest/store/message_store.d.ts +40 -0
  75. package/dest/store/message_store.d.ts.map +1 -0
  76. package/dest/{archiver/kv_archiver_store → store}/message_store.js +15 -14
  77. package/dest/{archiver/structs → structs}/data_retrieval.d.ts +1 -1
  78. package/dest/structs/data_retrieval.d.ts.map +1 -0
  79. package/dest/structs/inbox_message.d.ts +15 -0
  80. package/dest/structs/inbox_message.d.ts.map +1 -0
  81. package/dest/{archiver/structs → structs}/inbox_message.js +6 -6
  82. package/dest/structs/published.d.ts +2 -0
  83. package/dest/structs/published.d.ts.map +1 -0
  84. package/dest/test/fake_l1_state.d.ts +190 -0
  85. package/dest/test/fake_l1_state.d.ts.map +1 -0
  86. package/dest/test/fake_l1_state.js +383 -0
  87. package/dest/test/index.d.ts +2 -1
  88. package/dest/test/index.d.ts.map +1 -1
  89. package/dest/test/index.js +4 -1
  90. package/dest/test/mock_archiver.d.ts +5 -6
  91. package/dest/test/mock_archiver.d.ts.map +1 -1
  92. package/dest/test/mock_archiver.js +6 -11
  93. package/dest/test/mock_l1_to_l2_message_source.d.ts +6 -7
  94. package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
  95. package/dest/test/mock_l1_to_l2_message_source.js +19 -14
  96. package/dest/test/mock_l2_block_source.d.ts +30 -16
  97. package/dest/test/mock_l2_block_source.d.ts.map +1 -1
  98. package/dest/test/mock_l2_block_source.js +175 -68
  99. package/dest/test/mock_structs.d.ts +80 -4
  100. package/dest/test/mock_structs.d.ts.map +1 -1
  101. package/dest/test/mock_structs.js +145 -12
  102. package/dest/test/noop_l1_archiver.d.ts +23 -0
  103. package/dest/test/noop_l1_archiver.d.ts.map +1 -0
  104. package/dest/test/noop_l1_archiver.js +68 -0
  105. package/package.json +18 -18
  106. package/src/archiver.ts +543 -0
  107. package/src/{archiver/config.ts → config.ts} +28 -12
  108. package/src/errors.ts +102 -0
  109. package/src/factory.ts +125 -11
  110. package/src/index.ts +10 -3
  111. package/src/interfaces.ts +9 -0
  112. package/src/l1/README.md +98 -0
  113. package/src/l1/bin/retrieve-calldata.ts +187 -0
  114. package/src/l1/calldata_retriever.ts +641 -0
  115. package/src/{archiver → l1}/data_retrieval.ts +138 -220
  116. package/src/l1/debug_tx.ts +99 -0
  117. package/src/l1/spire_proposer.ts +160 -0
  118. package/src/l1/trace_tx.ts +128 -0
  119. package/src/l1/types.ts +13 -0
  120. package/src/l1/validate_trace.ts +229 -0
  121. package/src/modules/data_source_base.ts +367 -0
  122. package/src/modules/data_store_updater.ts +423 -0
  123. package/src/{archiver → modules}/instrumentation.ts +34 -64
  124. package/src/modules/l1_synchronizer.ts +930 -0
  125. package/src/{archiver → modules}/validation.ts +11 -6
  126. package/src/store/block_store.ts +966 -0
  127. package/src/{archiver/kv_archiver_store → store}/contract_class_store.ts +13 -9
  128. package/src/{archiver/kv_archiver_store → store}/contract_instance_store.ts +2 -2
  129. package/src/store/kv_archiver_store.ts +639 -0
  130. package/src/store/log_store.ts +575 -0
  131. package/src/{archiver/kv_archiver_store → store}/message_store.ts +21 -18
  132. package/src/{archiver/structs → structs}/inbox_message.ts +7 -8
  133. package/src/{archiver/structs → structs}/published.ts +0 -1
  134. package/src/test/fake_l1_state.ts +599 -0
  135. package/src/test/fixtures/debug_traceTransaction-multicall3.json +88 -0
  136. package/src/test/fixtures/debug_traceTransaction-multiplePropose.json +153 -0
  137. package/src/test/fixtures/debug_traceTransaction-proxied.json +122 -0
  138. package/src/test/fixtures/trace_transaction-multicall3.json +65 -0
  139. package/src/test/fixtures/trace_transaction-multiplePropose.json +319 -0
  140. package/src/test/fixtures/trace_transaction-proxied.json +128 -0
  141. package/src/test/fixtures/trace_transaction-randomRevert.json +216 -0
  142. package/src/test/index.ts +4 -0
  143. package/src/test/mock_archiver.ts +8 -13
  144. package/src/test/mock_l1_to_l2_message_source.ts +16 -15
  145. package/src/test/mock_l2_block_source.ts +191 -81
  146. package/src/test/mock_structs.ts +275 -14
  147. package/src/test/noop_l1_archiver.ts +109 -0
  148. package/dest/archiver/archiver.d.ts +0 -290
  149. package/dest/archiver/archiver.d.ts.map +0 -1
  150. package/dest/archiver/archiver.js +0 -1434
  151. package/dest/archiver/archiver_store.d.ts +0 -256
  152. package/dest/archiver/archiver_store.d.ts.map +0 -1
  153. package/dest/archiver/archiver_store.js +0 -4
  154. package/dest/archiver/archiver_store_test_suite.d.ts +0 -8
  155. package/dest/archiver/archiver_store_test_suite.d.ts.map +0 -1
  156. package/dest/archiver/archiver_store_test_suite.js +0 -1289
  157. package/dest/archiver/config.d.ts +0 -21
  158. package/dest/archiver/config.d.ts.map +0 -1
  159. package/dest/archiver/data_retrieval.d.ts +0 -80
  160. package/dest/archiver/data_retrieval.d.ts.map +0 -1
  161. package/dest/archiver/errors.d.ts +0 -12
  162. package/dest/archiver/errors.d.ts.map +0 -1
  163. package/dest/archiver/errors.js +0 -17
  164. package/dest/archiver/index.d.ts +0 -7
  165. package/dest/archiver/index.d.ts.map +0 -1
  166. package/dest/archiver/index.js +0 -4
  167. package/dest/archiver/instrumentation.d.ts +0 -35
  168. package/dest/archiver/instrumentation.d.ts.map +0 -1
  169. package/dest/archiver/kv_archiver_store/block_store.d.ts +0 -125
  170. package/dest/archiver/kv_archiver_store/block_store.d.ts.map +0 -1
  171. package/dest/archiver/kv_archiver_store/block_store.js +0 -371
  172. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +0 -18
  173. package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +0 -1
  174. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +0 -24
  175. package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +0 -1
  176. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +0 -169
  177. package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +0 -1
  178. package/dest/archiver/kv_archiver_store/kv_archiver_store.js +0 -296
  179. package/dest/archiver/kv_archiver_store/log_store.d.ts +0 -49
  180. package/dest/archiver/kv_archiver_store/log_store.d.ts.map +0 -1
  181. package/dest/archiver/kv_archiver_store/log_store.js +0 -337
  182. package/dest/archiver/kv_archiver_store/message_store.d.ts +0 -39
  183. package/dest/archiver/kv_archiver_store/message_store.d.ts.map +0 -1
  184. package/dest/archiver/structs/data_retrieval.d.ts.map +0 -1
  185. package/dest/archiver/structs/inbox_message.d.ts +0 -15
  186. package/dest/archiver/structs/inbox_message.d.ts.map +0 -1
  187. package/dest/archiver/structs/published.d.ts +0 -3
  188. package/dest/archiver/structs/published.d.ts.map +0 -1
  189. package/dest/archiver/validation.d.ts +0 -17
  190. package/dest/archiver/validation.d.ts.map +0 -1
  191. package/dest/rpc/index.d.ts +0 -9
  192. package/dest/rpc/index.d.ts.map +0 -1
  193. package/dest/rpc/index.js +0 -15
  194. package/src/archiver/archiver.ts +0 -1880
  195. package/src/archiver/archiver_store.ts +0 -310
  196. package/src/archiver/archiver_store_test_suite.ts +0 -1295
  197. package/src/archiver/errors.ts +0 -26
  198. package/src/archiver/index.ts +0 -6
  199. package/src/archiver/kv_archiver_store/block_store.ts +0 -482
  200. package/src/archiver/kv_archiver_store/kv_archiver_store.ts +0 -423
  201. package/src/archiver/kv_archiver_store/log_store.ts +0 -407
  202. package/src/rpc/index.ts +0 -16
  203. /package/dest/{archiver/structs → structs}/data_retrieval.js +0 -0
  204. /package/dest/{archiver/structs → structs}/published.js +0 -0
  205. /package/src/{archiver/structs → structs}/data_retrieval.ts +0 -0
@@ -1,1289 +0,0 @@
1
- import { INITIAL_L2_BLOCK_NUM, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, PRIVATE_LOG_SIZE_IN_FIELDS } from '@aztec/constants';
2
- import { makeTuple } from '@aztec/foundation/array';
3
- import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types';
4
- import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
5
- import { times, timesParallel } from '@aztec/foundation/collection';
6
- import { randomInt } from '@aztec/foundation/crypto';
7
- import { Fr } from '@aztec/foundation/fields';
8
- import { toArray } from '@aztec/foundation/iterable';
9
- import { sleep } from '@aztec/foundation/sleep';
10
- import { AztecAddress } from '@aztec/stdlib/aztec-address';
11
- import { CommitteeAttestation, EthAddress, L2Block, L2BlockHash, PublishedL2Block, randomBlockInfo, wrapInBlock } from '@aztec/stdlib/block';
12
- import { SerializableContractInstance, computePublicBytecodeCommitment } from '@aztec/stdlib/contract';
13
- import { LogId, PrivateLog, PublicLog } from '@aztec/stdlib/logs';
14
- import { InboxLeaf } from '@aztec/stdlib/messaging';
15
- import { makeContractClassPublic, makeExecutablePrivateFunctionWithMembershipProof, makeUtilityFunctionWithMembershipProof } from '@aztec/stdlib/testing';
16
- import '@aztec/stdlib/testing/jest';
17
- import { TxEffect, TxHash } from '@aztec/stdlib/tx';
18
- import { makeInboxMessage, makeInboxMessages } from '../test/mock_structs.js';
19
- import { BlockNumberNotSequentialError, InitialBlockNumberNotSequentialError } from './errors.js';
20
- import { MessageStoreError } from './kv_archiver_store/message_store.js';
21
- /**
22
- * @param testName - The name of the test suite.
23
- * @param getStore - Returns an instance of a store that's already been initialized.
24
- */ export function describeArchiverDataStore(testName, getStore) {
25
- describe(testName, ()=>{
26
- let store;
27
- let blocks;
28
- const blockTests = [
29
- [
30
- 1,
31
- 1,
32
- ()=>blocks.slice(0, 1)
33
- ],
34
- [
35
- 10,
36
- 1,
37
- ()=>blocks.slice(9, 10)
38
- ],
39
- [
40
- 1,
41
- 10,
42
- ()=>blocks.slice(0, 10)
43
- ],
44
- [
45
- 2,
46
- 5,
47
- ()=>blocks.slice(1, 6)
48
- ],
49
- [
50
- 5,
51
- 2,
52
- ()=>blocks.slice(4, 6)
53
- ]
54
- ];
55
- const makeBlockHash = (blockNumber)=>`0x${blockNumber.toString(16).padStart(64, '0')}`;
56
- const makePublished = (block, l1BlockNumber)=>PublishedL2Block.fromFields({
57
- block: block,
58
- l1: {
59
- blockNumber: BigInt(l1BlockNumber),
60
- blockHash: makeBlockHash(l1BlockNumber),
61
- timestamp: BigInt(l1BlockNumber * 1000)
62
- },
63
- attestations: times(3, CommitteeAttestation.random)
64
- });
65
- const expectBlocksEqual = (actual, expected)=>{
66
- expect(actual.length).toEqual(expected.length);
67
- for(let i = 0; i < expected.length; i++){
68
- const expectedBlock = expected[i];
69
- const actualBlock = actual[i];
70
- expect(actualBlock.l1).toEqual(expectedBlock.l1);
71
- expect(actualBlock.block.equals(expectedBlock.block)).toBe(true);
72
- expect(actualBlock.attestations.every((a, i)=>a.equals(expectedBlock.attestations[i]))).toBe(true);
73
- }
74
- };
75
- beforeEach(async ()=>{
76
- store = await getStore();
77
- blocks = await timesParallel(10, async (i)=>makePublished(await L2Block.random(BlockNumber(i + 1)), i + 10));
78
- });
79
- describe('addBlocks', ()=>{
80
- it('returns success when adding blocks', async ()=>{
81
- await expect(store.addBlocks(blocks)).resolves.toBe(true);
82
- });
83
- it('allows duplicate blocks', async ()=>{
84
- await store.addBlocks(blocks);
85
- await expect(store.addBlocks(blocks)).resolves.toBe(true);
86
- });
87
- it('throws an error if the previous block does not exist in the store', async ()=>{
88
- const block = makePublished(await L2Block.random(BlockNumber(2)), 2);
89
- await expect(store.addBlocks([
90
- block
91
- ])).rejects.toThrow(InitialBlockNumberNotSequentialError);
92
- await expect(store.getPublishedBlocks(BlockNumber(1), 10)).resolves.toEqual([]);
93
- });
94
- it('throws an error if there is a gap in the blocks being added', async ()=>{
95
- const blocks = [
96
- makePublished(await L2Block.random(BlockNumber(1)), 1),
97
- makePublished(await L2Block.random(BlockNumber(3)), 3)
98
- ];
99
- await expect(store.addBlocks(blocks)).rejects.toThrow(BlockNumberNotSequentialError);
100
- await expect(store.getPublishedBlocks(BlockNumber(1), 10)).resolves.toEqual([]);
101
- });
102
- });
103
- describe('unwindBlocks', ()=>{
104
- it('unwinding blocks will remove blocks from the chain', async ()=>{
105
- await store.addBlocks(blocks);
106
- const blockNumber = await store.getSynchedL2BlockNumber();
107
- expectBlocksEqual(await store.getPublishedBlocks(blockNumber, 1), [
108
- blocks[blocks.length - 1]
109
- ]);
110
- await store.unwindBlocks(blockNumber, 1);
111
- expect(await store.getSynchedL2BlockNumber()).toBe(blockNumber - 1);
112
- expect(await store.getPublishedBlocks(blockNumber, 1)).toEqual([]);
113
- });
114
- it('can unwind multiple empty blocks', async ()=>{
115
- const emptyBlocks = await timesParallel(10, async (i)=>makePublished(await L2Block.random(BlockNumber(i + 1), 0), i + 10));
116
- await store.addBlocks(emptyBlocks);
117
- expect(await store.getSynchedL2BlockNumber()).toBe(10);
118
- await store.unwindBlocks(BlockNumber(10), 3);
119
- expect(await store.getSynchedL2BlockNumber()).toBe(7);
120
- expect((await store.getPublishedBlocks(BlockNumber(1), 10)).map((b)=>b.block.number)).toEqual([
121
- 1,
122
- 2,
123
- 3,
124
- 4,
125
- 5,
126
- 6,
127
- 7
128
- ]);
129
- });
130
- it('refuses to unwind blocks if the tip is not the last block', async ()=>{
131
- await store.addBlocks(blocks);
132
- await expect(store.unwindBlocks(BlockNumber(5), 1)).rejects.toThrow(/can only unwind blocks from the tip/i);
133
- });
134
- it('unwound blocks and headers cannot be retrieved by hash or archive', async ()=>{
135
- await store.addBlocks(blocks);
136
- const lastBlock = blocks[blocks.length - 1];
137
- const blockHash = await lastBlock.block.hash();
138
- const archive = lastBlock.block.archive.root;
139
- // Verify block and header exist before unwinding
140
- expect(await store.getPublishedBlockByHash(blockHash)).toBeDefined();
141
- expect(await store.getPublishedBlockByArchive(archive)).toBeDefined();
142
- expect(await store.getBlockHeaderByHash(blockHash)).toBeDefined();
143
- expect(await store.getBlockHeaderByArchive(archive)).toBeDefined();
144
- // Unwind the block
145
- await store.unwindBlocks(lastBlock.block.number, 1);
146
- // Verify neither block nor header can be retrieved after unwinding
147
- expect(await store.getPublishedBlockByHash(blockHash)).toBeUndefined();
148
- expect(await store.getPublishedBlockByArchive(archive)).toBeUndefined();
149
- expect(await store.getBlockHeaderByHash(blockHash)).toBeUndefined();
150
- expect(await store.getBlockHeaderByArchive(archive)).toBeUndefined();
151
- });
152
- });
153
- describe('getBlocks', ()=>{
154
- beforeEach(async ()=>{
155
- await store.addBlocks(blocks);
156
- });
157
- it.each(blockTests)('retrieves previously stored blocks', async (start, limit, getExpectedBlocks)=>{
158
- expectBlocksEqual(await store.getPublishedBlocks(BlockNumber(start), limit), getExpectedBlocks());
159
- });
160
- it('returns an empty array if no blocks are found', async ()=>{
161
- await expect(store.getPublishedBlocks(BlockNumber(12), 1)).resolves.toEqual([]);
162
- });
163
- it('throws an error if limit is invalid', async ()=>{
164
- await expect(store.getPublishedBlocks(BlockNumber(1), 0)).rejects.toThrow('Invalid limit: 0');
165
- });
166
- it('throws an error if `from` it is out of range', async ()=>{
167
- await expect(store.getPublishedBlocks(INITIAL_L2_BLOCK_NUM - 100, 1)).rejects.toThrow('Invalid start: -99');
168
- });
169
- it('throws an error if unexpected initial block number is found', async ()=>{
170
- await store.addBlocks([
171
- makePublished(await L2Block.random(BlockNumber(21)), 31)
172
- ], {
173
- force: true
174
- });
175
- await expect(store.getPublishedBlocks(BlockNumber(20), 1)).rejects.toThrow(`mismatch`);
176
- });
177
- it('throws an error if a gap is found', async ()=>{
178
- await store.addBlocks([
179
- makePublished(await L2Block.random(BlockNumber(20)), 30),
180
- makePublished(await L2Block.random(BlockNumber(22)), 32)
181
- ], {
182
- force: true
183
- });
184
- await expect(store.getPublishedBlocks(BlockNumber(20), 2)).rejects.toThrow(`mismatch`);
185
- });
186
- });
187
- describe('getPublishedBlockByHash', ()=>{
188
- beforeEach(async ()=>{
189
- await store.addBlocks(blocks);
190
- });
191
- it('retrieves a block by its hash', async ()=>{
192
- const expectedBlock = blocks[5];
193
- const blockHash = await expectedBlock.block.hash();
194
- const retrievedBlock = await store.getPublishedBlockByHash(blockHash);
195
- expect(retrievedBlock).toBeDefined();
196
- expectBlocksEqual([
197
- retrievedBlock
198
- ], [
199
- expectedBlock
200
- ]);
201
- });
202
- it('returns undefined for non-existent block hash', async ()=>{
203
- const nonExistentHash = Fr.random();
204
- await expect(store.getPublishedBlockByHash(nonExistentHash)).resolves.toBeUndefined();
205
- });
206
- });
207
- describe('getPublishedBlockByArchive', ()=>{
208
- beforeEach(async ()=>{
209
- await store.addBlocks(blocks);
210
- });
211
- it('retrieves a block by its archive root', async ()=>{
212
- const expectedBlock = blocks[3];
213
- const archive = expectedBlock.block.archive.root;
214
- const retrievedBlock = await store.getPublishedBlockByArchive(archive);
215
- expect(retrievedBlock).toBeDefined();
216
- expectBlocksEqual([
217
- retrievedBlock
218
- ], [
219
- expectedBlock
220
- ]);
221
- });
222
- it('returns undefined for non-existent archive root', async ()=>{
223
- const nonExistentArchive = Fr.random();
224
- await expect(store.getPublishedBlockByArchive(nonExistentArchive)).resolves.toBeUndefined();
225
- });
226
- });
227
- describe('getBlockHeaderByHash', ()=>{
228
- beforeEach(async ()=>{
229
- await store.addBlocks(blocks);
230
- });
231
- it('retrieves a block header by its hash', async ()=>{
232
- const expectedBlock = blocks[7];
233
- const blockHash = await expectedBlock.block.hash();
234
- const retrievedHeader = await store.getBlockHeaderByHash(blockHash);
235
- expect(retrievedHeader).toBeDefined();
236
- expect(retrievedHeader.equals(expectedBlock.block.getBlockHeader())).toBe(true);
237
- });
238
- it('returns undefined for non-existent block hash', async ()=>{
239
- const nonExistentHash = Fr.random();
240
- await expect(store.getBlockHeaderByHash(nonExistentHash)).resolves.toBeUndefined();
241
- });
242
- });
243
- describe('getBlockHeaderByArchive', ()=>{
244
- beforeEach(async ()=>{
245
- await store.addBlocks(blocks);
246
- });
247
- it('retrieves a block header by its archive root', async ()=>{
248
- const expectedBlock = blocks[2];
249
- const archive = expectedBlock.block.archive.root;
250
- const retrievedHeader = await store.getBlockHeaderByArchive(archive);
251
- expect(retrievedHeader).toBeDefined();
252
- expect(retrievedHeader.equals(expectedBlock.block.getBlockHeader())).toBe(true);
253
- });
254
- it('returns undefined for non-existent archive root', async ()=>{
255
- const nonExistentArchive = Fr.random();
256
- await expect(store.getBlockHeaderByArchive(nonExistentArchive)).resolves.toBeUndefined();
257
- });
258
- });
259
- describe('getSyncedL2BlockNumber', ()=>{
260
- it('returns the block number before INITIAL_L2_BLOCK_NUM if no blocks have been added', async ()=>{
261
- await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(INITIAL_L2_BLOCK_NUM - 1);
262
- });
263
- it("returns the most recently added block's number", async ()=>{
264
- await store.addBlocks(blocks);
265
- await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(blocks.at(-1).block.number);
266
- });
267
- });
268
- describe('getSynchPoint', ()=>{
269
- it('returns undefined if no blocks have been added', async ()=>{
270
- await expect(store.getSynchPoint()).resolves.toEqual({
271
- blocksSynchedTo: undefined,
272
- messagesSynchedTo: undefined
273
- });
274
- });
275
- it('returns the L1 block number in which the most recent L2 block was published', async ()=>{
276
- await store.addBlocks(blocks);
277
- await expect(store.getSynchPoint()).resolves.toEqual({
278
- blocksSynchedTo: 19n,
279
- messagesSynchedTo: undefined
280
- });
281
- });
282
- it('returns the L1 block number that most recently added messages from inbox', async ()=>{
283
- const l1BlockHash = Buffer32.random();
284
- const l1BlockNumber = 10n;
285
- await store.setMessageSynchedL1Block({
286
- l1BlockNumber: 5n,
287
- l1BlockHash: Buffer32.random()
288
- });
289
- await store.addL1ToL2Messages([
290
- makeInboxMessage(Buffer16.ZERO, {
291
- l1BlockNumber,
292
- l1BlockHash
293
- })
294
- ]);
295
- await expect(store.getSynchPoint()).resolves.toEqual({
296
- blocksSynchedTo: undefined,
297
- messagesSynchedTo: {
298
- l1BlockHash,
299
- l1BlockNumber
300
- }
301
- });
302
- });
303
- it('returns the latest syncpoint if latest message is behind', async ()=>{
304
- const l1BlockHash = Buffer32.random();
305
- const l1BlockNumber = 10n;
306
- await store.setMessageSynchedL1Block({
307
- l1BlockNumber,
308
- l1BlockHash
309
- });
310
- const msg = makeInboxMessage(Buffer16.ZERO, {
311
- l1BlockNumber: 5n,
312
- l1BlockHash: Buffer32.random()
313
- });
314
- await store.addL1ToL2Messages([
315
- msg
316
- ]);
317
- await expect(store.getSynchPoint()).resolves.toEqual({
318
- blocksSynchedTo: undefined,
319
- messagesSynchedTo: {
320
- l1BlockHash,
321
- l1BlockNumber
322
- }
323
- });
324
- });
325
- });
326
- describe('addLogs', ()=>{
327
- it('adds private & public logs', async ()=>{
328
- const block = blocks[0].block;
329
- await expect(store.addLogs([
330
- block
331
- ])).resolves.toEqual(true);
332
- });
333
- });
334
- describe('deleteLogs', ()=>{
335
- it('deletes private & public logs', async ()=>{
336
- const block = blocks[0].block;
337
- await store.addBlocks([
338
- blocks[0]
339
- ]);
340
- await expect(store.addLogs([
341
- block
342
- ])).resolves.toEqual(true);
343
- expect((await store.getPrivateLogs(BlockNumber(1), 1)).length).toEqual(block.body.txEffects.map((txEffect)=>txEffect.privateLogs).flat().length);
344
- expect((await store.getPublicLogs({
345
- fromBlock: BlockNumber(1)
346
- })).logs.length).toEqual(block.body.txEffects.map((txEffect)=>txEffect.publicLogs).flat().length);
347
- // This one is a pain for memory as we would never want to just delete memory in the middle.
348
- await store.deleteLogs([
349
- block
350
- ]);
351
- expect((await store.getPrivateLogs(BlockNumber(1), 1)).length).toEqual(0);
352
- expect((await store.getPublicLogs({
353
- fromBlock: BlockNumber(1)
354
- })).logs.length).toEqual(0);
355
- });
356
- });
357
- describe('getPrivateLogs', ()=>{
358
- it('gets added private logs', async ()=>{
359
- const block = blocks[0].block;
360
- await store.addBlocks([
361
- blocks[0]
362
- ]);
363
- await store.addLogs([
364
- block
365
- ]);
366
- const privateLogs = await store.getPrivateLogs(BlockNumber(1), 1);
367
- expect(privateLogs).toEqual(block.body.txEffects.map((txEffect)=>txEffect.privateLogs).flat());
368
- });
369
- });
370
- describe('getTxEffect', ()=>{
371
- beforeEach(async ()=>{
372
- await store.addLogs(blocks.map((b)=>b.block));
373
- await store.addBlocks(blocks);
374
- });
375
- it.each([
376
- ()=>({
377
- data: blocks[0].block.body.txEffects[0],
378
- block: blocks[0].block,
379
- txIndexInBlock: 0
380
- }),
381
- ()=>({
382
- data: blocks[9].block.body.txEffects[3],
383
- block: blocks[9].block,
384
- txIndexInBlock: 3
385
- }),
386
- ()=>({
387
- data: blocks[3].block.body.txEffects[1],
388
- block: blocks[3].block,
389
- txIndexInBlock: 1
390
- }),
391
- ()=>({
392
- data: blocks[5].block.body.txEffects[2],
393
- block: blocks[5].block,
394
- txIndexInBlock: 2
395
- }),
396
- ()=>({
397
- data: blocks[1].block.body.txEffects[0],
398
- block: blocks[1].block,
399
- txIndexInBlock: 0
400
- })
401
- ])('retrieves a previously stored transaction', async (getExpectedTx)=>{
402
- const { data, block, txIndexInBlock } = getExpectedTx();
403
- const expectedTx = {
404
- data,
405
- l2BlockNumber: block.number,
406
- l2BlockHash: L2BlockHash.fromField(await block.hash()),
407
- txIndexInBlock
408
- };
409
- const actualTx = await store.getTxEffect(data.txHash);
410
- expect(actualTx).toEqual(expectedTx);
411
- });
412
- it('returns undefined if tx is not found', async ()=>{
413
- await expect(store.getTxEffect(TxHash.random())).resolves.toBeUndefined();
414
- });
415
- it.each([
416
- ()=>wrapInBlock(blocks[0].block.body.txEffects[0], blocks[0].block),
417
- ()=>wrapInBlock(blocks[9].block.body.txEffects[3], blocks[9].block),
418
- ()=>wrapInBlock(blocks[3].block.body.txEffects[1], blocks[3].block),
419
- ()=>wrapInBlock(blocks[5].block.body.txEffects[2], blocks[5].block),
420
- ()=>wrapInBlock(blocks[1].block.body.txEffects[0], blocks[1].block)
421
- ])('tries to retrieves a previously stored transaction after deleted', async (getExpectedTx)=>{
422
- await store.unwindBlocks(BlockNumber(blocks.length), blocks.length);
423
- const expectedTx = await getExpectedTx();
424
- const actualTx = await store.getTxEffect(expectedTx.data.txHash);
425
- expect(actualTx).toEqual(undefined);
426
- });
427
- it('returns undefined if tx is not found', async ()=>{
428
- await expect(store.getTxEffect(TxHash.random())).resolves.toBeUndefined();
429
- });
430
- it('does not fail if the block is unwound while requesting a tx', async ()=>{
431
- const expectedTx = await wrapInBlock(blocks[1].block.body.txEffects[0], blocks[1].block);
432
- let done = false;
433
- void (async ()=>{
434
- while(!done){
435
- void store.getTxEffect(expectedTx.data.txHash);
436
- await sleep(1);
437
- }
438
- })();
439
- await store.unwindBlocks(BlockNumber(blocks.length), blocks.length);
440
- done = true;
441
- expect(await store.getTxEffect(expectedTx.data.txHash)).toEqual(undefined);
442
- });
443
- });
444
- describe('L1 to L2 Messages', ()=>{
445
- const initialL2BlockNumber = 13;
446
- const checkMessages = async (msgs)=>{
447
- expect(await store.getLastL1ToL2Message()).toEqual(msgs.at(-1));
448
- expect(await toArray(store.iterateL1ToL2Messages())).toEqual(msgs);
449
- expect(await store.getTotalL1ToL2MessageCount()).toEqual(BigInt(msgs.length));
450
- };
451
- const makeInboxMessagesWithFullBlocks = (blockCount, opts = {})=>makeInboxMessages(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * blockCount, {
452
- overrideFn: (msg, i)=>{
453
- const l2BlockNumber = BlockNumber((opts.initialL2BlockNumber ?? initialL2BlockNumber) + Math.floor(i / NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP));
454
- const index = InboxLeaf.smallestIndexFromL2Block(l2BlockNumber) + BigInt(i % NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
455
- return {
456
- ...msg,
457
- l2BlockNumber,
458
- index
459
- };
460
- }
461
- });
462
- it('stores first message ever', async ()=>{
463
- const msg = makeInboxMessage(Buffer16.ZERO, {
464
- index: 0n,
465
- l2BlockNumber: BlockNumber(1)
466
- });
467
- await store.addL1ToL2Messages([
468
- msg
469
- ]);
470
- await checkMessages([
471
- msg
472
- ]);
473
- expect(await store.getL1ToL2Messages(BlockNumber(1))).toEqual([
474
- msg.leaf
475
- ]);
476
- });
477
- it('stores single message', async ()=>{
478
- const msg = makeInboxMessage(Buffer16.ZERO, {
479
- l2BlockNumber: BlockNumber(2)
480
- });
481
- await store.addL1ToL2Messages([
482
- msg
483
- ]);
484
- await checkMessages([
485
- msg
486
- ]);
487
- expect(await store.getL1ToL2Messages(BlockNumber(2))).toEqual([
488
- msg.leaf
489
- ]);
490
- });
491
- it('stores and returns messages across different blocks', async ()=>{
492
- const msgs = makeInboxMessages(5, {
493
- initialL2BlockNumber
494
- });
495
- await store.addL1ToL2Messages(msgs);
496
- await checkMessages(msgs);
497
- expect(await store.getL1ToL2Messages(BlockNumber(initialL2BlockNumber + 2))).toEqual([
498
- msgs[2]
499
- ].map((m)=>m.leaf));
500
- });
501
- it('stores the same messages again', async ()=>{
502
- const msgs = makeInboxMessages(5, {
503
- initialL2BlockNumber
504
- });
505
- await store.addL1ToL2Messages(msgs);
506
- await store.addL1ToL2Messages(msgs.slice(2));
507
- await checkMessages(msgs);
508
- });
509
- it('stores and returns messages across different blocks with gaps', async ()=>{
510
- const msgs1 = makeInboxMessages(3, {
511
- initialL2BlockNumber: 1
512
- });
513
- const msgs2 = makeInboxMessages(3, {
514
- initialL2BlockNumber: 20,
515
- initialHash: msgs1.at(-1).rollingHash
516
- });
517
- await store.addL1ToL2Messages(msgs1);
518
- await store.addL1ToL2Messages(msgs2);
519
- await checkMessages([
520
- ...msgs1,
521
- ...msgs2
522
- ]);
523
- expect(await store.getL1ToL2Messages(BlockNumber(1))).toEqual([
524
- msgs1[0].leaf
525
- ]);
526
- expect(await store.getL1ToL2Messages(BlockNumber(4))).toEqual([]);
527
- expect(await store.getL1ToL2Messages(BlockNumber(20))).toEqual([
528
- msgs2[0].leaf
529
- ]);
530
- expect(await store.getL1ToL2Messages(BlockNumber(24))).toEqual([]);
531
- });
532
- it('stores and returns messages with block numbers larger than a byte', async ()=>{
533
- const msgs = makeInboxMessages(5, {
534
- initialL2BlockNumber: 1000
535
- });
536
- await store.addL1ToL2Messages(msgs);
537
- await checkMessages(msgs);
538
- expect(await store.getL1ToL2Messages(BlockNumber(1002))).toEqual([
539
- msgs[2]
540
- ].map((m)=>m.leaf));
541
- });
542
- it('stores and returns multiple messages per block', async ()=>{
543
- const msgs = makeInboxMessagesWithFullBlocks(4);
544
- await store.addL1ToL2Messages(msgs);
545
- await checkMessages(msgs);
546
- const blockMessages = await store.getL1ToL2Messages(BlockNumber(initialL2BlockNumber + 1));
547
- expect(blockMessages).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
548
- expect(blockMessages).toEqual(msgs.slice(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2).map((m)=>m.leaf));
549
- });
550
- it('stores messages in multiple operations', async ()=>{
551
- const msgs = makeInboxMessages(20, {
552
- initialL2BlockNumber
553
- });
554
- await store.addL1ToL2Messages(msgs.slice(0, 10));
555
- await store.addL1ToL2Messages(msgs.slice(10, 20));
556
- expect(await store.getL1ToL2Messages(BlockNumber(initialL2BlockNumber + 2))).toEqual([
557
- msgs[2]
558
- ].map((m)=>m.leaf));
559
- expect(await store.getL1ToL2Messages(BlockNumber(initialL2BlockNumber + 12))).toEqual([
560
- msgs[12]
561
- ].map((m)=>m.leaf));
562
- await checkMessages(msgs);
563
- });
564
- it('iterates over messages from start index', async ()=>{
565
- const msgs = makeInboxMessages(10, {
566
- initialL2BlockNumber
567
- });
568
- await store.addL1ToL2Messages(msgs);
569
- const iterated = await toArray(store.iterateL1ToL2Messages({
570
- start: msgs[3].index
571
- }));
572
- expect(iterated).toEqual(msgs.slice(3));
573
- });
574
- it('iterates over messages in reverse', async ()=>{
575
- const msgs = makeInboxMessages(10, {
576
- initialL2BlockNumber
577
- });
578
- await store.addL1ToL2Messages(msgs);
579
- const iterated = await toArray(store.iterateL1ToL2Messages({
580
- reverse: true,
581
- end: msgs[3].index
582
- }));
583
- expect(iterated).toEqual(msgs.slice(0, 4).reverse());
584
- });
585
- it('throws if messages are added out of order', async ()=>{
586
- const msgs = makeInboxMessages(5, {
587
- overrideFn: (msg, i)=>({
588
- ...msg,
589
- index: BigInt(10 - i)
590
- })
591
- });
592
- await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
593
- });
594
- it('throws if block number for the first message is out of order', async ()=>{
595
- const msgs = makeInboxMessages(4, {
596
- initialL2BlockNumber
597
- });
598
- msgs[2].l2BlockNumber = BlockNumber(initialL2BlockNumber - 1);
599
- await store.addL1ToL2Messages(msgs.slice(0, 2));
600
- await expect(store.addL1ToL2Messages(msgs.slice(2, 4))).rejects.toThrow(MessageStoreError);
601
- });
602
- it('throws if rolling hash is not correct', async ()=>{
603
- const msgs = makeInboxMessages(5);
604
- msgs[1].rollingHash = Buffer16.random();
605
- await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
606
- });
607
- it('throws if rolling hash for first message is not correct', async ()=>{
608
- const msgs = makeInboxMessages(4);
609
- msgs[2].rollingHash = Buffer16.random();
610
- await store.addL1ToL2Messages(msgs.slice(0, BlockNumber(2)));
611
- await expect(store.addL1ToL2Messages(msgs.slice(2, 4))).rejects.toThrow(MessageStoreError);
612
- });
613
- it('throws if index is not in the correct range', async ()=>{
614
- const msgs = makeInboxMessages(5, {
615
- initialL2BlockNumber
616
- });
617
- msgs.at(-1).index += 100n;
618
- await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
619
- });
620
- it('throws if first index in block has gaps', async ()=>{
621
- const msgs = makeInboxMessages(4, {
622
- initialL2BlockNumber
623
- });
624
- msgs[2].index++;
625
- await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
626
- });
627
- it('throws if index does not follow previous one', async ()=>{
628
- const msgs = makeInboxMessages(2, {
629
- initialL2BlockNumber,
630
- overrideFn: (msg, i)=>({
631
- ...msg,
632
- l2BlockNumber: BlockNumber(2),
633
- index: BigInt(i + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2)
634
- })
635
- });
636
- msgs[1].index++;
637
- await expect(store.addL1ToL2Messages(msgs)).rejects.toThrow(MessageStoreError);
638
- });
639
- it('removes messages up to the given block number', async ()=>{
640
- const msgs = makeInboxMessagesWithFullBlocks(4, {
641
- initialL2BlockNumber: 1
642
- });
643
- await store.addL1ToL2Messages(msgs);
644
- await checkMessages(msgs);
645
- expect(await store.getL1ToL2Messages(BlockNumber(1))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
646
- expect(await store.getL1ToL2Messages(BlockNumber(2))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
647
- expect(await store.getL1ToL2Messages(BlockNumber(3))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
648
- expect(await store.getL1ToL2Messages(BlockNumber(4))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
649
- await store.rollbackL1ToL2MessagesToL2Block(BlockNumber(2));
650
- expect(await store.getL1ToL2Messages(BlockNumber(1))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
651
- expect(await store.getL1ToL2Messages(BlockNumber(2))).toHaveLength(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP);
652
- expect(await store.getL1ToL2Messages(BlockNumber(3))).toHaveLength(0);
653
- expect(await store.getL1ToL2Messages(BlockNumber(4))).toHaveLength(0);
654
- await checkMessages(msgs.slice(0, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP * 2));
655
- });
656
- it('removes messages starting with the given index', async ()=>{
657
- const msgs = makeInboxMessagesWithFullBlocks(4, {
658
- initialL2BlockNumber: 1
659
- });
660
- await store.addL1ToL2Messages(msgs);
661
- await store.removeL1ToL2Messages(msgs[13].index);
662
- await checkMessages(msgs.slice(0, 13));
663
- });
664
- });
665
- describe('contractInstances', ()=>{
666
- let contractInstance;
667
- const blockNum = 10;
668
- const timestamp = 3600n;
669
- beforeEach(async ()=>{
670
- const classId = Fr.random();
671
- const randomInstance = await SerializableContractInstance.random({
672
- currentContractClassId: classId,
673
- originalContractClassId: classId
674
- });
675
- contractInstance = {
676
- ...randomInstance,
677
- address: await AztecAddress.random()
678
- };
679
- await store.addContractInstances([
680
- contractInstance
681
- ], BlockNumber(blockNum));
682
- });
683
- it('returns previously stored contract instances', async ()=>{
684
- await expect(store.getContractInstance(contractInstance.address, timestamp)).resolves.toMatchObject(contractInstance);
685
- });
686
- it('returns undefined if contract instance is not found', async ()=>{
687
- await expect(store.getContractInstance(await AztecAddress.random(), timestamp)).resolves.toBeUndefined();
688
- });
689
- it('returns undefined if previously stored contract instances was deleted', async ()=>{
690
- await store.deleteContractInstances([
691
- contractInstance
692
- ], BlockNumber(blockNum));
693
- await expect(store.getContractInstance(contractInstance.address, timestamp)).resolves.toBeUndefined();
694
- });
695
- });
696
- describe('contractInstanceUpdates', ()=>{
697
- let contractInstance;
698
- let classId;
699
- let nextClassId;
700
- const timestampOfChange = 3600n;
701
- beforeEach(async ()=>{
702
- classId = Fr.random();
703
- nextClassId = Fr.random();
704
- const randomInstance = await SerializableContractInstance.random({
705
- currentContractClassId: classId,
706
- originalContractClassId: classId
707
- });
708
- contractInstance = {
709
- ...randomInstance,
710
- address: await AztecAddress.random()
711
- };
712
- await store.addContractInstances([
713
- contractInstance
714
- ], BlockNumber(1));
715
- await store.addContractInstanceUpdates([
716
- {
717
- prevContractClassId: classId,
718
- newContractClassId: nextClassId,
719
- timestampOfChange,
720
- address: contractInstance.address
721
- }
722
- ], timestampOfChange - 1n);
723
- });
724
- it('gets the correct current class id for a contract not updated yet', async ()=>{
725
- const fetchedInstance = await store.getContractInstance(contractInstance.address, timestampOfChange - 1n);
726
- expect(fetchedInstance?.originalContractClassId).toEqual(classId);
727
- expect(fetchedInstance?.currentContractClassId).toEqual(classId);
728
- });
729
- it('gets the correct current class id for a contract that has just been updated', async ()=>{
730
- const fetchedInstance = await store.getContractInstance(contractInstance.address, timestampOfChange);
731
- expect(fetchedInstance?.originalContractClassId).toEqual(classId);
732
- expect(fetchedInstance?.currentContractClassId).toEqual(nextClassId);
733
- });
734
- it('gets the correct current class id for a contract that was updated in the past', async ()=>{
735
- const fetchedInstance = await store.getContractInstance(contractInstance.address, timestampOfChange + 1n);
736
- expect(fetchedInstance?.originalContractClassId).toEqual(classId);
737
- expect(fetchedInstance?.currentContractClassId).toEqual(nextClassId);
738
- });
739
- it('ignores updates for the wrong contract', async ()=>{
740
- const otherClassId = Fr.random();
741
- const randomInstance = await SerializableContractInstance.random({
742
- currentContractClassId: otherClassId,
743
- originalContractClassId: otherClassId
744
- });
745
- const otherContractInstance = {
746
- ...randomInstance,
747
- address: await AztecAddress.random()
748
- };
749
- await store.addContractInstances([
750
- otherContractInstance
751
- ], BlockNumber(1));
752
- const fetchedInstance = await store.getContractInstance(otherContractInstance.address, timestampOfChange + 1n);
753
- expect(fetchedInstance?.originalContractClassId).toEqual(otherClassId);
754
- expect(fetchedInstance?.currentContractClassId).toEqual(otherClassId);
755
- });
756
- it('bounds its search to the right contract if more than than one update exists', async ()=>{
757
- const otherClassId = Fr.random();
758
- const otherNextClassId = Fr.random();
759
- const randomInstance = await SerializableContractInstance.random({
760
- currentContractClassId: otherClassId,
761
- originalContractClassId: otherNextClassId
762
- });
763
- const otherContractInstance = {
764
- ...randomInstance,
765
- address: await AztecAddress.random()
766
- };
767
- await store.addContractInstances([
768
- otherContractInstance
769
- ], BlockNumber(1));
770
- await store.addContractInstanceUpdates([
771
- {
772
- prevContractClassId: otherClassId,
773
- newContractClassId: otherNextClassId,
774
- timestampOfChange,
775
- address: otherContractInstance.address
776
- }
777
- ], timestampOfChange - 1n);
778
- const fetchedInstance = await store.getContractInstance(contractInstance.address, timestampOfChange + 1n);
779
- expect(fetchedInstance?.originalContractClassId).toEqual(classId);
780
- expect(fetchedInstance?.currentContractClassId).toEqual(nextClassId);
781
- });
782
- });
783
- describe('contractClasses', ()=>{
784
- let contractClass;
785
- const blockNum = 10;
786
- beforeEach(async ()=>{
787
- contractClass = await makeContractClassPublic();
788
- await store.addContractClasses([
789
- contractClass
790
- ], [
791
- await computePublicBytecodeCommitment(contractClass.packedBytecode)
792
- ], BlockNumber(blockNum));
793
- });
794
- it('returns previously stored contract class', async ()=>{
795
- await expect(store.getContractClass(contractClass.id)).resolves.toMatchObject(contractClass);
796
- });
797
- it('returns undefined if the initial deployed contract class was deleted', async ()=>{
798
- await store.deleteContractClasses([
799
- contractClass
800
- ], BlockNumber(blockNum));
801
- await expect(store.getContractClass(contractClass.id)).resolves.toBeUndefined();
802
- });
803
- it('returns contract class if later "deployment" class was deleted', async ()=>{
804
- await store.addContractClasses([
805
- contractClass
806
- ], [
807
- await computePublicBytecodeCommitment(contractClass.packedBytecode)
808
- ], BlockNumber(blockNum + 1));
809
- await store.deleteContractClasses([
810
- contractClass
811
- ], BlockNumber(blockNum + 1));
812
- await expect(store.getContractClass(contractClass.id)).resolves.toMatchObject(contractClass);
813
- });
814
- it('returns undefined if contract class is not found', async ()=>{
815
- await expect(store.getContractClass(Fr.random())).resolves.toBeUndefined();
816
- });
817
- it('adds new private functions', async ()=>{
818
- const fns = times(3, makeExecutablePrivateFunctionWithMembershipProof);
819
- await store.addFunctions(contractClass.id, fns, []);
820
- const stored = await store.getContractClass(contractClass.id);
821
- expect(stored?.privateFunctions).toEqual(fns);
822
- });
823
- it('does not duplicate private functions', async ()=>{
824
- const fns = times(3, makeExecutablePrivateFunctionWithMembershipProof);
825
- await store.addFunctions(contractClass.id, fns.slice(0, 1), []);
826
- await store.addFunctions(contractClass.id, fns, []);
827
- const stored = await store.getContractClass(contractClass.id);
828
- expect(stored?.privateFunctions).toEqual(fns);
829
- });
830
- it('adds new utility functions', async ()=>{
831
- const fns = times(3, makeUtilityFunctionWithMembershipProof);
832
- await store.addFunctions(contractClass.id, [], fns);
833
- const stored = await store.getContractClass(contractClass.id);
834
- expect(stored?.utilityFunctions).toEqual(fns);
835
- });
836
- it('does not duplicate utility functions', async ()=>{
837
- const fns = times(3, makeUtilityFunctionWithMembershipProof);
838
- await store.addFunctions(contractClass.id, [], fns.slice(0, 1));
839
- await store.addFunctions(contractClass.id, [], fns);
840
- const stored = await store.getContractClass(contractClass.id);
841
- expect(stored?.utilityFunctions).toEqual(fns);
842
- });
843
- });
844
- describe('getLogsByTags', ()=>{
845
- const numBlocks = 3;
846
- const numTxsPerBlock = 4;
847
- const numPrivateLogsPerTx = 3;
848
- const numPublicLogsPerTx = 2;
849
- let blocks;
850
- const makeTag = (blockNumber, txIndex, logIndex, isPublic = false)=>blockNumber === 1 && txIndex === 0 && logIndex === 0 ? Fr.ZERO // Shared tag
851
- : new Fr((blockNumber * 100 + txIndex * 10 + logIndex) * (isPublic ? 123 : 1));
852
- const makePrivateLog = (tag)=>PrivateLog.from({
853
- fields: makeTuple(PRIVATE_LOG_SIZE_IN_FIELDS, (i)=>!i ? tag : new Fr(tag.toNumber() + i)),
854
- emittedLength: PRIVATE_LOG_SIZE_IN_FIELDS
855
- });
856
- const makePublicLog = (tag)=>PublicLog.from({
857
- contractAddress: AztecAddress.fromNumber(1),
858
- // Arbitrary length
859
- fields: new Array(10).fill(null).map((_, i)=>!i ? tag : new Fr(tag.toNumber() + i))
860
- });
861
- const mockPrivateLogs = (blockNumber, txIndex)=>{
862
- return times(numPrivateLogsPerTx, (logIndex)=>{
863
- const tag = makeTag(blockNumber, txIndex, logIndex);
864
- return makePrivateLog(tag);
865
- });
866
- };
867
- const mockPublicLogs = (blockNumber, txIndex)=>{
868
- return times(numPublicLogsPerTx, (logIndex)=>{
869
- const tag = makeTag(blockNumber, txIndex, logIndex, /* isPublic */ true);
870
- return makePublicLog(tag);
871
- });
872
- };
873
- const mockBlockWithLogs = async (blockNumber)=>{
874
- const block = await L2Block.random(BlockNumber(blockNumber));
875
- block.header.globalVariables.blockNumber = BlockNumber(blockNumber);
876
- block.body.txEffects = await timesParallel(numTxsPerBlock, async (txIndex)=>{
877
- const txEffect = await TxEffect.random();
878
- txEffect.privateLogs = mockPrivateLogs(blockNumber, txIndex);
879
- txEffect.publicLogs = mockPublicLogs(blockNumber, txIndex);
880
- return txEffect;
881
- });
882
- return PublishedL2Block.fromFields({
883
- block: block,
884
- attestations: times(3, CommitteeAttestation.random),
885
- l1: {
886
- blockNumber: BigInt(blockNumber),
887
- blockHash: makeBlockHash(blockNumber),
888
- timestamp: BigInt(blockNumber)
889
- }
890
- });
891
- };
892
- beforeEach(async ()=>{
893
- blocks = await timesParallel(numBlocks, (index)=>mockBlockWithLogs(index + 1));
894
- await store.addBlocks(blocks);
895
- await store.addLogs(blocks.map((b)=>b.block));
896
- });
897
- it('is possible to batch request private logs via tags', async ()=>{
898
- const tags = [
899
- makeTag(2, 1, 2),
900
- makeTag(1, 2, 0)
901
- ];
902
- const logsByTags = await store.getLogsByTags(tags);
903
- expect(logsByTags).toEqual([
904
- [
905
- expect.objectContaining({
906
- blockNumber: 2,
907
- log: makePrivateLog(tags[0]),
908
- isFromPublic: false
909
- })
910
- ],
911
- [
912
- expect.objectContaining({
913
- blockNumber: 1,
914
- log: makePrivateLog(tags[1]),
915
- isFromPublic: false
916
- })
917
- ]
918
- ]);
919
- });
920
- it('is possible to batch request all logs (private and public) via tags', async ()=>{
921
- // Tag(1, 0, 0) is shared with the first private log and the first public log.
922
- const tags = [
923
- makeTag(1, 0, 0)
924
- ];
925
- const logsByTags = await store.getLogsByTags(tags);
926
- expect(logsByTags).toEqual([
927
- [
928
- expect.objectContaining({
929
- blockNumber: 1,
930
- log: makePrivateLog(tags[0]),
931
- isFromPublic: false
932
- }),
933
- expect.objectContaining({
934
- blockNumber: 1,
935
- log: makePublicLog(tags[0]),
936
- isFromPublic: true
937
- })
938
- ]
939
- ]);
940
- });
941
- it('is possible to batch request logs that have the same tag but different content', async ()=>{
942
- const tags = [
943
- makeTag(1, 2, 1)
944
- ];
945
- // Create a block containing logs that have the same tag as the blocks before.
946
- const newBlockNumber = numBlocks;
947
- const newBlock = await mockBlockWithLogs(newBlockNumber);
948
- const newLog = newBlock.block.body.txEffects[1].privateLogs[1];
949
- newLog.fields[0] = tags[0];
950
- newBlock.block.body.txEffects[1].privateLogs[1] = newLog;
951
- await store.addBlocks([
952
- newBlock
953
- ]);
954
- await store.addLogs([
955
- newBlock.block
956
- ]);
957
- const logsByTags = await store.getLogsByTags(tags);
958
- expect(logsByTags).toEqual([
959
- [
960
- expect.objectContaining({
961
- blockNumber: 1,
962
- log: makePrivateLog(tags[0]),
963
- isFromPublic: false
964
- }),
965
- expect.objectContaining({
966
- blockNumber: newBlockNumber,
967
- log: newLog,
968
- isFromPublic: false
969
- })
970
- ]
971
- ]);
972
- });
973
- it('is possible to request logs for non-existing tags and determine their position', async ()=>{
974
- const tags = [
975
- makeTag(99, 88, 77),
976
- makeTag(1, 1, 1)
977
- ];
978
- const logsByTags = await store.getLogsByTags(tags);
979
- expect(logsByTags).toEqual([
980
- [],
981
- [
982
- expect.objectContaining({
983
- blockNumber: 1,
984
- log: makePrivateLog(tags[1]),
985
- isFromPublic: false
986
- })
987
- ]
988
- ]);
989
- });
990
- });
991
- describe('getPublicLogs', ()=>{
992
- const txsPerBlock = 4;
993
- const numPublicFunctionCalls = 3;
994
- const numPublicLogs = 2;
995
- const numBlocks = 10;
996
- let blocks;
997
- beforeEach(async ()=>{
998
- blocks = await timesParallel(numBlocks, async (index)=>PublishedL2Block.fromFields({
999
- block: await L2Block.random(BlockNumber(index + 1), txsPerBlock, numPublicFunctionCalls, numPublicLogs),
1000
- l1: {
1001
- blockNumber: BigInt(index),
1002
- blockHash: makeBlockHash(index),
1003
- timestamp: BigInt(index)
1004
- },
1005
- attestations: times(3, CommitteeAttestation.random)
1006
- }));
1007
- await store.addBlocks(blocks);
1008
- await store.addLogs(blocks.map((b)=>b.block));
1009
- });
1010
- it('no logs returned if deleted ("txHash" filter param is respected variant)', async ()=>{
1011
- // get random tx
1012
- const targetBlockIndex = randomInt(numBlocks);
1013
- const targetTxIndex = randomInt(txsPerBlock);
1014
- const targetTxHash = blocks[targetBlockIndex].block.body.txEffects[targetTxIndex].txHash;
1015
- await Promise.all([
1016
- store.unwindBlocks(BlockNumber(blocks.length), blocks.length),
1017
- store.deleteLogs(blocks.map((b)=>b.block))
1018
- ]);
1019
- const response = await store.getPublicLogs({
1020
- txHash: targetTxHash
1021
- });
1022
- const logs = response.logs;
1023
- expect(response.maxLogsHit).toBeFalsy();
1024
- expect(logs.length).toEqual(0);
1025
- });
1026
- it('"txHash" filter param is respected', async ()=>{
1027
- // get random tx
1028
- const targetBlockIndex = randomInt(numBlocks);
1029
- const targetTxIndex = randomInt(txsPerBlock);
1030
- const targetTxHash = blocks[targetBlockIndex].block.body.txEffects[targetTxIndex].txHash;
1031
- const response = await store.getPublicLogs({
1032
- txHash: targetTxHash
1033
- });
1034
- const logs = response.logs;
1035
- expect(response.maxLogsHit).toBeFalsy();
1036
- const expectedNumLogs = numPublicFunctionCalls * numPublicLogs;
1037
- expect(logs.length).toEqual(expectedNumLogs);
1038
- const targeBlockNumber = targetBlockIndex + INITIAL_L2_BLOCK_NUM;
1039
- for (const log of logs){
1040
- expect(log.id.blockNumber).toEqual(targeBlockNumber);
1041
- expect(log.id.txIndex).toEqual(targetTxIndex);
1042
- }
1043
- });
1044
- it('"fromBlock" and "toBlock" filter params are respected', async ()=>{
1045
- // Set "fromBlock" and "toBlock"
1046
- const fromBlock = 3;
1047
- const toBlock = 7;
1048
- const response = await store.getPublicLogs({
1049
- fromBlock,
1050
- toBlock
1051
- });
1052
- const logs = response.logs;
1053
- expect(response.maxLogsHit).toBeFalsy();
1054
- const expectedNumLogs = txsPerBlock * numPublicFunctionCalls * numPublicLogs * (toBlock - fromBlock);
1055
- expect(logs.length).toEqual(expectedNumLogs);
1056
- for (const log of logs){
1057
- const blockNumber = log.id.blockNumber;
1058
- expect(blockNumber).toBeGreaterThanOrEqual(fromBlock);
1059
- expect(blockNumber).toBeLessThan(toBlock);
1060
- }
1061
- });
1062
- it('"contractAddress" filter param is respected', async ()=>{
1063
- // Get a random contract address from the logs
1064
- const targetBlockIndex = randomInt(numBlocks);
1065
- const targetTxIndex = randomInt(txsPerBlock);
1066
- const targetLogIndex = randomInt(numPublicLogs * numPublicFunctionCalls);
1067
- const targetContractAddress = blocks[targetBlockIndex].block.body.txEffects[targetTxIndex].publicLogs[targetLogIndex].contractAddress;
1068
- const response = await store.getPublicLogs({
1069
- contractAddress: targetContractAddress
1070
- });
1071
- expect(response.maxLogsHit).toBeFalsy();
1072
- for (const extendedLog of response.logs){
1073
- expect(extendedLog.log.contractAddress.equals(targetContractAddress)).toBeTruthy();
1074
- }
1075
- });
1076
- it('"afterLog" filter param is respected', async ()=>{
1077
- // Get a random log as reference
1078
- const targetBlockIndex = randomInt(numBlocks);
1079
- const targetTxIndex = randomInt(txsPerBlock);
1080
- const targetLogIndex = randomInt(numPublicLogs);
1081
- const afterLog = new LogId(BlockNumber(targetBlockIndex + INITIAL_L2_BLOCK_NUM), targetTxIndex, targetLogIndex);
1082
- const response = await store.getPublicLogs({
1083
- afterLog
1084
- });
1085
- const logs = response.logs;
1086
- expect(response.maxLogsHit).toBeFalsy();
1087
- for (const log of logs){
1088
- const logId = log.id;
1089
- expect(logId.blockNumber).toBeGreaterThanOrEqual(afterLog.blockNumber);
1090
- if (logId.blockNumber === afterLog.blockNumber) {
1091
- expect(logId.txIndex).toBeGreaterThanOrEqual(afterLog.txIndex);
1092
- if (logId.txIndex === afterLog.txIndex) {
1093
- expect(logId.logIndex).toBeGreaterThan(afterLog.logIndex);
1094
- }
1095
- }
1096
- }
1097
- });
1098
- it('"txHash" filter param is ignored when "afterLog" is set', async ()=>{
1099
- // Get random txHash
1100
- const txHash = TxHash.random();
1101
- const afterLog = new LogId(BlockNumber(1), 0, 0);
1102
- const response = await store.getPublicLogs({
1103
- txHash,
1104
- afterLog
1105
- });
1106
- expect(response.logs.length).toBeGreaterThan(1);
1107
- });
1108
- it('intersecting works', async ()=>{
1109
- let logs = (await store.getPublicLogs({
1110
- fromBlock: -10,
1111
- toBlock: -5
1112
- })).logs;
1113
- expect(logs.length).toBe(0);
1114
- // "fromBlock" gets correctly trimmed to range and "toBlock" is exclusive
1115
- logs = (await store.getPublicLogs({
1116
- fromBlock: -10,
1117
- toBlock: BlockNumber(5)
1118
- })).logs;
1119
- let blockNumbers = new Set(logs.map((log)=>log.id.blockNumber));
1120
- expect(blockNumbers).toEqual(new Set([
1121
- 1,
1122
- 2,
1123
- 3,
1124
- 4
1125
- ]));
1126
- // "toBlock" should be exclusive
1127
- logs = (await store.getPublicLogs({
1128
- fromBlock: BlockNumber(1),
1129
- toBlock: BlockNumber(1)
1130
- })).logs;
1131
- expect(logs.length).toBe(0);
1132
- logs = (await store.getPublicLogs({
1133
- fromBlock: BlockNumber(10),
1134
- toBlock: BlockNumber(5)
1135
- })).logs;
1136
- expect(logs.length).toBe(0);
1137
- // both "fromBlock" and "toBlock" get correctly capped to range and logs from all blocks are returned
1138
- logs = (await store.getPublicLogs({
1139
- fromBlock: -100,
1140
- toBlock: +100
1141
- })).logs;
1142
- blockNumbers = new Set(logs.map((log)=>log.id.blockNumber));
1143
- expect(blockNumbers.size).toBe(numBlocks);
1144
- // intersecting with "afterLog" works
1145
- logs = (await store.getPublicLogs({
1146
- fromBlock: BlockNumber(2),
1147
- toBlock: BlockNumber(5),
1148
- afterLog: new LogId(BlockNumber(4), 0, 0)
1149
- })).logs;
1150
- blockNumbers = new Set(logs.map((log)=>log.id.blockNumber));
1151
- expect(blockNumbers).toEqual(new Set([
1152
- 4
1153
- ]));
1154
- logs = (await store.getPublicLogs({
1155
- toBlock: BlockNumber(5),
1156
- afterLog: new LogId(BlockNumber(5), 1, 0)
1157
- })).logs;
1158
- expect(logs.length).toBe(0);
1159
- logs = (await store.getPublicLogs({
1160
- fromBlock: BlockNumber(2),
1161
- toBlock: BlockNumber(5),
1162
- afterLog: new LogId(BlockNumber(100), 0, 0)
1163
- })).logs;
1164
- expect(logs.length).toBe(0);
1165
- });
1166
- it('"txIndex" and "logIndex" are respected when "afterLog.blockNumber" is equal to "fromBlock"', async ()=>{
1167
- // Get a random log as reference
1168
- const targetBlockIndex = randomInt(numBlocks);
1169
- const targetTxIndex = randomInt(txsPerBlock);
1170
- const targetLogIndex = randomInt(numPublicLogs);
1171
- const afterLog = new LogId(BlockNumber(targetBlockIndex + INITIAL_L2_BLOCK_NUM), targetTxIndex, targetLogIndex);
1172
- const response = await store.getPublicLogs({
1173
- afterLog,
1174
- fromBlock: afterLog.blockNumber
1175
- });
1176
- const logs = response.logs;
1177
- expect(response.maxLogsHit).toBeFalsy();
1178
- for (const log of logs){
1179
- const logId = log.id;
1180
- expect(logId.blockNumber).toBeGreaterThanOrEqual(afterLog.blockNumber);
1181
- if (logId.blockNumber === afterLog.blockNumber) {
1182
- expect(logId.txIndex).toBeGreaterThanOrEqual(afterLog.txIndex);
1183
- if (logId.txIndex === afterLog.txIndex) {
1184
- expect(logId.logIndex).toBeGreaterThan(afterLog.logIndex);
1185
- }
1186
- }
1187
- }
1188
- });
1189
- });
1190
- describe('pendingChainValidationStatus', ()=>{
1191
- it('should return undefined when no status is set', async ()=>{
1192
- const status = await store.getPendingChainValidationStatus();
1193
- expect(status).toBeUndefined();
1194
- });
1195
- it('should store and retrieve a valid validation status', async ()=>{
1196
- const validStatus = {
1197
- valid: true
1198
- };
1199
- await store.setPendingChainValidationStatus(validStatus);
1200
- const retrievedStatus = await store.getPendingChainValidationStatus();
1201
- expect(retrievedStatus).toEqual(validStatus);
1202
- });
1203
- it('should store and retrieve an invalid validation status with insufficient attestations', async ()=>{
1204
- const invalidStatus = {
1205
- valid: false,
1206
- block: randomBlockInfo(1),
1207
- committee: [
1208
- EthAddress.random(),
1209
- EthAddress.random()
1210
- ],
1211
- epoch: EpochNumber(123),
1212
- seed: 456n,
1213
- attestors: [
1214
- EthAddress.random()
1215
- ],
1216
- attestations: [
1217
- CommitteeAttestation.random()
1218
- ],
1219
- reason: 'insufficient-attestations'
1220
- };
1221
- await store.setPendingChainValidationStatus(invalidStatus);
1222
- const retrievedStatus = await store.getPendingChainValidationStatus();
1223
- expect(retrievedStatus).toEqual(invalidStatus);
1224
- });
1225
- it('should store and retrieve an invalid validation status with invalid attestation', async ()=>{
1226
- const invalidStatus = {
1227
- valid: false,
1228
- block: randomBlockInfo(2),
1229
- committee: [
1230
- EthAddress.random()
1231
- ],
1232
- attestors: [
1233
- EthAddress.random()
1234
- ],
1235
- epoch: EpochNumber(789),
1236
- seed: 101n,
1237
- attestations: [
1238
- CommitteeAttestation.random()
1239
- ],
1240
- reason: 'invalid-attestation',
1241
- invalidIndex: 5
1242
- };
1243
- await store.setPendingChainValidationStatus(invalidStatus);
1244
- const retrievedStatus = await store.getPendingChainValidationStatus();
1245
- expect(retrievedStatus).toEqual(invalidStatus);
1246
- });
1247
- it('should overwrite existing status when setting a new one', async ()=>{
1248
- const firstStatus = {
1249
- valid: true
1250
- };
1251
- const secondStatus = {
1252
- valid: false,
1253
- block: randomBlockInfo(3),
1254
- committee: [
1255
- EthAddress.random()
1256
- ],
1257
- epoch: EpochNumber(999),
1258
- seed: 888n,
1259
- attestors: [
1260
- EthAddress.random()
1261
- ],
1262
- attestations: [
1263
- CommitteeAttestation.random()
1264
- ],
1265
- reason: 'insufficient-attestations'
1266
- };
1267
- await store.setPendingChainValidationStatus(firstStatus);
1268
- await store.setPendingChainValidationStatus(secondStatus);
1269
- const retrievedStatus = await store.getPendingChainValidationStatus();
1270
- expect(retrievedStatus).toEqual(secondStatus);
1271
- });
1272
- it('should handle empty committee and attestations arrays', async ()=>{
1273
- const statusWithEmptyArrays = {
1274
- valid: false,
1275
- block: randomBlockInfo(4),
1276
- committee: [],
1277
- epoch: EpochNumber(0),
1278
- seed: 0n,
1279
- attestors: [],
1280
- attestations: [],
1281
- reason: 'insufficient-attestations'
1282
- };
1283
- await store.setPendingChainValidationStatus(statusWithEmptyArrays);
1284
- const retrievedStatus = await store.getPendingChainValidationStatus();
1285
- expect(retrievedStatus).toEqual(statusWithEmptyArrays);
1286
- });
1287
- });
1288
- });
1289
- }