@aztec/archiver 0.0.1-commit.fce3e4f → 0.0.1-commit.fffb133c
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 +156 -22
- package/dest/archiver.d.ts +135 -0
- package/dest/archiver.d.ts.map +1 -0
- package/dest/archiver.js +768 -0
- package/dest/config.d.ts +30 -0
- package/dest/config.d.ts.map +1 -0
- package/dest/{archiver/config.js → config.js} +21 -5
- package/dest/errors.d.ts +41 -0
- package/dest/errors.d.ts.map +1 -0
- package/dest/errors.js +62 -0
- package/dest/factory.d.ts +7 -7
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +90 -10
- package/dest/index.d.ts +10 -4
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +8 -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 +149 -0
- package/dest/l1/calldata_retriever.d.ts +112 -0
- package/dest/l1/calldata_retriever.d.ts.map +1 -0
- package/dest/l1/calldata_retriever.js +471 -0
- package/dest/l1/data_retrieval.d.ts +88 -0
- package/dest/l1/data_retrieval.d.ts.map +1 -0
- package/dest/{archiver → l1}/data_retrieval.js +76 -150
- 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 +157 -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_trace.d.ts +29 -0
- package/dest/l1/validate_trace.d.ts.map +1 -0
- package/dest/l1/validate_trace.js +150 -0
- package/dest/modules/data_source_base.d.ts +84 -0
- package/dest/modules/data_source_base.d.ts.map +1 -0
- package/dest/modules/data_source_base.js +260 -0
- package/dest/modules/data_store_updater.d.ts +73 -0
- package/dest/modules/data_store_updater.d.ts.map +1 -0
- package/dest/modules/data_store_updater.js +302 -0
- package/dest/modules/instrumentation.d.ts +37 -0
- package/dest/modules/instrumentation.d.ts.map +1 -0
- package/dest/{archiver → modules}/instrumentation.js +22 -59
- package/dest/modules/l1_synchronizer.d.ts +75 -0
- package/dest/modules/l1_synchronizer.d.ts.map +1 -0
- package/dest/modules/l1_synchronizer.js +1113 -0
- package/dest/modules/validation.d.ts +17 -0
- package/dest/modules/validation.d.ts.map +1 -0
- package/dest/{archiver → modules}/validation.js +7 -1
- package/dest/store/block_store.d.ts +192 -0
- package/dest/store/block_store.d.ts.map +1 -0
- package/dest/store/block_store.js +721 -0
- package/dest/store/contract_class_store.d.ts +18 -0
- package/dest/store/contract_class_store.d.ts.map +1 -0
- package/dest/{archiver/kv_archiver_store → store}/contract_class_store.js +2 -2
- 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 +1 -1
- package/dest/store/kv_archiver_store.d.ts +340 -0
- package/dest/store/kv_archiver_store.d.ts.map +1 -0
- package/dest/store/kv_archiver_store.js +447 -0
- package/dest/store/log_store.d.ts +54 -0
- package/dest/store/log_store.d.ts.map +1 -0
- package/dest/store/log_store.js +436 -0
- package/dest/store/message_store.d.ts +40 -0
- package/dest/store/message_store.d.ts.map +1 -0
- package/dest/{archiver/kv_archiver_store → store}/message_store.js +15 -14
- 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 +190 -0
- package/dest/test/fake_l1_state.d.ts.map +1 -0
- package/dest/test/fake_l1_state.js +383 -0
- package/dest/test/index.d.ts +2 -1
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -0
- 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 +18 -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 +21 -11
- package/dest/test/mock_l2_block_source.d.ts +34 -16
- package/dest/test/mock_l2_block_source.d.ts.map +1 -1
- package/dest/test/mock_l2_block_source.js +179 -59
- package/dest/test/mock_structs.d.ts +78 -3
- package/dest/test/mock_structs.d.ts.map +1 -1
- package/dest/test/mock_structs.js +141 -9
- package/package.json +19 -20
- package/src/archiver.ts +523 -0
- package/src/{archiver/config.ts → config.ts} +28 -12
- package/src/errors.ts +102 -0
- package/src/factory.ts +125 -10
- package/src/index.ts +10 -3
- package/src/interfaces.ts +9 -0
- package/src/l1/README.md +98 -0
- package/src/l1/bin/retrieve-calldata.ts +187 -0
- package/src/l1/calldata_retriever.ts +641 -0
- package/src/{archiver → l1}/data_retrieval.ts +142 -223
- package/src/l1/debug_tx.ts +99 -0
- package/src/l1/spire_proposer.ts +160 -0
- package/src/l1/trace_tx.ts +128 -0
- package/src/l1/types.ts +13 -0
- package/src/l1/validate_trace.ts +211 -0
- package/src/modules/data_source_base.ts +367 -0
- package/src/modules/data_store_updater.ts +423 -0
- package/src/{archiver → modules}/instrumentation.ts +26 -61
- package/src/modules/l1_synchronizer.ts +931 -0
- package/src/{archiver → modules}/validation.ts +11 -6
- package/src/store/block_store.ts +966 -0
- package/src/{archiver/kv_archiver_store → store}/contract_class_store.ts +2 -2
- package/src/{archiver/kv_archiver_store → store}/contract_instance_store.ts +2 -2
- package/src/store/kv_archiver_store.ts +639 -0
- package/src/store/log_store.ts +575 -0
- package/src/{archiver/kv_archiver_store → store}/message_store.ts +21 -18
- package/src/{archiver/structs → structs}/inbox_message.ts +8 -8
- package/src/{archiver/structs → structs}/published.ts +0 -1
- package/src/test/fake_l1_state.ts +599 -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 +1 -0
- package/src/test/mock_archiver.ts +22 -16
- package/src/test/mock_l1_to_l2_message_source.ts +18 -11
- package/src/test/mock_l2_block_source.ts +195 -69
- package/src/test/mock_structs.ts +256 -10
- 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/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/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_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/kv_archiver_store/block_store.ts +0 -481
- 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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
1
2
|
import {
|
|
2
3
|
BlobDeserializationError,
|
|
3
4
|
type CheckpointBlobData,
|
|
@@ -5,45 +6,37 @@ import {
|
|
|
5
6
|
decodeCheckpointBlobDataFromBlobs,
|
|
6
7
|
encodeBlockBlobData,
|
|
7
8
|
} from '@aztec/blob-lib';
|
|
8
|
-
import type { BlobSinkClientInterface } from '@aztec/blob-sink/client';
|
|
9
9
|
import type {
|
|
10
|
+
CheckpointProposedLog,
|
|
10
11
|
EpochProofPublicInputArgs,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from '@aztec/ethereum';
|
|
12
|
+
InboxContract,
|
|
13
|
+
MessageSentLog,
|
|
14
|
+
RollupContract,
|
|
15
|
+
} from '@aztec/ethereum/contracts';
|
|
16
|
+
import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types';
|
|
16
17
|
import { asyncPool } from '@aztec/foundation/async-pool';
|
|
17
|
-
import {
|
|
18
|
-
import
|
|
19
|
-
import
|
|
20
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
18
|
+
import { CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
|
|
19
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
20
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
21
21
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
22
|
-
import {
|
|
23
|
-
import { Body, CommitteeAttestation,
|
|
24
|
-
import { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
22
|
+
import { RollupAbi } from '@aztec/l1-artifacts';
|
|
23
|
+
import { Body, CommitteeAttestation, L2Block } from '@aztec/stdlib/block';
|
|
24
|
+
import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
25
25
|
import { Proof } from '@aztec/stdlib/proofs';
|
|
26
26
|
import { CheckpointHeader } from '@aztec/stdlib/rollup';
|
|
27
27
|
import { AppendOnlyTreeSnapshot } from '@aztec/stdlib/trees';
|
|
28
28
|
import { BlockHeader, GlobalVariables, PartialStateReference, StateReference } from '@aztec/stdlib/tx';
|
|
29
29
|
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
multicall3Abi,
|
|
38
|
-
} from 'viem';
|
|
39
|
-
|
|
40
|
-
import { NoBlobBodiesFoundError } from './errors.js';
|
|
41
|
-
import type { DataRetrieval } from './structs/data_retrieval.js';
|
|
42
|
-
import type { InboxMessage } from './structs/inbox_message.js';
|
|
43
|
-
import type { L1PublishedData } from './structs/published.js';
|
|
30
|
+
import { type Hex, decodeFunctionData, getAbiItem, hexToBytes } from 'viem';
|
|
31
|
+
|
|
32
|
+
import { NoBlobBodiesFoundError } from '../errors.js';
|
|
33
|
+
import type { ArchiverInstrumentation } from '../modules/instrumentation.js';
|
|
34
|
+
import type { DataRetrieval } from '../structs/data_retrieval.js';
|
|
35
|
+
import type { InboxMessage } from '../structs/inbox_message.js';
|
|
36
|
+
import { CalldataRetriever } from './calldata_retriever.js';
|
|
44
37
|
|
|
45
38
|
export type RetrievedCheckpoint = {
|
|
46
|
-
checkpointNumber:
|
|
39
|
+
checkpointNumber: CheckpointNumber;
|
|
47
40
|
archiveRoot: Fr;
|
|
48
41
|
header: CheckpointHeader;
|
|
49
42
|
checkpointBlobData: CheckpointBlobData;
|
|
@@ -71,12 +64,12 @@ export async function retrievedToPublishedCheckpoint({
|
|
|
71
64
|
.slice(1)
|
|
72
65
|
.concat([archiveRoot]);
|
|
73
66
|
|
|
74
|
-
//
|
|
75
|
-
//
|
|
67
|
+
// An error will be thrown from `decodeCheckpointBlobDataFromBlobs` if it can't read a field for the
|
|
68
|
+
// `l1ToL2MessageRoot` of the first block. So below we can safely assume it exists:
|
|
76
69
|
const l1toL2MessageTreeRoot = blocksBlobData[0].l1ToL2MessageRoot!;
|
|
77
70
|
|
|
78
71
|
const spongeBlob = SpongeBlob.init();
|
|
79
|
-
const l2Blocks:
|
|
72
|
+
const l2Blocks: L2Block[] = [];
|
|
80
73
|
for (let i = 0; i < blocksBlobData.length; i++) {
|
|
81
74
|
const blockBlobData = blocksBlobData[i];
|
|
82
75
|
const { blockEndMarker, blockEndStateField, lastArchiveRoot, noteHashRoot, nullifierRoot, publicDataRoot } =
|
|
@@ -126,7 +119,7 @@ export async function retrievedToPublishedCheckpoint({
|
|
|
126
119
|
|
|
127
120
|
const newArchive = new AppendOnlyTreeSnapshot(newArchiveRoots[i], l2BlockNumber + 1);
|
|
128
121
|
|
|
129
|
-
l2Blocks.push(new
|
|
122
|
+
l2Blocks.push(new L2Block(newArchive, header, body, checkpointNumber, IndexWithinCheckpoint(i)));
|
|
130
123
|
}
|
|
131
124
|
|
|
132
125
|
const lastBlock = l2Blocks.at(-1)!;
|
|
@@ -142,20 +135,33 @@ export async function retrievedToPublishedCheckpoint({
|
|
|
142
135
|
|
|
143
136
|
/**
|
|
144
137
|
* Fetches new checkpoints.
|
|
138
|
+
* @param rollup - The rollup contract wrapper.
|
|
145
139
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
146
|
-
* @param
|
|
140
|
+
* @param debugClient - The viem debug client to use for trace/debug RPC methods (optional).
|
|
141
|
+
* @param blobClient - The blob client client for fetching blob data.
|
|
147
142
|
* @param searchStartBlock - The block number to use for starting the search.
|
|
148
143
|
* @param searchEndBlock - The highest block number that we should search up to.
|
|
149
|
-
* @param
|
|
150
|
-
* @
|
|
144
|
+
* @param contractAddresses - The contract addresses (governanceProposerAddress, slashFactoryAddress, slashingProposerAddress).
|
|
145
|
+
* @param instrumentation - The archiver instrumentation instance.
|
|
146
|
+
* @param logger - The logger instance.
|
|
147
|
+
* @param isHistoricalSync - Whether this is a historical sync.
|
|
148
|
+
* @returns An array of retrieved checkpoints.
|
|
151
149
|
*/
|
|
152
150
|
export async function retrieveCheckpointsFromRollup(
|
|
153
|
-
rollup:
|
|
151
|
+
rollup: RollupContract,
|
|
154
152
|
publicClient: ViemPublicClient,
|
|
155
|
-
|
|
153
|
+
debugClient: ViemPublicDebugClient,
|
|
154
|
+
blobClient: BlobClientInterface,
|
|
156
155
|
searchStartBlock: bigint,
|
|
157
156
|
searchEndBlock: bigint,
|
|
157
|
+
contractAddresses: {
|
|
158
|
+
governanceProposerAddress: EthAddress;
|
|
159
|
+
slashFactoryAddress?: EthAddress;
|
|
160
|
+
slashingProposerAddress: EthAddress;
|
|
161
|
+
},
|
|
162
|
+
instrumentation: ArchiverInstrumentation,
|
|
158
163
|
logger: Logger = createLogger('archiver'),
|
|
164
|
+
isHistoricalSync: boolean = false,
|
|
159
165
|
): Promise<RetrievedCheckpoint[]> {
|
|
160
166
|
const retrievedCheckpoints: RetrievedCheckpoint[] = [];
|
|
161
167
|
|
|
@@ -165,15 +171,7 @@ export async function retrieveCheckpointsFromRollup(
|
|
|
165
171
|
if (searchStartBlock > searchEndBlock) {
|
|
166
172
|
break;
|
|
167
173
|
}
|
|
168
|
-
const checkpointProposedLogs = (
|
|
169
|
-
await rollup.getEvents.CheckpointProposed(
|
|
170
|
-
{},
|
|
171
|
-
{
|
|
172
|
-
fromBlock: searchStartBlock,
|
|
173
|
-
toBlock: searchEndBlock,
|
|
174
|
-
},
|
|
175
|
-
)
|
|
176
|
-
).filter(log => log.blockNumber! >= searchStartBlock && log.blockNumber! <= searchEndBlock);
|
|
174
|
+
const checkpointProposedLogs = await rollup.getCheckpointProposedEvents(searchStartBlock, searchEndBlock);
|
|
177
175
|
|
|
178
176
|
if (checkpointProposedLogs.length === 0) {
|
|
179
177
|
break;
|
|
@@ -181,32 +179,36 @@ export async function retrieveCheckpointsFromRollup(
|
|
|
181
179
|
|
|
182
180
|
const lastLog = checkpointProposedLogs.at(-1)!;
|
|
183
181
|
logger.debug(
|
|
184
|
-
`Got ${checkpointProposedLogs.length} processed logs for checkpoints
|
|
182
|
+
`Got ${checkpointProposedLogs.length} processed logs for checkpoints ${checkpointProposedLogs[0].args.checkpointNumber}-${lastLog.args.checkpointNumber} between L1 blocks ${searchStartBlock}-${searchEndBlock}`,
|
|
185
183
|
);
|
|
186
184
|
|
|
187
185
|
if (rollupConstants === undefined) {
|
|
188
186
|
const [chainId, version, targetCommitteeSize] = await Promise.all([
|
|
189
187
|
publicClient.getChainId(),
|
|
190
|
-
rollup.
|
|
191
|
-
rollup.
|
|
188
|
+
rollup.getVersion(),
|
|
189
|
+
rollup.getTargetCommitteeSize(),
|
|
192
190
|
]);
|
|
193
191
|
rollupConstants = {
|
|
194
192
|
chainId: new Fr(chainId),
|
|
195
193
|
version: new Fr(version),
|
|
196
|
-
targetCommitteeSize
|
|
194
|
+
targetCommitteeSize,
|
|
197
195
|
};
|
|
198
196
|
}
|
|
199
197
|
|
|
200
198
|
const newCheckpoints = await processCheckpointProposedLogs(
|
|
201
199
|
rollup,
|
|
202
200
|
publicClient,
|
|
203
|
-
|
|
201
|
+
debugClient,
|
|
202
|
+
blobClient,
|
|
204
203
|
checkpointProposedLogs,
|
|
205
204
|
rollupConstants,
|
|
205
|
+
contractAddresses,
|
|
206
|
+
instrumentation,
|
|
206
207
|
logger,
|
|
208
|
+
isHistoricalSync,
|
|
207
209
|
);
|
|
208
210
|
retrievedCheckpoints.push(...newCheckpoints);
|
|
209
|
-
searchStartBlock = lastLog.
|
|
211
|
+
searchStartBlock = lastLog.l1BlockNumber + 1n;
|
|
210
212
|
} while (searchStartBlock <= searchEndBlock);
|
|
211
213
|
|
|
212
214
|
// The asyncPool from processCheckpointProposedLogs will not necessarily return the checkpoints in order, so we sort them before returning.
|
|
@@ -215,56 +217,90 @@ export async function retrieveCheckpointsFromRollup(
|
|
|
215
217
|
|
|
216
218
|
/**
|
|
217
219
|
* Processes newly received CheckpointProposed logs.
|
|
218
|
-
* @param rollup - The rollup contract
|
|
220
|
+
* @param rollup - The rollup contract wrapper.
|
|
219
221
|
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
222
|
+
* @param debugClient - The viem debug client to use for trace/debug RPC methods (optional).
|
|
223
|
+
* @param blobClient - The blob client client for fetching blob data.
|
|
220
224
|
* @param logs - CheckpointProposed logs.
|
|
221
|
-
* @
|
|
225
|
+
* @param rollupConstants - The rollup constants (chainId, version, targetCommitteeSize).
|
|
226
|
+
* @param contractAddresses - The contract addresses (governanceProposerAddress, slashFactoryAddress, slashingProposerAddress).
|
|
227
|
+
* @param instrumentation - The archiver instrumentation instance.
|
|
228
|
+
* @param logger - The logger instance.
|
|
229
|
+
* @param isHistoricalSync - Whether this is a historical sync.
|
|
230
|
+
* @returns An array of retrieved checkpoints.
|
|
222
231
|
*/
|
|
223
232
|
async function processCheckpointProposedLogs(
|
|
224
|
-
rollup:
|
|
233
|
+
rollup: RollupContract,
|
|
225
234
|
publicClient: ViemPublicClient,
|
|
226
|
-
|
|
227
|
-
|
|
235
|
+
debugClient: ViemPublicDebugClient,
|
|
236
|
+
blobClient: BlobClientInterface,
|
|
237
|
+
logs: CheckpointProposedLog[],
|
|
228
238
|
{ chainId, version, targetCommitteeSize }: { chainId: Fr; version: Fr; targetCommitteeSize: number },
|
|
239
|
+
contractAddresses: {
|
|
240
|
+
governanceProposerAddress: EthAddress;
|
|
241
|
+
slashFactoryAddress?: EthAddress;
|
|
242
|
+
slashingProposerAddress: EthAddress;
|
|
243
|
+
},
|
|
244
|
+
instrumentation: ArchiverInstrumentation,
|
|
229
245
|
logger: Logger,
|
|
246
|
+
isHistoricalSync: boolean,
|
|
230
247
|
): Promise<RetrievedCheckpoint[]> {
|
|
231
248
|
const retrievedCheckpoints: RetrievedCheckpoint[] = [];
|
|
249
|
+
const calldataRetriever = new CalldataRetriever(
|
|
250
|
+
publicClient,
|
|
251
|
+
debugClient,
|
|
252
|
+
targetCommitteeSize,
|
|
253
|
+
instrumentation,
|
|
254
|
+
logger,
|
|
255
|
+
{ ...contractAddresses, rollupAddress: EthAddress.fromString(rollup.address) },
|
|
256
|
+
);
|
|
257
|
+
|
|
232
258
|
await asyncPool(10, logs, async log => {
|
|
233
|
-
const checkpointNumber =
|
|
234
|
-
const archive = log.args.archive
|
|
235
|
-
const archiveFromChain = await rollup.
|
|
236
|
-
const blobHashes = log.args.versionedBlobHashes
|
|
259
|
+
const checkpointNumber = log.args.checkpointNumber;
|
|
260
|
+
const archive = log.args.archive;
|
|
261
|
+
const archiveFromChain = await rollup.archiveAt(checkpointNumber);
|
|
262
|
+
const blobHashes = log.args.versionedBlobHashes;
|
|
237
263
|
|
|
238
264
|
// The value from the event and contract will match only if the checkpoint is in the chain.
|
|
239
|
-
if (archive
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
log.
|
|
265
|
+
if (archive.equals(archiveFromChain)) {
|
|
266
|
+
// Build expected hashes object (fields may be undefined for backwards compatibility with older events)
|
|
267
|
+
const expectedHashes = {
|
|
268
|
+
attestationsHash: log.args.attestationsHash?.toString(),
|
|
269
|
+
payloadDigest: log.args.payloadDigest?.toString(),
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const checkpoint = await calldataRetriever.getCheckpointFromRollupTx(
|
|
273
|
+
log.l1TransactionHash,
|
|
274
|
+
blobHashes,
|
|
275
|
+
checkpointNumber,
|
|
276
|
+
expectedHashes,
|
|
277
|
+
);
|
|
278
|
+
const checkpointBlobData = await getCheckpointBlobDataFromBlobs(
|
|
279
|
+
blobClient,
|
|
280
|
+
checkpoint.blockHash,
|
|
244
281
|
blobHashes,
|
|
245
282
|
checkpointNumber,
|
|
246
|
-
rollup.address,
|
|
247
|
-
targetCommitteeSize,
|
|
248
283
|
logger,
|
|
284
|
+
isHistoricalSync,
|
|
249
285
|
);
|
|
250
286
|
|
|
251
|
-
const l1
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
287
|
+
const l1 = new L1PublishedData(
|
|
288
|
+
log.l1BlockNumber,
|
|
289
|
+
await getL1BlockTime(publicClient, log.l1BlockNumber),
|
|
290
|
+
log.l1BlockHash.toString(),
|
|
291
|
+
);
|
|
256
292
|
|
|
257
|
-
retrievedCheckpoints.push({ ...checkpoint, l1, chainId, version });
|
|
258
|
-
logger.trace(`Retrieved checkpoint ${checkpointNumber} from L1 tx ${log.
|
|
259
|
-
l1BlockNumber: log.
|
|
293
|
+
retrievedCheckpoints.push({ ...checkpoint, checkpointBlobData, l1, chainId, version });
|
|
294
|
+
logger.trace(`Retrieved checkpoint ${checkpointNumber} from L1 tx ${log.l1TransactionHash}`, {
|
|
295
|
+
l1BlockNumber: log.l1BlockNumber,
|
|
260
296
|
checkpointNumber,
|
|
261
297
|
archive: archive.toString(),
|
|
262
298
|
attestations: checkpoint.attestations,
|
|
263
299
|
});
|
|
264
300
|
} else {
|
|
265
301
|
logger.warn(`Ignoring checkpoint ${checkpointNumber} due to archive root mismatch`, {
|
|
266
|
-
actual: archive,
|
|
267
|
-
expected: archiveFromChain,
|
|
302
|
+
actual: archive.toString(),
|
|
303
|
+
expected: archiveFromChain.toString(),
|
|
268
304
|
});
|
|
269
305
|
}
|
|
270
306
|
});
|
|
@@ -277,118 +313,15 @@ export async function getL1BlockTime(publicClient: ViemPublicClient, blockNumber
|
|
|
277
313
|
return block.timestamp;
|
|
278
314
|
}
|
|
279
315
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
*/
|
|
286
|
-
function extractRollupProposeCalldata(multicall3Data: Hex, rollupAddress: Hex): Hex {
|
|
287
|
-
const { functionName: multicall3FunctionName, args: multicall3Args } = decodeFunctionData({
|
|
288
|
-
abi: multicall3Abi,
|
|
289
|
-
data: multicall3Data,
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
if (multicall3FunctionName !== 'aggregate3') {
|
|
293
|
-
throw new Error(`Unexpected multicall3 method called ${multicall3FunctionName}`);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (multicall3Args.length !== 1) {
|
|
297
|
-
throw new Error(`Unexpected number of arguments for multicall3`);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
const [calls] = multicall3Args;
|
|
301
|
-
|
|
302
|
-
// Find all rollup calls
|
|
303
|
-
const rollupAddressLower = rollupAddress.toLowerCase();
|
|
304
|
-
|
|
305
|
-
for (let i = 0; i < calls.length; i++) {
|
|
306
|
-
const addr = calls[i].target;
|
|
307
|
-
if (addr.toLowerCase() !== rollupAddressLower) {
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
const callData = calls[i].callData;
|
|
311
|
-
|
|
312
|
-
try {
|
|
313
|
-
const { functionName: rollupFunctionName } = decodeFunctionData({
|
|
314
|
-
abi: RollupAbi,
|
|
315
|
-
data: callData,
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
if (rollupFunctionName === 'propose') {
|
|
319
|
-
return callData;
|
|
320
|
-
}
|
|
321
|
-
} catch {
|
|
322
|
-
// Skip invalid function data
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
throw new Error(`Rollup address not found in multicall3 args`);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Gets checkpoint from the calldata of an L1 transaction.
|
|
332
|
-
* Assumes that the checkpoint was published from an EOA.
|
|
333
|
-
* TODO: Add retries and error management.
|
|
334
|
-
* @param publicClient - The viem public client to use for transaction retrieval.
|
|
335
|
-
* @param txHash - Hash of the tx that published it.
|
|
336
|
-
* @param checkpointNumber - Checkpoint number.
|
|
337
|
-
* @returns Checkpoint from the calldata, deserialized
|
|
338
|
-
*/
|
|
339
|
-
async function getCheckpointFromRollupTx(
|
|
340
|
-
publicClient: ViemPublicClient,
|
|
341
|
-
blobSinkClient: BlobSinkClientInterface,
|
|
342
|
-
txHash: `0x${string}`,
|
|
343
|
-
blobHashes: Buffer[], // TODO(md): buffer32?
|
|
344
|
-
checkpointNumber: number,
|
|
345
|
-
rollupAddress: Hex,
|
|
346
|
-
targetCommitteeSize: number,
|
|
316
|
+
export async function getCheckpointBlobDataFromBlobs(
|
|
317
|
+
blobClient: BlobClientInterface,
|
|
318
|
+
blockHash: string,
|
|
319
|
+
blobHashes: Buffer<ArrayBufferLike>[],
|
|
320
|
+
checkpointNumber: CheckpointNumber,
|
|
347
321
|
logger: Logger,
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
const rollupData = extractRollupProposeCalldata(forwarderData, rollupAddress);
|
|
353
|
-
const { functionName: rollupFunctionName, args: rollupArgs } = decodeFunctionData({
|
|
354
|
-
abi: RollupAbi,
|
|
355
|
-
data: rollupData,
|
|
356
|
-
});
|
|
357
|
-
|
|
358
|
-
if (rollupFunctionName !== 'propose') {
|
|
359
|
-
throw new Error(`Unexpected rollup method called ${rollupFunctionName}`);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
const [decodedArgs, packedAttestations, _signers, _blobInput] = rollupArgs! as readonly [
|
|
363
|
-
{
|
|
364
|
-
archive: Hex;
|
|
365
|
-
oracleInput: {
|
|
366
|
-
feeAssetPriceModifier: bigint;
|
|
367
|
-
};
|
|
368
|
-
header: ViemHeader;
|
|
369
|
-
txHashes: readonly Hex[];
|
|
370
|
-
},
|
|
371
|
-
ViemCommitteeAttestations,
|
|
372
|
-
Hex[],
|
|
373
|
-
ViemSignature,
|
|
374
|
-
Hex,
|
|
375
|
-
];
|
|
376
|
-
|
|
377
|
-
const attestations = CommitteeAttestation.fromPacked(packedAttestations, targetCommitteeSize);
|
|
378
|
-
|
|
379
|
-
logger.trace(`Recovered propose calldata from tx ${txHash}`, {
|
|
380
|
-
checkpointNumber,
|
|
381
|
-
archive: decodedArgs.archive,
|
|
382
|
-
header: decodedArgs.header,
|
|
383
|
-
l1BlockHash: blockHash,
|
|
384
|
-
blobHashes,
|
|
385
|
-
attestations,
|
|
386
|
-
packedAttestations,
|
|
387
|
-
targetCommitteeSize,
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
const header = CheckpointHeader.fromViem(decodedArgs.header);
|
|
391
|
-
const blobBodies = await blobSinkClient.getBlobSidecar(blockHash, blobHashes);
|
|
322
|
+
isHistoricalSync: boolean,
|
|
323
|
+
): Promise<CheckpointBlobData> {
|
|
324
|
+
const blobBodies = await blobClient.getBlobSidecar(blockHash, blobHashes, { isHistoricalSync });
|
|
392
325
|
if (blobBodies.length === 0) {
|
|
393
326
|
throw new NoBlobBodiesFoundError(checkpointNumber);
|
|
394
327
|
}
|
|
@@ -396,35 +329,28 @@ async function getCheckpointFromRollupTx(
|
|
|
396
329
|
let checkpointBlobData: CheckpointBlobData;
|
|
397
330
|
try {
|
|
398
331
|
// Attempt to decode the checkpoint blob data.
|
|
399
|
-
checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies
|
|
332
|
+
checkpointBlobData = decodeCheckpointBlobDataFromBlobs(blobBodies);
|
|
400
333
|
} catch (err: any) {
|
|
401
334
|
if (err instanceof BlobDeserializationError) {
|
|
402
335
|
logger.fatal(err.message);
|
|
403
336
|
} else {
|
|
404
337
|
logger.fatal('Unable to sync: failed to decode fetched blob, this blob was likely not created by us');
|
|
405
338
|
}
|
|
339
|
+
// Throwing an error since this is most likely caused by a bug.
|
|
406
340
|
throw err;
|
|
407
341
|
}
|
|
408
342
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
return {
|
|
412
|
-
checkpointNumber,
|
|
413
|
-
archiveRoot,
|
|
414
|
-
header,
|
|
415
|
-
checkpointBlobData,
|
|
416
|
-
attestations,
|
|
417
|
-
};
|
|
343
|
+
return checkpointBlobData;
|
|
418
344
|
}
|
|
419
345
|
|
|
420
346
|
/** Given an L1 to L2 message, retrieves its corresponding event from the Inbox within a specific block range. */
|
|
421
347
|
export async function retrieveL1ToL2Message(
|
|
422
|
-
inbox:
|
|
348
|
+
inbox: InboxContract,
|
|
423
349
|
leaf: Fr,
|
|
424
350
|
fromBlock: bigint,
|
|
425
351
|
toBlock: bigint,
|
|
426
352
|
): Promise<InboxMessage | undefined> {
|
|
427
|
-
const logs = await inbox.
|
|
353
|
+
const logs = await inbox.getMessageSentEventByHash(leaf.toString(), fromBlock, toBlock);
|
|
428
354
|
|
|
429
355
|
const messages = mapLogsInboxMessage(logs);
|
|
430
356
|
return messages.length > 0 ? messages[0] : undefined;
|
|
@@ -432,47 +358,40 @@ export async function retrieveL1ToL2Message(
|
|
|
432
358
|
|
|
433
359
|
/**
|
|
434
360
|
* Fetch L1 to L2 messages.
|
|
435
|
-
* @param
|
|
436
|
-
* @param inboxAddress - The address of the inbox contract to fetch messages from.
|
|
437
|
-
* @param blockUntilSynced - If true, blocks until the archiver has fully synced.
|
|
361
|
+
* @param inbox - The inbox contract wrapper.
|
|
438
362
|
* @param searchStartBlock - The block number to use for starting the search.
|
|
439
363
|
* @param searchEndBlock - The highest block number that we should search up to.
|
|
440
364
|
* @returns An array of InboxLeaf and next eth block to search from.
|
|
441
365
|
*/
|
|
442
366
|
export async function retrieveL1ToL2Messages(
|
|
443
|
-
inbox:
|
|
367
|
+
inbox: InboxContract,
|
|
444
368
|
searchStartBlock: bigint,
|
|
445
369
|
searchEndBlock: bigint,
|
|
446
370
|
): Promise<InboxMessage[]> {
|
|
447
371
|
const retrievedL1ToL2Messages: InboxMessage[] = [];
|
|
448
372
|
while (searchStartBlock <= searchEndBlock) {
|
|
449
|
-
const messageSentLogs = (
|
|
450
|
-
await inbox.getEvents.MessageSent({}, { fromBlock: searchStartBlock, toBlock: searchEndBlock })
|
|
451
|
-
).filter(log => log.blockNumber! >= searchStartBlock && log.blockNumber! <= searchEndBlock);
|
|
373
|
+
const messageSentLogs = await inbox.getMessageSentEvents(searchStartBlock, searchEndBlock);
|
|
452
374
|
|
|
453
375
|
if (messageSentLogs.length === 0) {
|
|
454
376
|
break;
|
|
455
377
|
}
|
|
456
378
|
|
|
457
379
|
retrievedL1ToL2Messages.push(...mapLogsInboxMessage(messageSentLogs));
|
|
458
|
-
searchStartBlock = messageSentLogs.at(-1)!.
|
|
380
|
+
searchStartBlock = messageSentLogs.at(-1)!.l1BlockNumber + 1n;
|
|
459
381
|
}
|
|
460
382
|
|
|
461
383
|
return retrievedL1ToL2Messages;
|
|
462
384
|
}
|
|
463
385
|
|
|
464
|
-
function mapLogsInboxMessage(logs:
|
|
465
|
-
return logs.map(log => {
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
rollingHash: Buffer16.fromString(rollingHash!),
|
|
474
|
-
};
|
|
475
|
-
});
|
|
386
|
+
function mapLogsInboxMessage(logs: MessageSentLog[]): InboxMessage[] {
|
|
387
|
+
return logs.map(log => ({
|
|
388
|
+
index: log.args.index,
|
|
389
|
+
leaf: log.args.leaf,
|
|
390
|
+
l1BlockNumber: log.l1BlockNumber,
|
|
391
|
+
l1BlockHash: log.l1BlockHash,
|
|
392
|
+
checkpointNumber: log.args.checkpointNumber,
|
|
393
|
+
rollingHash: log.args.rollingHash,
|
|
394
|
+
}));
|
|
476
395
|
}
|
|
477
396
|
|
|
478
397
|
/** Retrieves L2ProofVerified events from the rollup contract. */
|
|
@@ -481,7 +400,7 @@ export async function retrieveL2ProofVerifiedEvents(
|
|
|
481
400
|
rollupAddress: EthAddress,
|
|
482
401
|
searchStartBlock: bigint,
|
|
483
402
|
searchEndBlock?: bigint,
|
|
484
|
-
): Promise<{ l1BlockNumber: bigint; checkpointNumber:
|
|
403
|
+
): Promise<{ l1BlockNumber: bigint; checkpointNumber: CheckpointNumber; proverId: Fr; txHash: Hex }[]> {
|
|
485
404
|
const logs = await publicClient.getLogs({
|
|
486
405
|
address: rollupAddress.toString(),
|
|
487
406
|
fromBlock: searchStartBlock,
|
|
@@ -492,7 +411,7 @@ export async function retrieveL2ProofVerifiedEvents(
|
|
|
492
411
|
|
|
493
412
|
return logs.map(log => ({
|
|
494
413
|
l1BlockNumber: log.blockNumber,
|
|
495
|
-
checkpointNumber:
|
|
414
|
+
checkpointNumber: CheckpointNumber.fromBigInt(log.args.checkpointNumber),
|
|
496
415
|
proverId: Fr.fromHexString(log.args.proverId),
|
|
497
416
|
txHash: log.transactionHash,
|
|
498
417
|
}));
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { DebugCallTrace, ViemPublicDebugClient } from '@aztec/ethereum/types';
|
|
2
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
|
+
import type { Logger } from '@aztec/foundation/log';
|
|
4
|
+
import { type ZodFor, schemas } from '@aztec/foundation/schemas';
|
|
5
|
+
import { withHexPrefix } from '@aztec/foundation/string';
|
|
6
|
+
|
|
7
|
+
import type { Hex } from 'viem';
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
|
|
10
|
+
import type { CallInfo } from './types.js';
|
|
11
|
+
|
|
12
|
+
/** Zod schema for validating call trace from debug_traceTransaction */
|
|
13
|
+
export const callTraceSchema: ZodFor<DebugCallTrace> = z.lazy(() =>
|
|
14
|
+
z.object({
|
|
15
|
+
from: schemas.HexStringWith0x,
|
|
16
|
+
to: schemas.HexStringWith0x.optional(),
|
|
17
|
+
type: z.string(),
|
|
18
|
+
input: schemas.HexStringWith0x.optional(),
|
|
19
|
+
output: schemas.HexStringWith0x.optional(),
|
|
20
|
+
gas: schemas.HexStringWith0x.optional(),
|
|
21
|
+
gasUsed: schemas.HexStringWith0x.optional(),
|
|
22
|
+
value: schemas.HexStringWith0x.optional(),
|
|
23
|
+
error: z.string().optional(),
|
|
24
|
+
calls: z.array(callTraceSchema).optional(),
|
|
25
|
+
}),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Traces a transaction and extracts all CALL operations to a specific contract and function selector.
|
|
30
|
+
*
|
|
31
|
+
* @param client - The Viem public client
|
|
32
|
+
* @param txHash - The transaction hash to trace
|
|
33
|
+
* @param targetAddress - The contract address to filter for
|
|
34
|
+
* @param functionSelector - The 4-byte function selector to filter for (with or without 0x prefix)
|
|
35
|
+
* @returns Array of CallInfo objects containing from, gasUsed, input, and value for matching calls
|
|
36
|
+
*/
|
|
37
|
+
export async function getSuccessfulCallsFromDebug(
|
|
38
|
+
client: ViemPublicDebugClient,
|
|
39
|
+
txHash: Hex,
|
|
40
|
+
targetAddress: EthAddress,
|
|
41
|
+
functionSelector: string,
|
|
42
|
+
logger?: Logger,
|
|
43
|
+
): Promise<CallInfo[]> {
|
|
44
|
+
// Normalize inputs for comparison
|
|
45
|
+
const normalizedTarget = targetAddress.toString().toLowerCase();
|
|
46
|
+
const normalizedSelector = withHexPrefix(functionSelector.toLowerCase());
|
|
47
|
+
|
|
48
|
+
// Call debug_traceTransaction with callTracer
|
|
49
|
+
// Using 'any' here because debug_traceTransaction is not in viem's standard RPC types
|
|
50
|
+
const rawTrace = await client.request({
|
|
51
|
+
method: 'debug_traceTransaction',
|
|
52
|
+
params: [txHash, { tracer: 'callTracer' }],
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
if (rawTrace === null || rawTrace === undefined) {
|
|
56
|
+
throw new Error(`Failed to retrieve debug_traceTransaction for ${txHash}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
logger?.trace(`Retrieved debug_traceTransaction for ${txHash}`, { trace: rawTrace });
|
|
60
|
+
|
|
61
|
+
// Validate the response with zod
|
|
62
|
+
const trace = callTraceSchema.parse(rawTrace);
|
|
63
|
+
|
|
64
|
+
const results: CallInfo[] = [];
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Recursively traverse the call trace tree
|
|
68
|
+
*/
|
|
69
|
+
function traverseCalls(callTrace: DebugCallTrace) {
|
|
70
|
+
// Skip calls that have errors, and all its descendants
|
|
71
|
+
if (callTrace.error) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Check if this is a CALL (not DELEGATECALL or STATICCALL) to the target address with matching selector
|
|
76
|
+
if (
|
|
77
|
+
callTrace.type.toUpperCase() === 'CALL' &&
|
|
78
|
+
callTrace.to?.toLowerCase() === normalizedTarget &&
|
|
79
|
+
callTrace.input?.toLowerCase().startsWith(normalizedSelector)
|
|
80
|
+
) {
|
|
81
|
+
results.push({
|
|
82
|
+
from: EthAddress.fromString(callTrace.from),
|
|
83
|
+
gasUsed: callTrace.gasUsed === undefined ? undefined : BigInt(callTrace.gasUsed),
|
|
84
|
+
input: callTrace.input,
|
|
85
|
+
value: callTrace.value ? BigInt(callTrace.value) : 0n,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Recursively process nested calls
|
|
90
|
+
for (const nestedCall of callTrace.calls ?? []) {
|
|
91
|
+
traverseCalls(nestedCall);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Start traversal from the root trace
|
|
96
|
+
traverseCalls(trace);
|
|
97
|
+
|
|
98
|
+
return results;
|
|
99
|
+
}
|