Skip to content

Commit 155fe72

Browse files
authored
fix: script robustness (#97)
* fix: support RPC URLs with API keys * updates * fix: invalid check
1 parent ede2306 commit 155fe72

18 files changed

+146
-47
lines changed

.env.template

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
INFURA_API_KEY=
2+
ALCHEMY_API_KEY=

.github/workflows/fetch-data.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Fetch Chain Data
33
on:
44
workflow_dispatch:
55
schedule:
6-
- cron: '0 */4 * * *'
6+
- cron: '0 */6 * * *'
77

88
jobs:
99
fetch-data:

script/.env.example

-1
This file was deleted.

script/checks/opcodes.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,17 @@ async function checkOpcode(opcode: Opcode, client: PublicClient): Promise<boolea
3131
return true; // Call succeeded so opcode is supported.
3232
} catch (e: unknown) {
3333
const err = e as CallError;
34+
const details = err.details.toLowerCase();
3435
// TODO These might be specific to the node implementation, can this be more robust?
35-
if (opcode === 0xfe && err.details === 'invalid opcode: INVALID') return true; // Designated invalid opcode.
36-
if (err.details.includes('stack underflow')) return true; // Implies opcode is supported.
37-
if (err.details.includes('not defined')) return false;
38-
if (err.details.includes('not supported')) return false;
39-
if (err.details.includes('invalid opcode')) return false;
36+
if (opcode === 0xfe && details.includes('invalid opcode: invalid')) return true; // Designated invalid opcode.
37+
if (details.includes('stack underflow')) return true; // Implies opcode is supported.
38+
if (details.includes('not defined')) return false;
39+
if (details.includes('not supported')) return false;
40+
if (details.includes('invalid opcode')) return false;
4041

42+
console.log(`\n======== Opcode ${opcode} ========`);
43+
console.log('err.details:', err.details);
44+
console.log(JSON.stringify(err, null, 2));
4145
throw new Error(`Unexpected error: ${err}`);
4246
}
4347
}

script/data/chain/1.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@
4444
"https://rpc.mevblocker.io/noreverts",
4545
"https://rpc.mevblocker.io/fullprivacy",
4646
"https://eth.drpc.org",
47-
"wss://eth.drpc.org"
47+
"wss://eth.drpc.org",
48+
"https://api.securerpc.com/v1",
49+
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
4850
],
4951
"slip44": 60
5052
},

script/data/chain/10.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
"https://optimism.gateway.tenderly.co",
3232
"wss://optimism.gateway.tenderly.co",
3333
"https://optimism.drpc.org",
34-
"wss://optimism.drpc.org"
34+
"wss://optimism.drpc.org",
35+
"https://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}",
36+
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
3537
]
3638
},
3739
"opcodes": [

script/data/chain/137.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
"https://polygon.gateway.tenderly.co",
3131
"wss://polygon.gateway.tenderly.co",
3232
"https://polygon.drpc.org",
33-
"wss://polygon.drpc.org"
33+
"wss://polygon.drpc.org",
34+
"https://polygon-mainnet.infura.io/v3/${INFURA_API_KEY}",
35+
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
3436
],
3537
"slip44": 966
3638
},

script/data/chain/42161.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
"https://arbitrum-mainnet.infura.io/v3/${INFURA_API_KEY}",
2828
"https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
2929
"https://arb1.arbitrum.io/rpc",
30-
"https://arbitrum-one.publicnode.com",
31-
"wss://arbitrum-one.publicnode.com"
30+
"https://arbitrum-one-rpc.publicnode.com",
31+
"wss://arbitrum-one-rpc.publicnode.com"
3232
]
3333
},
3434
"opcodes": [

script/data/chain/43114.json

+10-7
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@
1818
"rpc": [
1919
"https://api.avax.network/ext/bc/C/rpc",
2020
"https://avalanche-c-chain-rpc.publicnode.com",
21-
"wss://avalanche-c-chain-rpc.publicnode.com"
21+
"wss://avalanche-c-chain-rpc.publicnode.com",
22+
"https://rpc.ankr.com/avalanche",
23+
"https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc",
24+
"https://avalanche-mainnet.infura.io/v3/${INFURA_API_KEY}"
2225
],
2326
"slip44": 9005
2427
},
@@ -75,8 +78,8 @@
7578
{ "number": "0x46", "name": "CHAINID", "supported": true },
7679
{ "number": "0x47", "name": "SELFBALANCE", "supported": true },
7780
{ "number": "0x48", "name": "BASEFEE", "supported": true },
78-
{ "number": "0x49", "name": "BLOBHASH", "supported": false },
79-
{ "number": "0x4a", "name": "BLOBBASEFEE", "supported": false },
81+
{ "number": "0x49", "name": "BLOBHASH", "supported": true },
82+
{ "number": "0x4a", "name": "BLOBBASEFEE", "supported": true },
8083
{ "number": "0x50", "name": "POP", "supported": true },
8184
{ "number": "0x51", "name": "MLOAD", "supported": true },
8285
{ "number": "0x52", "name": "MSTORE", "supported": true },
@@ -89,9 +92,9 @@
8992
{ "number": "0x59", "name": "MSIZE", "supported": true },
9093
{ "number": "0x5a", "name": "GAS", "supported": true },
9194
{ "number": "0x5b", "name": "JUMPDEST", "supported": true },
92-
{ "number": "0x5c", "name": "TLOAD", "supported": false },
93-
{ "number": "0x5d", "name": "TSTORE", "supported": false },
94-
{ "number": "0x5e", "name": "MCOPY", "supported": false },
95+
{ "number": "0x5c", "name": "TLOAD", "supported": true },
96+
{ "number": "0x5d", "name": "TSTORE", "supported": true },
97+
{ "number": "0x5e", "name": "MCOPY", "supported": true },
9598
{ "number": "0x5f", "name": "PUSH0", "supported": true },
9699
{ "number": "0x60", "name": "PUSH1", "supported": true },
97100
{ "number": "0x61", "name": "PUSH2", "supported": true },
@@ -266,7 +269,7 @@
266269
{
267270
"name": "point evaluation",
268271
"address": "0x000000000000000000000000000000000000000a",
269-
"implemented": false
272+
"implemented": true
270273
},
271274
{
272275
"name": "secp256r1",

script/data/chain/534352.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
"https://rpc.ankr.com/scroll",
2020
"https://scroll-mainnet.chainstacklabs.com",
2121
"https://scroll-rpc.publicnode.com",
22-
"wss://scroll-rpc.publicnode.com"
22+
"wss://scroll-rpc.publicnode.com",
23+
"https://scroll-mainnet.infura.io/v3/${INFURA_API_KEY}",
24+
"https://scroll-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
2325
],
2426
"status": "active"
2527
},

script/data/chain/59144.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
"https://linea-mainnet.infura.io/v3/${INFURA_API_KEY}",
3636
"wss://linea-mainnet.infura.io/ws/v3/${INFURA_API_KEY}",
3737
"https://linea-rpc.publicnode.com",
38-
"wss://linea-rpc.publicnode.com"
38+
"wss://linea-rpc.publicnode.com",
39+
"https://linea-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
3940
],
4041
"status": "active",
4142
"title": "Linea Mainnet"

script/data/chain/8453.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
"https://base.gateway.tenderly.co",
3232
"wss://base.gateway.tenderly.co",
3333
"https://base-rpc.publicnode.com",
34-
"wss://base-rpc.publicnode.com"
34+
"wss://base-rpc.publicnode.com",
35+
"https://base-mainnet.infura.io/v3/${INFURA_API_KEY}",
36+
"https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
3537
],
3638
"status": "active"
3739
},

script/data/feature/metadata.json

+23-9
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@
4444
"https://rpc.mevblocker.io/noreverts",
4545
"https://rpc.mevblocker.io/fullprivacy",
4646
"https://eth.drpc.org",
47-
"wss://eth.drpc.org"
47+
"wss://eth.drpc.org",
48+
"https://api.securerpc.com/v1",
49+
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
4850
],
4951
"slip44": 60
5052
},
@@ -80,7 +82,9 @@
8082
"https://optimism.gateway.tenderly.co",
8183
"wss://optimism.gateway.tenderly.co",
8284
"https://optimism.drpc.org",
83-
"wss://optimism.drpc.org"
85+
"wss://optimism.drpc.org",
86+
"https://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}",
87+
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
8488
]
8589
},
8690
"137": {
@@ -114,7 +118,9 @@
114118
"https://polygon.gateway.tenderly.co",
115119
"wss://polygon.gateway.tenderly.co",
116120
"https://polygon.drpc.org",
117-
"wss://polygon.drpc.org"
121+
"wss://polygon.drpc.org",
122+
"https://polygon-mainnet.infura.io/v3/${INFURA_API_KEY}",
123+
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
118124
],
119125
"slip44": 966
120126
},
@@ -150,7 +156,9 @@
150156
"https://base.gateway.tenderly.co",
151157
"wss://base.gateway.tenderly.co",
152158
"https://base-rpc.publicnode.com",
153-
"wss://base-rpc.publicnode.com"
159+
"wss://base-rpc.publicnode.com",
160+
"https://base-mainnet.infura.io/v3/${INFURA_API_KEY}",
161+
"https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
154162
],
155163
"status": "active"
156164
},
@@ -198,8 +206,8 @@
198206
"https://arbitrum-mainnet.infura.io/v3/${INFURA_API_KEY}",
199207
"https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
200208
"https://arb1.arbitrum.io/rpc",
201-
"https://arbitrum-one.publicnode.com",
202-
"wss://arbitrum-one.publicnode.com"
209+
"https://arbitrum-one-rpc.publicnode.com",
210+
"wss://arbitrum-one-rpc.publicnode.com"
203211
]
204212
},
205213
"43114": {
@@ -221,7 +229,10 @@
221229
"rpc": [
222230
"https://api.avax.network/ext/bc/C/rpc",
223231
"https://avalanche-c-chain-rpc.publicnode.com",
224-
"wss://avalanche-c-chain-rpc.publicnode.com"
232+
"wss://avalanche-c-chain-rpc.publicnode.com",
233+
"https://rpc.ankr.com/avalanche",
234+
"https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc",
235+
"https://avalanche-mainnet.infura.io/v3/${INFURA_API_KEY}"
225236
],
226237
"slip44": 9005
227238
},
@@ -261,7 +272,8 @@
261272
"https://linea-mainnet.infura.io/v3/${INFURA_API_KEY}",
262273
"wss://linea-mainnet.infura.io/ws/v3/${INFURA_API_KEY}",
263274
"https://linea-rpc.publicnode.com",
264-
"wss://linea-rpc.publicnode.com"
275+
"wss://linea-rpc.publicnode.com",
276+
"https://linea-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
265277
],
266278
"status": "active",
267279
"title": "Linea Mainnet"
@@ -286,7 +298,9 @@
286298
"https://rpc.ankr.com/scroll",
287299
"https://scroll-mainnet.chainstacklabs.com",
288300
"https://scroll-rpc.publicnode.com",
289-
"wss://scroll-rpc.publicnode.com"
301+
"wss://scroll-rpc.publicnode.com",
302+
"https://scroll-mainnet.infura.io/v3/${INFURA_API_KEY}",
303+
"https://scroll-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
290304
],
291305
"status": "active"
292306
}

script/data/feature/opcodes.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -958,8 +958,8 @@
958958
{ "number": "0x46", "name": "CHAINID", "supported": true },
959959
{ "number": "0x47", "name": "SELFBALANCE", "supported": true },
960960
{ "number": "0x48", "name": "BASEFEE", "supported": true },
961-
{ "number": "0x49", "name": "BLOBHASH", "supported": false },
962-
{ "number": "0x4a", "name": "BLOBBASEFEE", "supported": false },
961+
{ "number": "0x49", "name": "BLOBHASH", "supported": true },
962+
{ "number": "0x4a", "name": "BLOBBASEFEE", "supported": true },
963963
{ "number": "0x50", "name": "POP", "supported": true },
964964
{ "number": "0x51", "name": "MLOAD", "supported": true },
965965
{ "number": "0x52", "name": "MSTORE", "supported": true },
@@ -972,9 +972,9 @@
972972
{ "number": "0x59", "name": "MSIZE", "supported": true },
973973
{ "number": "0x5a", "name": "GAS", "supported": true },
974974
{ "number": "0x5b", "name": "JUMPDEST", "supported": true },
975-
{ "number": "0x5c", "name": "TLOAD", "supported": false },
976-
{ "number": "0x5d", "name": "TSTORE", "supported": false },
977-
{ "number": "0x5e", "name": "MCOPY", "supported": false },
975+
{ "number": "0x5c", "name": "TLOAD", "supported": true },
976+
{ "number": "0x5d", "name": "TSTORE", "supported": true },
977+
{ "number": "0x5e", "name": "MCOPY", "supported": true },
978978
{ "number": "0x5f", "name": "PUSH0", "supported": true },
979979
{ "number": "0x60", "name": "PUSH1", "supported": true },
980980
{ "number": "0x61", "name": "PUSH2", "supported": true },

script/data/feature/precompiles.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@
390390
{
391391
"name": "point evaluation",
392392
"address": "0x000000000000000000000000000000000000000a",
393-
"implemented": false
393+
"implemented": true
394394
},
395395
{
396396
"name": "secp256r1",

script/index.ts

+9
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ async function getMetadata(chainId: number): Promise<Metadata> {
8686
const data = await response.json();
8787
const metadata = data.find((chain: Metadata) => chain.chainId === chainId);
8888
if (!metadata) throw new Error(`Chain with ID ${chainId} not found.`);
89+
90+
// Add in the custom RPC URLs from input.json.
91+
const chains = await Bun.file('script/input.json').json();
92+
const chain = chains.find((chain: Metadata) => chain.chainId === chainId);
93+
if (chain?.rpcUrls) metadata.rpc.push(...chain.rpcUrls);
94+
metadata.rpc = [...new Set(metadata.rpc)]; // Deduplicate RPC URLs.
95+
8996
return metadata;
9097
}
9198

@@ -128,6 +135,8 @@ function selectRpcUrls(rpcUrls: string[]): string[] {
128135
'matic-mainnet-full-rpc.bwarelabs.com', // "This endpoint is deprecated".
129136
'publicnode.com', // Transaction creation failed.
130137
'cloudflare', // Requested resource not found.
138+
'api.avax.network', // Unrecognized token '<', 429's easily.
139+
'rpc.linea.build', // All error messages are identical so can't distinguish opcode support.
131140
];
132141
const filteredRpcUrls = rpcUrls.filter(
133142
(url) => !domainsToSkip.some((domain) => url.includes(domain)),

script/input.json

+62-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,64 @@
11
[
2-
{ "chainId": 1 },
3-
{ "chainId": 10 },
4-
{ "chainId": 137 },
5-
{ "chainId": 8453 },
6-
{ "chainId": 34443 },
7-
{ "chainId": 42161 },
8-
{ "chainId": 43114 },
9-
{ "chainId": 59144 },
10-
{ "chainId": 534352 }
2+
{
3+
"chainId": 1,
4+
"rpcUrls": [
5+
"https://mainnet.infura.io/v3/${INFURA_API_KEY}",
6+
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
7+
]
8+
},
9+
{
10+
"chainId": 10,
11+
"rpcUrls": [
12+
"https://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}",
13+
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
14+
]
15+
},
16+
{
17+
"chainId": 137,
18+
"rpcUrls": [
19+
"https://polygon-mainnet.infura.io/v3/${INFURA_API_KEY}",
20+
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
21+
]
22+
},
23+
{
24+
"chainId": 8453,
25+
"rpcUrls": [
26+
"https://base-mainnet.infura.io/v3/${INFURA_API_KEY}",
27+
"https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
28+
]
29+
},
30+
{
31+
"chainId": 34443,
32+
"rpcUrls": []
33+
},
34+
{
35+
"chainId": 42161,
36+
"rpcUrls": [
37+
"https://arbitrum-mainnet.infura.io/v3/${INFURA_API_KEY}",
38+
"https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
39+
]
40+
},
41+
{
42+
"chainId": 43114,
43+
"rpcUrls": [
44+
"https://avalanche-c-chain-rpc.publicnode.com",
45+
"https://rpc.ankr.com/avalanche",
46+
"https://ava-mainnet.public.blastapi.io/ext/bc/C/rpc",
47+
"https://avalanche-mainnet.infura.io/v3/${INFURA_API_KEY}"
48+
]
49+
},
50+
{
51+
"chainId": 59144,
52+
"rpcUrls": [
53+
"https://linea-mainnet.infura.io/v3/${INFURA_API_KEY}",
54+
"https://linea-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
55+
]
56+
},
57+
{
58+
"chainId": 534352,
59+
"rpcUrls": [
60+
"https://scroll-mainnet.infura.io/v3/${INFURA_API_KEY}",
61+
"https://scroll-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
62+
]
63+
}
1164
]

script/main.sh

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
#!/bin/bash
22
set -euo pipefail
33

4+
# Load API keys from the repo root.
5+
repoRoot=$(git rev-parse --show-toplevel)
6+
# shellcheck disable=SC1091
7+
source "$repoRoot"/.env
8+
49
# Function to handle final preparation steps.
510
final_preparation() {
611
local exitStatus=$?
@@ -19,7 +24,6 @@ final_preparation() {
1924
# Set up a trap to run final preparation steps on script exit.
2025
trap final_preparation EXIT
2126

22-
2327
if [ $# -eq 0 ]; then
2428
# No input provided, read from `input.json`.
2529
chainIds=$(jq -r '.[].chainId' script/input.json)

0 commit comments

Comments
 (0)