@aztec/archiver 0.0.1-commit.5daedc8 → 0.0.1-commit.6201a7b05
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.
- package/README.md +162 -22
- package/dest/archiver.d.ts +147 -0
- package/dest/archiver.d.ts.map +1 -0
- package/dest/archiver.js +788 -0
- package/dest/config.d.ts +32 -0
- package/dest/config.d.ts.map +1 -0
- package/dest/config.js +83 -0
- package/dest/errors.d.ts +92 -0
- package/dest/errors.d.ts.map +1 -0
- package/dest/errors.js +136 -0
- package/dest/factory.d.ts +8 -7
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +100 -15
- package/dest/index.d.ts +12 -4
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +10 -3
- package/dest/interfaces.d.ts +9 -0
- package/dest/interfaces.d.ts.map +1 -0
- package/dest/interfaces.js +3 -0
- package/dest/l1/bin/retrieve-calldata.d.ts +3 -0
- package/dest/l1/bin/retrieve-calldata.d.ts.map +1 -0
- package/dest/l1/bin/retrieve-calldata.js +152 -0
- package/dest/l1/calldata_retriever.d.ts +136 -0
- package/dest/l1/calldata_retriever.d.ts.map +1 -0
- package/dest/l1/calldata_retriever.js +408 -0
- package/dest/l1/data_retrieval.d.ts +97 -0
- package/dest/l1/data_retrieval.d.ts.map +1 -0
- package/dest/{archiver → l1}/data_retrieval.js +86 -165
- package/dest/l1/debug_tx.d.ts +19 -0
- package/dest/l1/debug_tx.d.ts.map +1 -0
- package/dest/l1/debug_tx.js +73 -0
- package/dest/l1/spire_proposer.d.ts +70 -0
- package/dest/l1/spire_proposer.d.ts.map +1 -0
- package/dest/l1/spire_proposer.js +149 -0
- package/dest/l1/trace_tx.d.ts +97 -0
- package/dest/l1/trace_tx.d.ts.map +1 -0
- package/dest/l1/trace_tx.js +91 -0
- package/dest/l1/types.d.ts +12 -0
- package/dest/l1/types.d.ts.map +1 -0
- package/dest/l1/types.js +3 -0
- package/dest/l1/validate_historical_logs.d.ts +23 -0
- package/dest/l1/validate_historical_logs.d.ts.map +1 -0
- package/dest/l1/validate_historical_logs.js +108 -0
- package/dest/l1/validate_trace.d.ts +32 -0
- package/dest/l1/validate_trace.d.ts.map +1 -0
- package/dest/l1/validate_trace.js +154 -0
- package/dest/modules/data_source_base.d.ts +95 -0
- package/dest/modules/data_source_base.d.ts.map +1 -0
- package/dest/modules/data_source_base.js +234 -0
- package/dest/modules/data_store_updater.d.ts +93 -0
- package/dest/modules/data_store_updater.d.ts.map +1 -0
- package/dest/modules/data_store_updater.js +345 -0
- package/dest/modules/instrumentation.d.ts +55 -0
- package/dest/modules/instrumentation.d.ts.map +1 -0
- package/dest/modules/instrumentation.js +143 -0
- package/dest/modules/l1_synchronizer.d.ts +77 -0
- package/dest/modules/l1_synchronizer.d.ts.map +1 -0
- package/dest/modules/l1_synchronizer.js +1265 -0
- package/dest/modules/validation.d.ts +18 -0
- package/dest/modules/validation.d.ts.map +1 -0
- package/dest/{archiver → modules}/validation.js +13 -7
- package/dest/store/block_store.d.ts +262 -0
- package/dest/store/block_store.d.ts.map +1 -0
- package/dest/store/block_store.js +1048 -0
- package/dest/store/contract_class_store.d.ts +17 -0
- package/dest/store/contract_class_store.d.ts.map +1 -0
- package/dest/store/contract_class_store.js +64 -0
- package/dest/store/contract_instance_store.d.ts +24 -0
- package/dest/store/contract_instance_store.d.ts.map +1 -0
- package/dest/{archiver/kv_archiver_store → store}/contract_instance_store.js +7 -3
- package/dest/store/kv_archiver_store.d.ts +401 -0
- package/dest/store/kv_archiver_store.d.ts.map +1 -0
- package/dest/store/kv_archiver_store.js +525 -0
- package/dest/store/l2_tips_cache.d.ts +20 -0
- package/dest/store/l2_tips_cache.d.ts.map +1 -0
- package/dest/store/l2_tips_cache.js +109 -0
- package/dest/store/log_store.d.ts +57 -0
- package/dest/store/log_store.d.ts.map +1 -0
- package/dest/store/log_store.js +531 -0
- package/dest/store/message_store.d.ts +44 -0
- package/dest/store/message_store.d.ts.map +1 -0
- package/dest/{archiver/kv_archiver_store → store}/message_store.js +36 -23
- package/dest/{archiver/structs → structs}/data_retrieval.d.ts +1 -1
- package/dest/structs/data_retrieval.d.ts.map +1 -0
- package/dest/structs/inbox_message.d.ts +15 -0
- package/dest/structs/inbox_message.d.ts.map +1 -0
- package/dest/{archiver/structs → structs}/inbox_message.js +6 -5
- package/dest/structs/published.d.ts +2 -0
- package/dest/structs/published.d.ts.map +1 -0
- package/dest/test/fake_l1_state.d.ts +214 -0
- package/dest/test/fake_l1_state.d.ts.map +1 -0
- package/dest/test/fake_l1_state.js +517 -0
- package/dest/test/index.d.ts +2 -1
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +4 -1
- package/dest/test/mock_archiver.d.ts +16 -8
- package/dest/test/mock_archiver.d.ts.map +1 -1
- package/dest/test/mock_archiver.js +19 -14
- package/dest/test/mock_l1_to_l2_message_source.d.ts +7 -6
- package/dest/test/mock_l1_to_l2_message_source.d.ts.map +1 -1
- package/dest/test/mock_l1_to_l2_message_source.js +23 -12
- package/dest/test/mock_l2_block_source.d.ts +68 -20
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +298 -85
- package/dest/test/mock_structs.d.ts +83 -4
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +157 -11
- package/dest/test/noop_l1_archiver.d.ts +26 -0
- package/dest/test/noop_l1_archiver.d.ts.map +1 -0
- package/dest/test/noop_l1_archiver.js +74 -0
- package/package.json +20 -20
- package/src/archiver.ts +566 -0
- package/src/{archiver/config.ts → config.ts} +51 -14
- package/src/errors.ts +213 -0
- package/src/factory.ts +155 -17
- package/src/index.ts +12 -3
- package/src/interfaces.ts +9 -0
- package/src/l1/README.md +55 -0
- package/src/l1/bin/retrieve-calldata.ts +194 -0
- package/src/l1/calldata_retriever.ts +523 -0
- package/src/{archiver → l1}/data_retrieval.ts +155 -247
- package/src/l1/debug_tx.ts +99 -0
- package/src/l1/spire_proposer.ts +152 -0
- package/src/l1/trace_tx.ts +128 -0
- package/src/l1/types.ts +13 -0
- package/src/l1/validate_historical_logs.ts +140 -0
- package/src/l1/validate_trace.ts +229 -0
- package/src/modules/data_source_base.ts +364 -0
- package/src/modules/data_store_updater.ts +465 -0
- package/src/modules/instrumentation.ts +204 -0
- package/src/modules/l1_synchronizer.ts +1126 -0
- package/src/{archiver → modules}/validation.ts +21 -15
- package/src/store/block_store.ts +1361 -0
- package/src/store/contract_class_store.ts +82 -0
- package/src/{archiver/kv_archiver_store → store}/contract_instance_store.ts +10 -7
- package/src/store/kv_archiver_store.ts +765 -0
- package/src/store/l2_tips_cache.ts +134 -0
- package/src/store/log_store.ts +733 -0
- package/src/{archiver/kv_archiver_store → store}/message_store.ts +48 -28
- package/src/{archiver/structs → structs}/inbox_message.ts +7 -7
- package/src/{archiver/structs → structs}/published.ts +0 -1
- package/src/test/fake_l1_state.ts +770 -0
- package/src/test/fixtures/debug_traceTransaction-multicall3.json +88 -0
- package/src/test/fixtures/debug_traceTransaction-multiplePropose.json +153 -0
- package/src/test/fixtures/debug_traceTransaction-proxied.json +122 -0
- package/src/test/fixtures/trace_transaction-multicall3.json +65 -0
- package/src/test/fixtures/trace_transaction-multiplePropose.json +319 -0
- package/src/test/fixtures/trace_transaction-proxied.json +128 -0
- package/src/test/fixtures/trace_transaction-randomRevert.json +216 -0
- package/src/test/index.ts +4 -0
- package/src/test/mock_archiver.ts +23 -16
- package/src/test/mock_l1_to_l2_message_source.ts +19 -11
- package/src/test/mock_l2_block_source.ts +367 -93
- package/src/test/mock_structs.ts +289 -13
- package/src/test/noop_l1_archiver.ts +117 -0
- package/dest/archiver/archiver.d.ts +0 -287
- package/dest/archiver/archiver.d.ts.map +0 -1
- package/dest/archiver/archiver.js +0 -1408
- package/dest/archiver/archiver_store.d.ts +0 -255
- package/dest/archiver/archiver_store.d.ts.map +0 -1
- package/dest/archiver/archiver_store.js +0 -4
- package/dest/archiver/archiver_store_test_suite.d.ts +0 -8
- package/dest/archiver/archiver_store_test_suite.d.ts.map +0 -1
- package/dest/archiver/archiver_store_test_suite.js +0 -1289
- package/dest/archiver/config.d.ts +0 -21
- package/dest/archiver/config.d.ts.map +0 -1
- package/dest/archiver/config.js +0 -55
- package/dest/archiver/data_retrieval.d.ts +0 -79
- package/dest/archiver/data_retrieval.d.ts.map +0 -1
- package/dest/archiver/errors.d.ts +0 -12
- package/dest/archiver/errors.d.ts.map +0 -1
- package/dest/archiver/errors.js +0 -17
- package/dest/archiver/index.d.ts +0 -7
- package/dest/archiver/index.d.ts.map +0 -1
- package/dest/archiver/index.js +0 -4
- package/dest/archiver/instrumentation.d.ts +0 -35
- package/dest/archiver/instrumentation.d.ts.map +0 -1
- package/dest/archiver/instrumentation.js +0 -140
- package/dest/archiver/kv_archiver_store/block_store.d.ts +0 -124
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/block_store.js +0 -370
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +0 -18
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.js +0 -120
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +0 -24
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +0 -168
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +0 -296
- package/dest/archiver/kv_archiver_store/log_store.d.ts +0 -49
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +0 -1
- package/dest/archiver/kv_archiver_store/log_store.js +0 -336
- package/dest/archiver/kv_archiver_store/message_store.d.ts +0 -39
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +0 -1
- package/dest/archiver/structs/data_retrieval.d.ts.map +0 -1
- package/dest/archiver/structs/inbox_message.d.ts +0 -15
- package/dest/archiver/structs/inbox_message.d.ts.map +0 -1
- package/dest/archiver/structs/published.d.ts +0 -3
- package/dest/archiver/structs/published.d.ts.map +0 -1
- package/dest/archiver/validation.d.ts +0 -17
- package/dest/archiver/validation.d.ts.map +0 -1
- package/dest/rpc/index.d.ts +0 -9
- package/dest/rpc/index.d.ts.map +0 -1
- package/dest/rpc/index.js +0 -15
- package/src/archiver/archiver.ts +0 -1858
- package/src/archiver/archiver_store.ts +0 -305
- package/src/archiver/archiver_store_test_suite.ts +0 -1264
- package/src/archiver/errors.ts +0 -26
- package/src/archiver/index.ts +0 -6
- package/src/archiver/instrumentation.ts +0 -187
- package/src/archiver/kv_archiver_store/block_store.ts +0 -481
- package/src/archiver/kv_archiver_store/contract_class_store.ts +0 -176
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +0 -422
- package/src/archiver/kv_archiver_store/log_store.ts +0 -406
- package/src/rpc/index.ts +0 -16
- /package/dest/{archiver/structs → structs}/data_retrieval.js +0 -0
- /package/dest/{archiver/structs → structs}/published.js +0 -0
- /package/src/{archiver/structs → structs}/data_retrieval.ts +0 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import type { ViemPublicDebugClient } from '@aztec/ethereum/types';
|
|
2
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
|
+
|
|
4
|
+
import type { Hex } from 'viem';
|
|
5
|
+
import type { ZodSchema } from 'zod';
|
|
6
|
+
|
|
7
|
+
import { callTraceSchema } from './debug_tx.js';
|
|
8
|
+
import { traceTransactionResponseSchema } from './trace_tx.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Helper function to test a trace method with validation
|
|
12
|
+
*
|
|
13
|
+
* @param client - The Viem public debug client
|
|
14
|
+
* @param txHash - Transaction hash to trace
|
|
15
|
+
* @param schema - Zod schema to validate the response
|
|
16
|
+
* @param method - Name of the RPC method ('debug_traceTransaction' or 'trace_transaction')
|
|
17
|
+
* @param blockType - Type of block being tested ('recent' or 'old')
|
|
18
|
+
* @param logger - Logger instance
|
|
19
|
+
* @returns true if the method works and validation passes, false otherwise
|
|
20
|
+
*/
|
|
21
|
+
async function testTraceMethod(
|
|
22
|
+
client: ViemPublicDebugClient,
|
|
23
|
+
txHash: Hex,
|
|
24
|
+
schema: ZodSchema,
|
|
25
|
+
method: 'debug_traceTransaction' | 'trace_transaction',
|
|
26
|
+
blockType: string,
|
|
27
|
+
logger: Logger,
|
|
28
|
+
): Promise<boolean> {
|
|
29
|
+
try {
|
|
30
|
+
// Make request with appropriate params based on method name
|
|
31
|
+
const result = await client.request(
|
|
32
|
+
method === 'debug_traceTransaction'
|
|
33
|
+
? { method, params: [txHash, { tracer: 'callTracer' }] }
|
|
34
|
+
: { method, params: [txHash] },
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
schema.parse(result);
|
|
38
|
+
logger.debug(`${method} works for ${blockType} blocks`);
|
|
39
|
+
return true;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
logger.warn(`${method} failed for ${blockType} blocks: ${error}`);
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Result of trace availability checks */
|
|
47
|
+
export interface TraceAvailability {
|
|
48
|
+
/** Whether debug_traceTransaction works for recent blocks */
|
|
49
|
+
debugTraceRecent: boolean;
|
|
50
|
+
/** Whether trace_transaction works for recent blocks */
|
|
51
|
+
traceTransactionRecent: boolean;
|
|
52
|
+
/** Whether debug_traceTransaction works for old blocks (512 blocks ago) */
|
|
53
|
+
debugTraceOld: boolean;
|
|
54
|
+
/** Whether trace_transaction works for old blocks (512 blocks ago) */
|
|
55
|
+
traceTransactionOld: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Validates the availability of debug/trace methods on the Ethereum client.
|
|
60
|
+
*
|
|
61
|
+
* @param client - The Viem public debug client
|
|
62
|
+
* @param bindings - Optional logger bindings for context
|
|
63
|
+
* @returns Object indicating which trace methods are available for recent and old blocks
|
|
64
|
+
*/
|
|
65
|
+
export async function validateTraceAvailability(
|
|
66
|
+
client: ViemPublicDebugClient,
|
|
67
|
+
bindings?: LoggerBindings,
|
|
68
|
+
): Promise<TraceAvailability> {
|
|
69
|
+
const logger = createLogger('archiver:validate_trace', bindings);
|
|
70
|
+
const result: TraceAvailability = {
|
|
71
|
+
debugTraceRecent: false,
|
|
72
|
+
traceTransactionRecent: false,
|
|
73
|
+
debugTraceOld: false,
|
|
74
|
+
traceTransactionOld: false,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
// Get the latest block
|
|
79
|
+
let latestBlock = await client.getBlock({ blockTag: 'latest' });
|
|
80
|
+
let attempts = 10;
|
|
81
|
+
|
|
82
|
+
// Loop back to find a block with transactions (handles dev/test scenarios)
|
|
83
|
+
while (!hasTxs(latestBlock) && latestBlock.number && latestBlock.number > 0n && --attempts > 0) {
|
|
84
|
+
logger.debug(`Block ${latestBlock.number} has no transactions, checking previous block`);
|
|
85
|
+
latestBlock = await client.getBlock({ blockNumber: latestBlock.number - 1n });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!hasTxs(latestBlock)) {
|
|
89
|
+
logger.warn('No blocks with transactions found from latest back to genesis, cannot validate trace availability');
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Get a transaction from the found block
|
|
94
|
+
const recentTxHash = latestBlock.transactions[0] as Hex;
|
|
95
|
+
|
|
96
|
+
// Test debug_traceTransaction with recent block
|
|
97
|
+
result.debugTraceRecent = await testTraceMethod(
|
|
98
|
+
client,
|
|
99
|
+
recentTxHash,
|
|
100
|
+
callTraceSchema,
|
|
101
|
+
'debug_traceTransaction',
|
|
102
|
+
'recent',
|
|
103
|
+
logger,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// Test trace_transaction with recent block
|
|
107
|
+
result.traceTransactionRecent = await testTraceMethod(
|
|
108
|
+
client,
|
|
109
|
+
recentTxHash,
|
|
110
|
+
traceTransactionResponseSchema,
|
|
111
|
+
'trace_transaction',
|
|
112
|
+
'recent',
|
|
113
|
+
logger,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
// Get a block from 512 blocks ago
|
|
117
|
+
const oldBlockNumber = latestBlock.number ? latestBlock.number - 512n : null;
|
|
118
|
+
if (!oldBlockNumber || oldBlockNumber < 0n) {
|
|
119
|
+
logger.debug('Cannot test old blocks, blockchain too short');
|
|
120
|
+
return result;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let oldBlock = await client.getBlock({ blockNumber: oldBlockNumber });
|
|
124
|
+
attempts = 10;
|
|
125
|
+
|
|
126
|
+
// Loop back to find a block with transactions (handles dev/test scenarios)
|
|
127
|
+
while (!hasTxs(oldBlock) && oldBlock.number && oldBlock.number > 0n && --attempts > 0) {
|
|
128
|
+
logger.debug(`Block ${oldBlock.number} has no transactions, checking previous block`);
|
|
129
|
+
oldBlock = await client.getBlock({ blockNumber: oldBlock.number - 1n });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (!hasTxs(oldBlock)) {
|
|
133
|
+
logger.debug(
|
|
134
|
+
'No blocks with transactions found from old block back to genesis, cannot validate trace availability for old blocks',
|
|
135
|
+
);
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const oldTxHash = oldBlock.transactions[0] as Hex;
|
|
140
|
+
|
|
141
|
+
// Test debug_traceTransaction with old block
|
|
142
|
+
result.debugTraceOld = await testTraceMethod(
|
|
143
|
+
client,
|
|
144
|
+
oldTxHash,
|
|
145
|
+
callTraceSchema,
|
|
146
|
+
'debug_traceTransaction',
|
|
147
|
+
'old',
|
|
148
|
+
logger,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Test trace_transaction with old block
|
|
152
|
+
result.traceTransactionOld = await testTraceMethod(
|
|
153
|
+
client,
|
|
154
|
+
oldTxHash,
|
|
155
|
+
traceTransactionResponseSchema,
|
|
156
|
+
'trace_transaction',
|
|
157
|
+
'old',
|
|
158
|
+
logger,
|
|
159
|
+
);
|
|
160
|
+
} catch (error) {
|
|
161
|
+
logger.warn(`Error validating debug_traceTransaction and trace_transaction availability: ${error}`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function hasTxs(block: { transactions?: Hex[] }): boolean {
|
|
168
|
+
return Array.isArray(block.transactions) && block.transactions.length > 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Validates trace availability and logs appropriate messages based on the results.
|
|
173
|
+
* Optionally throws an error if no trace methods are available and ethereumAllowNoDebugHosts is false.
|
|
174
|
+
*
|
|
175
|
+
* @param client - The Viem public debug client
|
|
176
|
+
* @param ethereumAllowNoDebugHosts - If false, throws an error when no trace methods are available
|
|
177
|
+
* @param bindings - Optional logger bindings for context
|
|
178
|
+
* @throws Error if ethereumAllowNoDebugHosts is false and no trace methods are available
|
|
179
|
+
*/
|
|
180
|
+
export async function validateAndLogTraceAvailability(
|
|
181
|
+
client: ViemPublicDebugClient,
|
|
182
|
+
ethereumAllowNoDebugHosts: boolean,
|
|
183
|
+
bindings?: LoggerBindings,
|
|
184
|
+
): Promise<void> {
|
|
185
|
+
const logger = createLogger('archiver:validate_trace', bindings);
|
|
186
|
+
logger.debug('Validating trace/debug method availability...');
|
|
187
|
+
|
|
188
|
+
const availability = await validateTraceAvailability(client, bindings);
|
|
189
|
+
|
|
190
|
+
// Check if we have support for old blocks (either debug or trace)
|
|
191
|
+
const hasOldBlockSupport = availability.debugTraceOld || availability.traceTransactionOld;
|
|
192
|
+
|
|
193
|
+
if (hasOldBlockSupport) {
|
|
194
|
+
// Ideal case: we have trace support for old blocks
|
|
195
|
+
const methods: string[] = [];
|
|
196
|
+
if (availability.debugTraceOld) {
|
|
197
|
+
methods.push('debug_traceTransaction');
|
|
198
|
+
}
|
|
199
|
+
if (availability.traceTransactionOld) {
|
|
200
|
+
methods.push('trace_transaction');
|
|
201
|
+
}
|
|
202
|
+
logger.info(
|
|
203
|
+
`Ethereum client supports trace methods for old blocks (${methods.join(', ')}). Archiver can retrieve historical transaction traces.`,
|
|
204
|
+
);
|
|
205
|
+
} else if (availability.debugTraceRecent || availability.traceTransactionRecent) {
|
|
206
|
+
// Warning case: only recent block support
|
|
207
|
+
const methods: string[] = [];
|
|
208
|
+
if (availability.debugTraceRecent) {
|
|
209
|
+
methods.push('debug_traceTransaction');
|
|
210
|
+
}
|
|
211
|
+
if (availability.traceTransactionRecent) {
|
|
212
|
+
methods.push('trace_transaction');
|
|
213
|
+
}
|
|
214
|
+
logger.warn(
|
|
215
|
+
`Ethereum client only supports trace methods for recent blocks (${methods.join(', ')}). Historical transaction traces may not be available.`,
|
|
216
|
+
);
|
|
217
|
+
} else {
|
|
218
|
+
// Error case: no support at all
|
|
219
|
+
const errorMessage =
|
|
220
|
+
'Ethereum debug client does not support debug_traceTransaction or trace_transaction methods. Transaction tracing will not be available. This may impact archiver syncing.';
|
|
221
|
+
|
|
222
|
+
if (ethereumAllowNoDebugHosts) {
|
|
223
|
+
logger.warn(`${errorMessage} Continuing because ETHEREUM_ALLOW_NO_DEBUG_HOSTS is set to true.`);
|
|
224
|
+
} else {
|
|
225
|
+
logger.error(errorMessage);
|
|
226
|
+
throw new Error(`${errorMessage} Set ETHEREUM_ALLOW_NO_DEBUG_HOSTS=true to bypass this check.`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { range } from '@aztec/foundation/array';
|
|
2
|
+
import { BlockNumber, CheckpointNumber, type EpochNumber, type SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
+
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
|
+
import { isDefined } from '@aztec/foundation/types';
|
|
6
|
+
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
7
|
+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
8
|
+
import { type BlockData, type BlockHash, CheckpointedL2Block, L2Block, type L2Tips } from '@aztec/stdlib/block';
|
|
9
|
+
import {
|
|
10
|
+
Checkpoint,
|
|
11
|
+
type CheckpointData,
|
|
12
|
+
type CommonCheckpointData,
|
|
13
|
+
type ProposedCheckpointData,
|
|
14
|
+
PublishedCheckpoint,
|
|
15
|
+
} from '@aztec/stdlib/checkpoint';
|
|
16
|
+
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
17
|
+
import { type L1RollupConstants, getSlotRangeForEpoch } from '@aztec/stdlib/epoch-helpers';
|
|
18
|
+
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from '@aztec/stdlib/interfaces/client';
|
|
19
|
+
import type { L2LogsSource } from '@aztec/stdlib/interfaces/server';
|
|
20
|
+
import type { LogFilter, SiloedTag, Tag, TxScopedL2Log } from '@aztec/stdlib/logs';
|
|
21
|
+
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
22
|
+
import type { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
23
|
+
import type { BlockHeader, IndexedTxEffect, TxHash, TxReceipt } from '@aztec/stdlib/tx';
|
|
24
|
+
import type { UInt64 } from '@aztec/stdlib/types';
|
|
25
|
+
|
|
26
|
+
import type { ArchiverDataSource } from '../interfaces.js';
|
|
27
|
+
import type { KVArchiverDataStore } from '../store/kv_archiver_store.js';
|
|
28
|
+
import type { ValidateCheckpointResult } from './validation.js';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Abstract base class implementing ArchiverDataSource using a KVArchiverDataStore.
|
|
32
|
+
* Provides implementations for all store-delegating methods and declares abstract methods
|
|
33
|
+
* for L1-dependent functionality that subclasses must implement.
|
|
34
|
+
*/
|
|
35
|
+
export abstract class ArchiverDataSourceBase
|
|
36
|
+
implements ArchiverDataSource, L2LogsSource, ContractDataSource, L1ToL2MessageSource
|
|
37
|
+
{
|
|
38
|
+
constructor(
|
|
39
|
+
protected readonly store: KVArchiverDataStore,
|
|
40
|
+
protected readonly l1Constants?: L1RollupConstants,
|
|
41
|
+
) {}
|
|
42
|
+
|
|
43
|
+
abstract getRollupAddress(): Promise<EthAddress>;
|
|
44
|
+
|
|
45
|
+
abstract getRegistryAddress(): Promise<EthAddress>;
|
|
46
|
+
|
|
47
|
+
abstract getL1Constants(): Promise<L1RollupConstants>;
|
|
48
|
+
|
|
49
|
+
abstract getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }>;
|
|
50
|
+
|
|
51
|
+
abstract getL1Timestamp(): Promise<bigint | undefined>;
|
|
52
|
+
|
|
53
|
+
abstract getL2Tips(): Promise<L2Tips>;
|
|
54
|
+
|
|
55
|
+
abstract getSyncedL2SlotNumber(): Promise<SlotNumber | undefined>;
|
|
56
|
+
|
|
57
|
+
abstract getSyncedL2EpochNumber(): Promise<EpochNumber | undefined>;
|
|
58
|
+
|
|
59
|
+
abstract isEpochComplete(epochNumber: EpochNumber): Promise<boolean>;
|
|
60
|
+
|
|
61
|
+
abstract syncImmediate(): Promise<void>;
|
|
62
|
+
|
|
63
|
+
public getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
64
|
+
return this.store.getSynchedCheckpointNumber();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public getSynchedCheckpointNumber(): Promise<CheckpointNumber> {
|
|
68
|
+
return this.store.getSynchedCheckpointNumber();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public getProvenCheckpointNumber(): Promise<CheckpointNumber> {
|
|
72
|
+
return this.store.getProvenCheckpointNumber();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public getBlockNumber(): Promise<BlockNumber> {
|
|
76
|
+
return this.store.getLatestBlockNumber();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public getProvenBlockNumber(): Promise<BlockNumber> {
|
|
80
|
+
return this.store.getProvenBlockNumber();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public async getBlockHeader(number: BlockNumber | 'latest'): Promise<BlockHeader | undefined> {
|
|
84
|
+
const blockNumber = number === 'latest' ? await this.store.getLatestBlockNumber() : number;
|
|
85
|
+
if (blockNumber === 0) {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
const headers = await this.store.getBlockHeaders(blockNumber, 1);
|
|
89
|
+
return headers.length === 0 ? undefined : headers[0];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public getCheckpointedBlock(number: BlockNumber): Promise<CheckpointedL2Block | undefined> {
|
|
93
|
+
return this.store.getCheckpointedBlock(number);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public getCheckpointedL2BlockNumber(): Promise<BlockNumber> {
|
|
97
|
+
return this.store.getCheckpointedL2BlockNumber();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public getFinalizedL2BlockNumber(): Promise<BlockNumber> {
|
|
101
|
+
return this.store.getFinalizedL2BlockNumber();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public async getCheckpointHeader(number: CheckpointNumber | 'latest'): Promise<CheckpointHeader | undefined> {
|
|
105
|
+
if (number === 'latest') {
|
|
106
|
+
number = await this.store.getSynchedCheckpointNumber();
|
|
107
|
+
}
|
|
108
|
+
if (number === 0) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
const checkpoint = await this.store.getCheckpointData(number);
|
|
112
|
+
if (!checkpoint) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
return checkpoint.header;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public async getLastBlockNumberInCheckpoint(checkpointNumber: CheckpointNumber): Promise<BlockNumber | undefined> {
|
|
119
|
+
const checkpointData = await this.store.getCheckpointData(checkpointNumber);
|
|
120
|
+
if (!checkpointData) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
return BlockNumber(checkpointData.startBlock + checkpointData.blockCount - 1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public getCheckpointedBlocks(from: BlockNumber, limit: number): Promise<CheckpointedL2Block[]> {
|
|
127
|
+
return this.store.getCheckpointedBlocks(from, limit);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public getCheckpointData(checkpointNumber: CheckpointNumber): Promise<CheckpointData | undefined> {
|
|
131
|
+
return this.store.getCheckpointData(checkpointNumber);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public getCheckpointDataRange(from: CheckpointNumber, limit: number): Promise<CheckpointData[]> {
|
|
135
|
+
return this.store.getCheckpointDataRange(from, limit);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public getCheckpointNumberBySlot(slot: SlotNumber): Promise<CheckpointNumber | undefined> {
|
|
139
|
+
return this.store.getCheckpointNumberBySlot(slot);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public getBlockDataWithCheckpointContext(blockNumber: BlockNumber) {
|
|
143
|
+
return this.store.getBlockDataWithCheckpointContext(blockNumber);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public getBlockHeaderByHash(blockHash: BlockHash): Promise<BlockHeader | undefined> {
|
|
147
|
+
return this.store.getBlockHeaderByHash(blockHash);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public getBlockHeaderByArchive(archive: Fr): Promise<BlockHeader | undefined> {
|
|
151
|
+
return this.store.getBlockHeaderByArchive(archive);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public getBlockData(number: BlockNumber): Promise<BlockData | undefined> {
|
|
155
|
+
return this.store.getBlockData(number);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
public getBlockDataByArchive(archive: Fr): Promise<BlockData | undefined> {
|
|
159
|
+
return this.store.getBlockDataByArchive(archive);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public async getL2Block(number: BlockNumber): Promise<L2Block | undefined> {
|
|
163
|
+
// If the number provided is -ve, then return the latest block.
|
|
164
|
+
if (number < 0) {
|
|
165
|
+
number = await this.store.getLatestBlockNumber();
|
|
166
|
+
}
|
|
167
|
+
if (number === 0) {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
const publishedBlock = await this.store.getBlock(number);
|
|
171
|
+
return publishedBlock;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public getTxEffect(txHash: TxHash): Promise<IndexedTxEffect | undefined> {
|
|
175
|
+
return this.store.getTxEffect(txHash);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
public getSettledTxReceipt(txHash: TxHash): Promise<TxReceipt | undefined> {
|
|
179
|
+
return this.store.getSettledTxReceipt(txHash, this.l1Constants);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public getLastCheckpoint(): Promise<CommonCheckpointData | undefined> {
|
|
183
|
+
return this.store.getLastCheckpoint();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public getLastProposedCheckpoint(): Promise<ProposedCheckpointData | undefined> {
|
|
187
|
+
return this.store.getLastProposedCheckpoint();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public isPendingChainInvalid(): Promise<boolean> {
|
|
191
|
+
return this.getPendingChainValidationStatus().then(status => !status.valid);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public async getPendingChainValidationStatus(): Promise<ValidateCheckpointResult> {
|
|
195
|
+
return (await this.store.getPendingChainValidationStatus()) ?? { valid: true };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public getPrivateLogsByTags(
|
|
199
|
+
tags: SiloedTag[],
|
|
200
|
+
page?: number,
|
|
201
|
+
upToBlockNumber?: BlockNumber,
|
|
202
|
+
): Promise<TxScopedL2Log[][]> {
|
|
203
|
+
return this.store.getPrivateLogsByTags(tags, page, upToBlockNumber);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public getPublicLogsByTagsFromContract(
|
|
207
|
+
contractAddress: AztecAddress,
|
|
208
|
+
tags: Tag[],
|
|
209
|
+
page?: number,
|
|
210
|
+
upToBlockNumber?: BlockNumber,
|
|
211
|
+
): Promise<TxScopedL2Log[][]> {
|
|
212
|
+
return this.store.getPublicLogsByTagsFromContract(contractAddress, tags, page, upToBlockNumber);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public getPublicLogs(filter: LogFilter): Promise<GetPublicLogsResponse> {
|
|
216
|
+
return this.store.getPublicLogs(filter);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public getContractClassLogs(filter: LogFilter): Promise<GetContractClassLogsResponse> {
|
|
220
|
+
return this.store.getContractClassLogs(filter);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
public getContractClass(id: Fr): Promise<ContractClassPublic | undefined> {
|
|
224
|
+
return this.store.getContractClass(id);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
public getBytecodeCommitment(id: Fr): Promise<Fr | undefined> {
|
|
228
|
+
return this.store.getBytecodeCommitment(id);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
public async getContract(
|
|
232
|
+
address: AztecAddress,
|
|
233
|
+
maybeTimestamp?: UInt64,
|
|
234
|
+
): Promise<ContractInstanceWithAddress | undefined> {
|
|
235
|
+
let timestamp;
|
|
236
|
+
if (maybeTimestamp === undefined) {
|
|
237
|
+
const latestBlockHeader = await this.getBlockHeader('latest');
|
|
238
|
+
// If we get undefined block header, it means that the archiver has not yet synced any block so we default to 0.
|
|
239
|
+
timestamp = latestBlockHeader ? latestBlockHeader.globalVariables.timestamp : 0n;
|
|
240
|
+
} else {
|
|
241
|
+
timestamp = maybeTimestamp;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return this.store.getContractInstance(address, timestamp);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
public getContractClassIds(): Promise<Fr[]> {
|
|
248
|
+
return this.store.getContractClassIds();
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
public getDebugFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined> {
|
|
252
|
+
return this.store.getDebugFunctionName(address, selector);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
public registerContractFunctionSignatures(signatures: string[]): Promise<void> {
|
|
256
|
+
return this.store.registerContractFunctionSignatures(signatures);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
public getL1ToL2Messages(checkpointNumber: CheckpointNumber): Promise<Fr[]> {
|
|
260
|
+
return this.store.getL1ToL2Messages(checkpointNumber);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise<bigint | undefined> {
|
|
264
|
+
return this.store.getL1ToL2MessageIndex(l1ToL2Message);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
public async getCheckpoints(checkpointNumber: CheckpointNumber, limit: number): Promise<PublishedCheckpoint[]> {
|
|
268
|
+
const checkpoints = await this.store.getRangeOfCheckpoints(checkpointNumber, limit);
|
|
269
|
+
return Promise.all(checkpoints.map(ch => this.getPublishedCheckpointFromCheckpointData(ch)));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private async getPublishedCheckpointFromCheckpointData(checkpoint: CheckpointData): Promise<PublishedCheckpoint> {
|
|
273
|
+
const blocksForCheckpoint = await this.store.getBlocksForCheckpoint(checkpoint.checkpointNumber);
|
|
274
|
+
if (!blocksForCheckpoint) {
|
|
275
|
+
throw new Error(`Blocks for checkpoint ${checkpoint.checkpointNumber} not found`);
|
|
276
|
+
}
|
|
277
|
+
const fullCheckpoint = new Checkpoint(
|
|
278
|
+
checkpoint.archive,
|
|
279
|
+
checkpoint.header,
|
|
280
|
+
blocksForCheckpoint,
|
|
281
|
+
checkpoint.checkpointNumber,
|
|
282
|
+
checkpoint.feeAssetPriceModifier,
|
|
283
|
+
);
|
|
284
|
+
return new PublishedCheckpoint(fullCheckpoint, checkpoint.l1, checkpoint.attestations);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
public getBlocksForSlot(slotNumber: SlotNumber): Promise<L2Block[]> {
|
|
288
|
+
return this.store.getBlocksForSlot(slotNumber);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
public async getCheckpointedBlocksForEpoch(epochNumber: EpochNumber): Promise<CheckpointedL2Block[]> {
|
|
292
|
+
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
293
|
+
const blocks = await Promise.all(
|
|
294
|
+
checkpointsData.flatMap(checkpoint =>
|
|
295
|
+
range(checkpoint.blockCount, checkpoint.startBlock).map(blockNumber =>
|
|
296
|
+
this.getCheckpointedBlock(BlockNumber(blockNumber)),
|
|
297
|
+
),
|
|
298
|
+
),
|
|
299
|
+
);
|
|
300
|
+
return blocks.filter(isDefined);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
public async getCheckpointedBlockHeadersForEpoch(epochNumber: EpochNumber): Promise<BlockHeader[]> {
|
|
304
|
+
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
305
|
+
const blocks = await Promise.all(
|
|
306
|
+
checkpointsData.flatMap(checkpoint =>
|
|
307
|
+
range(checkpoint.blockCount, checkpoint.startBlock).map(blockNumber =>
|
|
308
|
+
this.getBlockHeader(BlockNumber(blockNumber)),
|
|
309
|
+
),
|
|
310
|
+
),
|
|
311
|
+
);
|
|
312
|
+
return blocks.filter(isDefined);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
public async getCheckpointsForEpoch(epochNumber: EpochNumber): Promise<Checkpoint[]> {
|
|
316
|
+
const checkpointsData = await this.getCheckpointsDataForEpoch(epochNumber);
|
|
317
|
+
return Promise.all(
|
|
318
|
+
checkpointsData.map(data => this.getPublishedCheckpointFromCheckpointData(data).then(p => p.checkpoint)),
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Returns checkpoint data for all checkpoints whose slot falls within the given epoch. */
|
|
323
|
+
public getCheckpointsDataForEpoch(epochNumber: EpochNumber): Promise<CheckpointData[]> {
|
|
324
|
+
if (!this.l1Constants) {
|
|
325
|
+
throw new Error('L1 constants not set');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const [start, end] = getSlotRangeForEpoch(epochNumber, this.l1Constants);
|
|
329
|
+
return this.store.getCheckpointDataForSlotRange(start, end);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
public async getBlock(number: BlockNumber): Promise<L2Block | undefined> {
|
|
333
|
+
// If the number provided is -ve, then return the latest block.
|
|
334
|
+
if (number < 0) {
|
|
335
|
+
number = await this.store.getLatestBlockNumber();
|
|
336
|
+
}
|
|
337
|
+
if (number === 0) {
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
return this.store.getBlock(number);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
public getBlocks(from: BlockNumber, limit: number): Promise<L2Block[]> {
|
|
344
|
+
return this.store.getBlocks(from, limit);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
public getCheckpointedBlockByHash(blockHash: BlockHash): Promise<CheckpointedL2Block | undefined> {
|
|
348
|
+
return this.store.getCheckpointedBlockByHash(blockHash);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
public getCheckpointedBlockByArchive(archive: Fr): Promise<CheckpointedL2Block | undefined> {
|
|
352
|
+
return this.store.getCheckpointedBlockByArchive(archive);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
public async getL2BlockByHash(blockHash: BlockHash): Promise<L2Block | undefined> {
|
|
356
|
+
const checkpointedBlock = await this.store.getCheckpointedBlockByHash(blockHash);
|
|
357
|
+
return checkpointedBlock?.block;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
public async getL2BlockByArchive(archive: Fr): Promise<L2Block | undefined> {
|
|
361
|
+
const checkpointedBlock = await this.store.getCheckpointedBlockByArchive(archive);
|
|
362
|
+
return checkpointedBlock?.block;
|
|
363
|
+
}
|
|
364
|
+
}
|