Skip to content

Commit 382bba3

Browse files
committed
chore: test log ranges script
1 parent 03ee6de commit 382bba3

File tree

1 file changed

+307
-0
lines changed

1 file changed

+307
-0
lines changed

scripts/test-log-ranges.ts

Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
import { mkdir, writeFile } from "node:fs/promises";
2+
import path from "node:path";
3+
import { setTimeout } from "node:timers/promises";
4+
import {
5+
type Abi,
6+
type Address,
7+
BaseError,
8+
type ContractEventName,
9+
createPublicClient,
10+
erc20Abi,
11+
http,
12+
parseAbi,
13+
} from "viem";
14+
import {
15+
getRpcProviderUrl,
16+
type RpcProvider,
17+
SUPPORTED_RPC_PROVIDERS,
18+
} from "../src/dev/index.js";
19+
import {
20+
type GearboxChain,
21+
getChain,
22+
type NetworkType,
23+
SUPPORTED_NETWORKS,
24+
} from "../src/sdk/index.js";
25+
26+
const ErrorsByProvider = new Map<RpcProvider, Set<string>>();
27+
28+
const BLOCK_RANGES = [
29+
0n,
30+
10_000_000n,
31+
5_000_000n,
32+
1_000_000n,
33+
500_000n,
34+
300_000n,
35+
200_000n,
36+
100_000n,
37+
50_000n,
38+
10_000n,
39+
5_000n,
40+
1_000n,
41+
];
42+
43+
interface Scenario<abi extends Abi | readonly unknown[] = Abi> {
44+
id: string;
45+
name: string;
46+
abi: abi;
47+
eventName: ContractEventName<abi>;
48+
address: Address | ((chain: GearboxChain) => Address);
49+
}
50+
51+
function addError(provider: RpcProvider, error: BaseError): void {
52+
const errors = ErrorsByProvider.get(provider) ?? new Set<string>();
53+
errors.add(error.name);
54+
ErrorsByProvider.set(provider, errors);
55+
}
56+
57+
async function testProviderNetworkRange(
58+
network: NetworkType,
59+
provider: RpcProvider,
60+
blockRange: bigint,
61+
scenario: Scenario,
62+
): Promise<boolean> {
63+
const chain = getChain(network);
64+
const address =
65+
typeof scenario.address === "function"
66+
? scenario.address(chain)
67+
: scenario.address;
68+
const rpcUrl = getRpcProviderUrl(
69+
provider,
70+
network,
71+
process.env[`${provider}_KEY`.toUpperCase()] ?? "",
72+
);
73+
if (!rpcUrl) {
74+
return false;
75+
}
76+
77+
try {
78+
const client = createPublicClient({
79+
transport: http(rpcUrl, { timeout: 120_000 }),
80+
});
81+
82+
// Get latest block number
83+
const { number: finalizedBlock } = await client.getBlock({
84+
blockTag: "finalized",
85+
});
86+
87+
// Get logs for Transfer event from block 0 to latest block
88+
await client.getContractEvents({
89+
address,
90+
abi: scenario.abi,
91+
eventName: scenario.eventName,
92+
fromBlock: blockRange === 0n ? 0n : finalizedBlock - blockRange,
93+
toBlock: finalizedBlock,
94+
});
95+
96+
await writeFile(
97+
`tmp/${scenario.id}/${provider}-${network}-${blockRange}-ok.txt`.toLowerCase(),
98+
"OK",
99+
"utf-8",
100+
);
101+
return true;
102+
} catch (error) {
103+
let code = "";
104+
if (error instanceof BaseError) {
105+
code = `${error.name}\n\n`;
106+
addError(provider, error);
107+
}
108+
await writeFile(
109+
`tmp/${scenario.id}/${provider}-${network}-${blockRange}-error.txt`.toLowerCase(),
110+
`${code}${error}`,
111+
"utf-8",
112+
);
113+
return false;
114+
}
115+
}
116+
117+
async function testProviderNetwork(
118+
network: NetworkType,
119+
provider: RpcProvider,
120+
scenario: Scenario,
121+
): Promise<bigint | undefined> {
122+
for (const blockRange of BLOCK_RANGES) {
123+
const success = await testProviderNetworkRange(
124+
network,
125+
provider,
126+
blockRange,
127+
scenario,
128+
);
129+
if (success) {
130+
return blockRange;
131+
}
132+
await setTimeout(1000);
133+
}
134+
return undefined;
135+
}
136+
137+
async function testNetwork(
138+
network: NetworkType,
139+
scenario: Scenario,
140+
): Promise<Record<RpcProvider, bigint | undefined>> {
141+
console.log(`\n=== Testing ${network}`);
142+
const results = await Promise.all(
143+
SUPPORTED_RPC_PROVIDERS.map(provider =>
144+
testProviderNetwork(network, provider, scenario),
145+
),
146+
);
147+
return results.reduce(
148+
(acc, result, index) => {
149+
acc[SUPPORTED_RPC_PROVIDERS[index]] = result;
150+
return acc;
151+
},
152+
{} as Record<RpcProvider, bigint | undefined>,
153+
);
154+
}
155+
156+
function formatBlockRange(range: bigint | undefined): string {
157+
if (range === undefined) {
158+
return "✗";
159+
}
160+
if (range === 0n) {
161+
return "∞";
162+
}
163+
if (range >= 1_000_000n) {
164+
return `${range / 1_000_000n}M`;
165+
}
166+
if (range >= 1_000n) {
167+
return `${range / 1_000n}K`;
168+
}
169+
return range.toString();
170+
}
171+
172+
function printResultsTable(
173+
results: Map<NetworkType, Record<RpcProvider, bigint | undefined>>,
174+
): void {
175+
const networks = Array.from(results.keys());
176+
const providers = SUPPORTED_RPC_PROVIDERS;
177+
178+
// Calculate column widths
179+
const networkColWidth = Math.max(
180+
"Network".length,
181+
...networks.map(n => n.length),
182+
);
183+
const providerColWidths = providers.map(provider =>
184+
Math.max(
185+
provider.length,
186+
...networks.map(network => {
187+
const value = results.get(network)?.[provider];
188+
return formatBlockRange(value).length;
189+
}),
190+
),
191+
);
192+
193+
// Print header
194+
const headerRow =
195+
"│ " +
196+
"Network".padEnd(networkColWidth) +
197+
" │ " +
198+
providers
199+
.map((provider, i) => provider.padEnd(providerColWidths[i]))
200+
.join(" │ ") +
201+
" │";
202+
const separatorRow =
203+
"├" +
204+
"─".repeat(networkColWidth + 2) +
205+
"┼" +
206+
providerColWidths.map(w => "─".repeat(w + 2)).join("┼") +
207+
"┤";
208+
const topBorder =
209+
"┌" +
210+
"─".repeat(networkColWidth + 2) +
211+
"┬" +
212+
providerColWidths.map(w => "─".repeat(w + 2)).join("┬") +
213+
"┐";
214+
const bottomBorder =
215+
"└" +
216+
"─".repeat(networkColWidth + 2) +
217+
"┴" +
218+
providerColWidths.map(w => "─".repeat(w + 2)).join("┴") +
219+
"┘";
220+
221+
console.log("\n" + topBorder);
222+
console.log(headerRow);
223+
console.log(separatorRow);
224+
225+
// Print data rows
226+
for (const network of networks) {
227+
const networkResults = results.get(network);
228+
if (!networkResults) continue;
229+
const row =
230+
"│ " +
231+
network.padEnd(networkColWidth) +
232+
" │ " +
233+
providers
234+
.map((provider, i) => {
235+
const value = networkResults[provider];
236+
return formatBlockRange(value).padEnd(providerColWidths[i]);
237+
})
238+
.join(" │ ") +
239+
" │";
240+
console.log(row);
241+
}
242+
243+
console.log(bottomBorder);
244+
}
245+
246+
async function testScenario(scenario: Scenario): Promise<void> {
247+
console.log(`\nStarting scenario ${scenario.name}...\n`);
248+
await mkdir(path.join("tmp", scenario.id), { recursive: true });
249+
250+
const results = new Map<
251+
NetworkType,
252+
Record<RpcProvider, bigint | undefined>
253+
>();
254+
255+
for (const network of SUPPORTED_NETWORKS) {
256+
results.set(network, await testNetwork(network, scenario));
257+
}
258+
console.log(`\n=== Results for ${scenario.name}`);
259+
printResultsTable(results);
260+
console.log(`\n`);
261+
}
262+
263+
function printErrorsTable(): void {
264+
console.info(`\n\n=== Errors by provider ===`);
265+
for (const p of SUPPORTED_RPC_PROVIDERS) {
266+
const errors = ErrorsByProvider.get(p) ?? new Set<string>();
267+
console.log(`${p}: ${Array.from(errors).join(", ")}`);
268+
}
269+
}
270+
271+
async function main(): Promise<void> {
272+
const scenarios: Scenario[] = [
273+
{
274+
id: "rare",
275+
name: "Rare event",
276+
address: "0x77777777144339Bdc3aCceE992D8d4D31734CB2e",
277+
abi: parseAbi([
278+
"event OwnershipTransferred(address indexed previousOwner, address indexed newOwner)",
279+
]),
280+
eventName: "OwnershipTransferred",
281+
},
282+
{
283+
id: "impossible",
284+
name: "Impossible event",
285+
address: "0x77777777144339Bdc3aCceE992D8d4D31734CB2e",
286+
abi: parseAbi(["event SomeEvent()"]),
287+
eventName: "SomeEvent",
288+
},
289+
{
290+
id: "frequent",
291+
name: "Frequent event",
292+
address: chain => chain.wellKnownToken.address,
293+
abi: erc20Abi,
294+
eventName: "Transfer",
295+
},
296+
];
297+
for (const scenario of scenarios) {
298+
await testScenario(scenario);
299+
}
300+
printErrorsTable();
301+
console.log("\n✓ All tests completed!");
302+
}
303+
304+
main().catch(error => {
305+
console.error("Fatal error:", error);
306+
process.exit(1);
307+
});

0 commit comments

Comments
 (0)