@aztec/archiver 3.0.0-devnet.6 → 3.0.0-devnet.6-patch.1
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/dest/archiver/archiver.d.ts +67 -60
- package/dest/archiver/archiver.d.ts.map +1 -1
- package/dest/archiver/archiver.js +391 -262
- package/dest/archiver/archiver_store.d.ts +21 -27
- package/dest/archiver/archiver_store.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts +1 -1
- package/dest/archiver/archiver_store_test_suite.d.ts.map +1 -1
- package/dest/archiver/archiver_store_test_suite.js +125 -140
- package/dest/archiver/config.d.ts +3 -2
- package/dest/archiver/config.d.ts.map +1 -1
- package/dest/archiver/config.js +13 -1
- package/dest/archiver/errors.d.ts +1 -1
- package/dest/archiver/errors.d.ts.map +1 -1
- package/dest/archiver/index.d.ts +1 -1
- package/dest/archiver/instrumentation.d.ts +5 -3
- package/dest/archiver/instrumentation.d.ts.map +1 -1
- package/dest/archiver/instrumentation.js +11 -0
- package/dest/archiver/kv_archiver_store/block_store.d.ts +10 -9
- package/dest/archiver/kv_archiver_store/block_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/block_store.js +9 -8
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/contract_class_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/contract_class_store.js +1 -1
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts +2 -2
- package/dest/archiver/kv_archiver_store/contract_instance_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts +23 -29
- package/dest/archiver/kv_archiver_store/kv_archiver_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/kv_archiver_store.js +7 -15
- package/dest/archiver/kv_archiver_store/log_store.d.ts +3 -10
- package/dest/archiver/kv_archiver_store/log_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/log_store.js +4 -26
- package/dest/archiver/kv_archiver_store/message_store.d.ts +6 -5
- package/dest/archiver/kv_archiver_store/message_store.d.ts.map +1 -1
- package/dest/archiver/kv_archiver_store/message_store.js +15 -14
- package/dest/archiver/l1/bin/retrieve-calldata.d.ts +3 -0
- package/dest/archiver/l1/bin/retrieve-calldata.d.ts.map +1 -0
- package/dest/archiver/l1/bin/retrieve-calldata.js +147 -0
- package/dest/archiver/l1/calldata_retriever.d.ts +98 -0
- package/dest/archiver/l1/calldata_retriever.d.ts.map +1 -0
- package/dest/archiver/l1/calldata_retriever.js +403 -0
- package/dest/archiver/l1/data_retrieval.d.ts +87 -0
- package/dest/archiver/l1/data_retrieval.d.ts.map +1 -0
- package/dest/archiver/l1/data_retrieval.js +318 -0
- package/dest/archiver/l1/debug_tx.d.ts +19 -0
- package/dest/archiver/l1/debug_tx.d.ts.map +1 -0
- package/dest/archiver/l1/debug_tx.js +73 -0
- package/dest/archiver/l1/spire_proposer.d.ts +70 -0
- package/dest/archiver/l1/spire_proposer.d.ts.map +1 -0
- package/dest/archiver/l1/spire_proposer.js +157 -0
- package/dest/archiver/l1/trace_tx.d.ts +97 -0
- package/dest/archiver/l1/trace_tx.d.ts.map +1 -0
- package/dest/archiver/l1/trace_tx.js +91 -0
- package/dest/archiver/l1/types.d.ts +12 -0
- package/dest/archiver/l1/types.d.ts.map +1 -0
- package/dest/archiver/l1/types.js +3 -0
- package/dest/archiver/l1/validate_trace.d.ts +29 -0
- package/dest/archiver/l1/validate_trace.d.ts.map +1 -0
- package/dest/archiver/l1/validate_trace.js +150 -0
- package/dest/archiver/structs/data_retrieval.d.ts +1 -1
- package/dest/archiver/structs/inbox_message.d.ts +4 -4
- package/dest/archiver/structs/inbox_message.d.ts.map +1 -1
- package/dest/archiver/structs/inbox_message.js +6 -5
- package/dest/archiver/structs/published.d.ts +3 -2
- package/dest/archiver/structs/published.d.ts.map +1 -1
- package/dest/archiver/validation.d.ts +10 -4
- package/dest/archiver/validation.d.ts.map +1 -1
- package/dest/archiver/validation.js +29 -21
- package/dest/factory.d.ts +3 -5
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +3 -2
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/rpc/index.d.ts +2 -2
- package/dest/test/index.d.ts +1 -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 +10 -9
- package/dest/test/mock_l2_block_source.d.ts +15 -10
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +22 -9
- package/dest/test/mock_structs.d.ts +3 -2
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +9 -8
- package/package.json +18 -17
- package/src/archiver/archiver.ts +531 -345
- package/src/archiver/archiver_store.ts +24 -27
- package/src/archiver/archiver_store_test_suite.ts +151 -128
- package/src/archiver/config.ts +13 -7
- package/src/archiver/instrumentation.ts +16 -2
- package/src/archiver/kv_archiver_store/block_store.ts +18 -17
- package/src/archiver/kv_archiver_store/contract_class_store.ts +1 -1
- package/src/archiver/kv_archiver_store/contract_instance_store.ts +1 -1
- package/src/archiver/kv_archiver_store/kv_archiver_store.ts +23 -32
- package/src/archiver/kv_archiver_store/log_store.ts +4 -30
- package/src/archiver/kv_archiver_store/message_store.ts +21 -18
- package/src/archiver/l1/README.md +98 -0
- package/src/archiver/l1/bin/retrieve-calldata.ts +182 -0
- package/src/archiver/l1/calldata_retriever.ts +531 -0
- package/src/archiver/{data_retrieval.ts → l1/data_retrieval.ts} +196 -250
- package/src/archiver/l1/debug_tx.ts +99 -0
- package/src/archiver/l1/spire_proposer.ts +160 -0
- package/src/archiver/l1/trace_tx.ts +128 -0
- package/src/archiver/l1/types.ts +13 -0
- package/src/archiver/l1/validate_trace.ts +211 -0
- package/src/archiver/structs/inbox_message.ts +8 -8
- package/src/archiver/structs/published.ts +2 -1
- package/src/archiver/validation.ts +52 -27
- package/src/factory.ts +4 -5
- package/src/index.ts +1 -1
- 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/mock_archiver.ts +22 -16
- package/src/test/mock_l1_to_l2_message_source.ts +10 -9
- package/src/test/mock_l2_block_source.ts +32 -15
- package/src/test/mock_structs.ts +10 -9
- package/dest/archiver/data_retrieval.d.ts +0 -79
- package/dest/archiver/data_retrieval.d.ts.map +0 -1
- package/dest/archiver/data_retrieval.js +0 -362
|
@@ -1,362 +0,0 @@
|
|
|
1
|
-
import { BlobDeserializationError, SpongeBlob, getBlobFieldsInCheckpoint } from '@aztec/blob-lib';
|
|
2
|
-
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
3
|
-
import { Buffer16, Buffer32 } from '@aztec/foundation/buffer';
|
|
4
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
5
|
-
import { createLogger } from '@aztec/foundation/log';
|
|
6
|
-
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
7
|
-
import { Body, CommitteeAttestation, L2Block, L2BlockHeader, PublishedL2Block } from '@aztec/stdlib/block';
|
|
8
|
-
import { Proof } from '@aztec/stdlib/proofs';
|
|
9
|
-
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
10
|
-
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
11
|
-
import { GlobalVariables, StateReference } from '@aztec/stdlib/tx';
|
|
12
|
-
import { decodeFunctionData, getAbiItem, hexToBytes, multicall3Abi } from 'viem';
|
|
13
|
-
import { NoBlobBodiesFoundError } from './errors.js';
|
|
14
|
-
export async function retrievedBlockToPublishedL2Block(retrievedBlock) {
|
|
15
|
-
const { l2BlockNumber, archiveRoot, stateReference, header: checkpointHeader, blobFields, l1, chainId, version, attestations } = retrievedBlock;
|
|
16
|
-
const archive = new AppendOnlyTreeSnapshot(archiveRoot, l2BlockNumber + 1);
|
|
17
|
-
const globalVariables = GlobalVariables.from({
|
|
18
|
-
chainId,
|
|
19
|
-
version,
|
|
20
|
-
blockNumber: l2BlockNumber,
|
|
21
|
-
slotNumber: checkpointHeader.slotNumber,
|
|
22
|
-
timestamp: checkpointHeader.timestamp,
|
|
23
|
-
coinbase: checkpointHeader.coinbase,
|
|
24
|
-
feeRecipient: checkpointHeader.feeRecipient,
|
|
25
|
-
gasFees: checkpointHeader.gasFees
|
|
26
|
-
});
|
|
27
|
-
// TODO(#17027)
|
|
28
|
-
// This works when there's only one block in the checkpoint.
|
|
29
|
-
// If there's more than one block, we need to build the spongeBlob from the endSpongeBlob of the previous block.
|
|
30
|
-
const spongeBlob = await SpongeBlob.init(blobFields.length);
|
|
31
|
-
// Skip the first field which is the checkpoint prefix indicating the number of total blob fields in a checkpoint.
|
|
32
|
-
const blockBlobFields = blobFields.slice(1);
|
|
33
|
-
await spongeBlob.absorb(blockBlobFields);
|
|
34
|
-
const spongeBlobHash = await spongeBlob.squeeze();
|
|
35
|
-
const body = Body.fromBlobFields(blockBlobFields);
|
|
36
|
-
const header = L2BlockHeader.from({
|
|
37
|
-
lastArchive: new AppendOnlyTreeSnapshot(checkpointHeader.lastArchiveRoot, l2BlockNumber),
|
|
38
|
-
contentCommitment: checkpointHeader.contentCommitment,
|
|
39
|
-
state: stateReference,
|
|
40
|
-
globalVariables,
|
|
41
|
-
totalFees: body.txEffects.reduce((accum, txEffect)=>accum.add(txEffect.transactionFee), Fr.ZERO),
|
|
42
|
-
totalManaUsed: checkpointHeader.totalManaUsed,
|
|
43
|
-
spongeBlobHash
|
|
44
|
-
});
|
|
45
|
-
const block = new L2Block(archive, header, body);
|
|
46
|
-
return PublishedL2Block.fromFields({
|
|
47
|
-
block,
|
|
48
|
-
l1,
|
|
49
|
-
attestations
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Fetches new L2 blocks.
|
|
54
|
-
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
55
|
-
* @param rollupAddress - The address of the rollup contract.
|
|
56
|
-
* @param searchStartBlock - The block number to use for starting the search.
|
|
57
|
-
* @param searchEndBlock - The highest block number that we should search up to.
|
|
58
|
-
* @param expectedNextL2BlockNum - The next L2 block number that we expect to find.
|
|
59
|
-
* @returns An array of block; as well as the next eth block to search from.
|
|
60
|
-
*/ export async function retrieveBlocksFromRollup(rollup, publicClient, blobSinkClient, searchStartBlock, searchEndBlock, logger = createLogger('archiver')) {
|
|
61
|
-
const retrievedBlocks = [];
|
|
62
|
-
let rollupConstants;
|
|
63
|
-
do {
|
|
64
|
-
if (searchStartBlock > searchEndBlock) {
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
const l2BlockProposedLogs = (await rollup.getEvents.L2BlockProposed({}, {
|
|
68
|
-
fromBlock: searchStartBlock,
|
|
69
|
-
toBlock: searchEndBlock
|
|
70
|
-
})).filter((log)=>log.blockNumber >= searchStartBlock && log.blockNumber <= searchEndBlock);
|
|
71
|
-
if (l2BlockProposedLogs.length === 0) {
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
const lastLog = l2BlockProposedLogs[l2BlockProposedLogs.length - 1];
|
|
75
|
-
logger.debug(`Got ${l2BlockProposedLogs.length} L2 block processed logs for L2 blocks ${l2BlockProposedLogs[0].args.blockNumber}-${lastLog.args.blockNumber} between L1 blocks ${searchStartBlock}-${searchEndBlock}`);
|
|
76
|
-
if (rollupConstants === undefined) {
|
|
77
|
-
const [chainId, version, targetCommitteeSize] = await Promise.all([
|
|
78
|
-
publicClient.getChainId(),
|
|
79
|
-
rollup.read.getVersion(),
|
|
80
|
-
rollup.read.getTargetCommitteeSize()
|
|
81
|
-
]);
|
|
82
|
-
rollupConstants = {
|
|
83
|
-
chainId: new Fr(chainId),
|
|
84
|
-
version: new Fr(version),
|
|
85
|
-
targetCommitteeSize: Number(targetCommitteeSize)
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
const newBlocks = await processL2BlockProposedLogs(rollup, publicClient, blobSinkClient, l2BlockProposedLogs, rollupConstants, logger);
|
|
89
|
-
retrievedBlocks.push(...newBlocks);
|
|
90
|
-
searchStartBlock = lastLog.blockNumber + 1n;
|
|
91
|
-
}while (searchStartBlock <= searchEndBlock)
|
|
92
|
-
// The asyncpool from processL2BlockProposedLogs will not necessarily return the blocks in order, so we sort them before returning.
|
|
93
|
-
return retrievedBlocks.sort((a, b)=>Number(a.l1.blockNumber - b.l1.blockNumber));
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Processes newly received L2BlockProposed logs.
|
|
97
|
-
* @param rollup - The rollup contract
|
|
98
|
-
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
99
|
-
* @param logs - L2BlockProposed logs.
|
|
100
|
-
* @returns - An array blocks.
|
|
101
|
-
*/ async function processL2BlockProposedLogs(rollup, publicClient, blobSinkClient, logs, { chainId, version, targetCommitteeSize }, logger) {
|
|
102
|
-
const retrievedBlocks = [];
|
|
103
|
-
await asyncPool(10, logs, async (log)=>{
|
|
104
|
-
const l2BlockNumber = Number(log.args.blockNumber);
|
|
105
|
-
const archive = log.args.archive;
|
|
106
|
-
const archiveFromChain = await rollup.read.archiveAt([
|
|
107
|
-
BigInt(l2BlockNumber)
|
|
108
|
-
]);
|
|
109
|
-
const blobHashes = log.args.versionedBlobHashes.map((blobHash)=>Buffer.from(blobHash.slice(2), 'hex'));
|
|
110
|
-
// The value from the event and contract will match only if the block is in the chain.
|
|
111
|
-
if (archive === archiveFromChain) {
|
|
112
|
-
const block = await getBlockFromRollupTx(publicClient, blobSinkClient, log.transactionHash, blobHashes, l2BlockNumber, rollup.address, targetCommitteeSize, logger);
|
|
113
|
-
const l1 = {
|
|
114
|
-
blockNumber: log.blockNumber,
|
|
115
|
-
blockHash: log.blockHash,
|
|
116
|
-
timestamp: await getL1BlockTime(publicClient, log.blockNumber)
|
|
117
|
-
};
|
|
118
|
-
retrievedBlocks.push({
|
|
119
|
-
...block,
|
|
120
|
-
l1,
|
|
121
|
-
chainId,
|
|
122
|
-
version
|
|
123
|
-
});
|
|
124
|
-
logger.trace(`Retrieved L2 block ${l2BlockNumber} from L1 tx ${log.transactionHash}`, {
|
|
125
|
-
l1BlockNumber: log.blockNumber,
|
|
126
|
-
l2BlockNumber,
|
|
127
|
-
archive: archive.toString(),
|
|
128
|
-
attestations: block.attestations
|
|
129
|
-
});
|
|
130
|
-
} else {
|
|
131
|
-
logger.warn(`Ignoring L2 block ${l2BlockNumber} due to archive root mismatch`, {
|
|
132
|
-
actual: archive,
|
|
133
|
-
expected: archiveFromChain
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
return retrievedBlocks;
|
|
138
|
-
}
|
|
139
|
-
export async function getL1BlockTime(publicClient, blockNumber) {
|
|
140
|
-
const block = await publicClient.getBlock({
|
|
141
|
-
blockNumber,
|
|
142
|
-
includeTransactions: false
|
|
143
|
-
});
|
|
144
|
-
return block.timestamp;
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Extracts the first 'propose' method calldata from a multicall3 transaction's data.
|
|
148
|
-
* @param multicall3Data - The multicall3 transaction input data
|
|
149
|
-
* @param rollupAddress - The address of the rollup contract
|
|
150
|
-
* @returns The calldata for the first 'propose' method call to the rollup contract
|
|
151
|
-
*/ function extractRollupProposeCalldata(multicall3Data, rollupAddress) {
|
|
152
|
-
const { functionName: multicall3FunctionName, args: multicall3Args } = decodeFunctionData({
|
|
153
|
-
abi: multicall3Abi,
|
|
154
|
-
data: multicall3Data
|
|
155
|
-
});
|
|
156
|
-
if (multicall3FunctionName !== 'aggregate3') {
|
|
157
|
-
throw new Error(`Unexpected multicall3 method called ${multicall3FunctionName}`);
|
|
158
|
-
}
|
|
159
|
-
if (multicall3Args.length !== 1) {
|
|
160
|
-
throw new Error(`Unexpected number of arguments for multicall3`);
|
|
161
|
-
}
|
|
162
|
-
const [calls] = multicall3Args;
|
|
163
|
-
// Find all rollup calls
|
|
164
|
-
const rollupAddressLower = rollupAddress.toLowerCase();
|
|
165
|
-
for(let i = 0; i < calls.length; i++){
|
|
166
|
-
const addr = calls[i].target;
|
|
167
|
-
if (addr.toLowerCase() !== rollupAddressLower) {
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
const callData = calls[i].callData;
|
|
171
|
-
try {
|
|
172
|
-
const { functionName: rollupFunctionName } = decodeFunctionData({
|
|
173
|
-
abi: RollupAbi,
|
|
174
|
-
data: callData
|
|
175
|
-
});
|
|
176
|
-
if (rollupFunctionName === 'propose') {
|
|
177
|
-
return callData;
|
|
178
|
-
}
|
|
179
|
-
} catch {
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
throw new Error(`Rollup address not found in multicall3 args`);
|
|
184
|
-
}
|
|
185
|
-
/**
|
|
186
|
-
* Gets block from the calldata of an L1 transaction.
|
|
187
|
-
* Assumes that the block was published from an EOA.
|
|
188
|
-
* TODO: Add retries and error management.
|
|
189
|
-
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
190
|
-
* @param txHash - Hash of the tx that published it.
|
|
191
|
-
* @param l2BlockNumber - L2 block number.
|
|
192
|
-
* @returns L2 block from the calldata, deserialized
|
|
193
|
-
*/ async function getBlockFromRollupTx(publicClient, blobSinkClient, txHash, blobHashes, l2BlockNumber, rollupAddress, targetCommitteeSize, logger) {
|
|
194
|
-
const { input: forwarderData, blockHash } = await publicClient.getTransaction({
|
|
195
|
-
hash: txHash
|
|
196
|
-
});
|
|
197
|
-
const rollupData = extractRollupProposeCalldata(forwarderData, rollupAddress);
|
|
198
|
-
const { functionName: rollupFunctionName, args: rollupArgs } = decodeFunctionData({
|
|
199
|
-
abi: RollupAbi,
|
|
200
|
-
data: rollupData
|
|
201
|
-
});
|
|
202
|
-
if (rollupFunctionName !== 'propose') {
|
|
203
|
-
throw new Error(`Unexpected rollup method called ${rollupFunctionName}`);
|
|
204
|
-
}
|
|
205
|
-
const [decodedArgs, packedAttestations, _signers, _blobInput] = rollupArgs;
|
|
206
|
-
const attestations = CommitteeAttestation.fromPacked(packedAttestations, targetCommitteeSize);
|
|
207
|
-
logger.trace(`Recovered propose calldata from tx ${txHash}`, {
|
|
208
|
-
l2BlockNumber,
|
|
209
|
-
archive: decodedArgs.archive,
|
|
210
|
-
stateReference: decodedArgs.stateReference,
|
|
211
|
-
header: decodedArgs.header,
|
|
212
|
-
blobHashes,
|
|
213
|
-
attestations,
|
|
214
|
-
packedAttestations,
|
|
215
|
-
targetCommitteeSize
|
|
216
|
-
});
|
|
217
|
-
const header = CheckpointHeader.fromViem(decodedArgs.header);
|
|
218
|
-
const blobBodies = await blobSinkClient.getBlobSidecar(blockHash, blobHashes);
|
|
219
|
-
if (blobBodies.length === 0) {
|
|
220
|
-
throw new NoBlobBodiesFoundError(l2BlockNumber);
|
|
221
|
-
}
|
|
222
|
-
let blobFields;
|
|
223
|
-
try {
|
|
224
|
-
// Get the fields that were actually added in the checkpoint. And check the encoding of the fields.
|
|
225
|
-
blobFields = getBlobFieldsInCheckpoint(blobBodies.map((b)=>b.blob), true);
|
|
226
|
-
} catch (err) {
|
|
227
|
-
if (err instanceof BlobDeserializationError) {
|
|
228
|
-
logger.fatal(err.message);
|
|
229
|
-
} else {
|
|
230
|
-
logger.fatal('Unable to sync: failed to decode fetched blob, this blob was likely not created by us');
|
|
231
|
-
}
|
|
232
|
-
throw err;
|
|
233
|
-
}
|
|
234
|
-
const archiveRoot = new Fr(Buffer.from(hexToBytes(decodedArgs.archive)));
|
|
235
|
-
const stateReference = StateReference.fromViem(decodedArgs.stateReference);
|
|
236
|
-
return {
|
|
237
|
-
l2BlockNumber,
|
|
238
|
-
archiveRoot,
|
|
239
|
-
stateReference,
|
|
240
|
-
header,
|
|
241
|
-
blobFields,
|
|
242
|
-
attestations
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
/** Given an L1 to L2 message, retrieves its corresponding event from the Inbox within a specific block range. */ export async function retrieveL1ToL2Message(inbox, leaf, fromBlock, toBlock) {
|
|
246
|
-
const logs = await inbox.getEvents.MessageSent({
|
|
247
|
-
hash: leaf.toString()
|
|
248
|
-
}, {
|
|
249
|
-
fromBlock,
|
|
250
|
-
toBlock
|
|
251
|
-
});
|
|
252
|
-
const messages = mapLogsInboxMessage(logs);
|
|
253
|
-
return messages.length > 0 ? messages[0] : undefined;
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Fetch L1 to L2 messages.
|
|
257
|
-
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
258
|
-
* @param inboxAddress - The address of the inbox contract to fetch messages from.
|
|
259
|
-
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
260
|
-
* @param searchStartBlock - The block number to use for starting the search.
|
|
261
|
-
* @param searchEndBlock - The highest block number that we should search up to.
|
|
262
|
-
* @returns An array of InboxLeaf and next eth block to search from.
|
|
263
|
-
*/ export async function retrieveL1ToL2Messages(inbox, searchStartBlock, searchEndBlock) {
|
|
264
|
-
const retrievedL1ToL2Messages = [];
|
|
265
|
-
while(searchStartBlock <= searchEndBlock){
|
|
266
|
-
const messageSentLogs = (await inbox.getEvents.MessageSent({}, {
|
|
267
|
-
fromBlock: searchStartBlock,
|
|
268
|
-
toBlock: searchEndBlock
|
|
269
|
-
})).filter((log)=>log.blockNumber >= searchStartBlock && log.blockNumber <= searchEndBlock);
|
|
270
|
-
if (messageSentLogs.length === 0) {
|
|
271
|
-
break;
|
|
272
|
-
}
|
|
273
|
-
retrievedL1ToL2Messages.push(...mapLogsInboxMessage(messageSentLogs));
|
|
274
|
-
searchStartBlock = messageSentLogs.at(-1).blockNumber + 1n;
|
|
275
|
-
}
|
|
276
|
-
return retrievedL1ToL2Messages;
|
|
277
|
-
}
|
|
278
|
-
function mapLogsInboxMessage(logs) {
|
|
279
|
-
return logs.map((log)=>{
|
|
280
|
-
const { index, hash, l2BlockNumber, rollingHash } = log.args;
|
|
281
|
-
return {
|
|
282
|
-
index: index,
|
|
283
|
-
leaf: Fr.fromHexString(hash),
|
|
284
|
-
l1BlockNumber: log.blockNumber,
|
|
285
|
-
l1BlockHash: Buffer32.fromString(log.blockHash),
|
|
286
|
-
l2BlockNumber: Number(l2BlockNumber),
|
|
287
|
-
rollingHash: Buffer16.fromString(rollingHash)
|
|
288
|
-
};
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
/** Retrieves L2ProofVerified events from the rollup contract. */ export async function retrieveL2ProofVerifiedEvents(publicClient, rollupAddress, searchStartBlock, searchEndBlock) {
|
|
292
|
-
const logs = await publicClient.getLogs({
|
|
293
|
-
address: rollupAddress.toString(),
|
|
294
|
-
fromBlock: searchStartBlock,
|
|
295
|
-
toBlock: searchEndBlock ? searchEndBlock : undefined,
|
|
296
|
-
strict: true,
|
|
297
|
-
event: getAbiItem({
|
|
298
|
-
abi: RollupAbi,
|
|
299
|
-
name: 'L2ProofVerified'
|
|
300
|
-
})
|
|
301
|
-
});
|
|
302
|
-
return logs.map((log)=>({
|
|
303
|
-
l1BlockNumber: log.blockNumber,
|
|
304
|
-
l2BlockNumber: Number(log.args.blockNumber),
|
|
305
|
-
proverId: Fr.fromHexString(log.args.proverId),
|
|
306
|
-
txHash: log.transactionHash
|
|
307
|
-
}));
|
|
308
|
-
}
|
|
309
|
-
/** Retrieve submitted proofs from the rollup contract */ export async function retrieveL2ProofsFromRollup(publicClient, rollupAddress, searchStartBlock, searchEndBlock) {
|
|
310
|
-
const logs = await retrieveL2ProofVerifiedEvents(publicClient, rollupAddress, searchStartBlock, searchEndBlock);
|
|
311
|
-
const retrievedData = [];
|
|
312
|
-
const lastProcessedL1BlockNumber = logs.length > 0 ? logs.at(-1).l1BlockNumber : searchStartBlock - 1n;
|
|
313
|
-
for (const { txHash, proverId, l2BlockNumber } of logs){
|
|
314
|
-
const proofData = await getProofFromSubmitProofTx(publicClient, txHash, proverId);
|
|
315
|
-
retrievedData.push({
|
|
316
|
-
proof: proofData.proof,
|
|
317
|
-
proverId: proofData.proverId,
|
|
318
|
-
l2BlockNumber,
|
|
319
|
-
txHash
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
return {
|
|
323
|
-
retrievedData,
|
|
324
|
-
lastProcessedL1BlockNumber
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Gets block metadata (header and archive snapshot) from the calldata of an L1 transaction.
|
|
329
|
-
* Assumes that the block was published from an EOA.
|
|
330
|
-
* TODO: Add retries and error management.
|
|
331
|
-
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
332
|
-
* @param txHash - Hash of the tx that published it.
|
|
333
|
-
* @param l2BlockNum - L2 block number.
|
|
334
|
-
* @returns L2 block metadata (header and archive) from the calldata, deserialized
|
|
335
|
-
*/ export async function getProofFromSubmitProofTx(publicClient, txHash, expectedProverId) {
|
|
336
|
-
const { input: data } = await publicClient.getTransaction({
|
|
337
|
-
hash: txHash
|
|
338
|
-
});
|
|
339
|
-
const { functionName, args } = decodeFunctionData({
|
|
340
|
-
abi: RollupAbi,
|
|
341
|
-
data
|
|
342
|
-
});
|
|
343
|
-
let proverId;
|
|
344
|
-
let archiveRoot;
|
|
345
|
-
let proof;
|
|
346
|
-
if (functionName === 'submitEpochRootProof') {
|
|
347
|
-
const [decodedArgs] = args;
|
|
348
|
-
proverId = Fr.fromHexString(decodedArgs.args.proverId);
|
|
349
|
-
archiveRoot = Fr.fromHexString(decodedArgs.args.endArchive);
|
|
350
|
-
proof = Proof.fromBuffer(Buffer.from(hexToBytes(decodedArgs.proof)));
|
|
351
|
-
} else {
|
|
352
|
-
throw new Error(`Unexpected proof method called ${functionName}`);
|
|
353
|
-
}
|
|
354
|
-
if (!proverId.equals(expectedProverId)) {
|
|
355
|
-
throw new Error(`Prover ID mismatch: expected ${expectedProverId} but got ${proverId}`);
|
|
356
|
-
}
|
|
357
|
-
return {
|
|
358
|
-
proverId,
|
|
359
|
-
archiveRoot,
|
|
360
|
-
proof
|
|
361
|
-
};
|
|
362
|
-
}
|