@aztec/archiver 3.0.3 → 4.0.0-devnet.1-patch.0

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