@aztec/archiver 0.0.1-commit.b655e406 → 0.0.1-commit.bf2612ae

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