Skip to content

Commit 9e341b2

Browse files
S0.7-norm: normalize 28 chain templates to baseline schema + fix cache var bug
Convert all 28 research-format chain templates (extracted by S0-inv subagents) to the baseline 7-key schema used by config_loader.sh, so they can be loaded by the S1 file-based loader without further per-chain hand-edits. baseline 8 chains untouched. Eliminates the parallel-entry-trap where two schemas (research format "chain/public_endpoints/single_method/mixed_methods/rpc_protocol/notes" vs baseline "chain_type/methods/param_formats/params/rpc_methods/rpc_url/ system_addresses") would otherwise drift through wave S2-A..H. CHANGES: 1. tools/normalize_chain_templates.py — NEW one-shot normalizer * Field mapping: rpc_url ← constant "LOCAL_RPC_URL" (matches baseline 8) rpc_methods.single ← single_method (string) rpc_methods.mixed ← ",".join(mixed_methods) methods ← {} (framework alias dict; new chains fill in S3) params ← baseline 6-key template + target_address real value chain_type / param_formats / system_addresses → kept as-is * Idempotent: re-running on already-normalized file = no-op (detected via baseline-required-keys subset check). * Preserves research-only fields under _meta.original_* for traceability. * Marks `_meta.adapter_required = true` for chains where rpc_protocol ∈ {rest, mixed} or single_method contains "/". 20/28 chains match — this is real business boundary (REST chains need an adapter layer in S3), not schema laziness. 2. config/chains/<chain>.json — 28 files rewritten acala, algorand, aptos, arbitrum, astar, avalanche-c, avalanche-x, bch, bitcoin, cardano, celestia, cosmos-hub, dogecoin, hedera, injective, kusama, linea, litecoin, moonbeam, near, optimism, osmosis, polkadot, sei, tezos, ton, tron, zksync-era (baseline 8: solana/ethereum/bsc/base/scroll/polygon/starknet/sui untouched — verified by L1 byte-equal regression below) 3. config/config_loader.sh — fix bash cache var name bug, 3 spots bash variable names disallow '-', so cache var "CACHED_CHAIN_CONFIG_avalanche-c" hit "invalid variable name" and caused exit 1 for chains whose names contain a hyphen. Fix: ${blockchain_node_lower//-/_} for cache var name only — on-disk file name and chain_type field unchanged. 4 chains affected: avalanche-c, avalanche-x, cosmos-hub, zksync-era. VERIFICATION: L1 36-chain `source loader && generate_auto_config`: baseline 8 chains: 8/8 unchanged (byte-equal to snapshot) new 28 chains: 28/28 keys complete (7 required keys all present) Dry-run preview before live run showed correct transformation for all 28 chains, 0 file errors. FINDINGS DOCUMENTED: * S0-inv naming mismatch — file is config/chains/cosmos-hub.json (1886B), not cosmos.json. Wave-A entry check assumed `cosmos` and falsely reported "0-byte missing". Future wave entry checks must list real file names, not assume. * 20/28 chains marked adapter_required (71%) — REST / mixed-protocol chains will be normalized to baseline shape but mock route won't handle HTTP-path methods. S3 adds adapter layer. NOT a defer — it's the real boundary of "JSON-RPC over HTTP" framework. REVERSAL: git checkout 70e88ed -- config/chains/ config/config_loader.sh rm tools/normalize_chain_templates.py (normalizer is one-shot; safe to delete after merge if desired, but kept in tree as documentation of the mapping rule.) See analysis-notes/p2-exec/wave-S0.7-norm.md for full decision table, finding details, and S2-A re-entry plan. baseline=70e88ed
1 parent 70e88ed commit 9e341b2

31 files changed

Lines changed: 1538 additions & 1037 deletions
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Wave S0.7-norm — 28 链 schema normalize + cache var name bash 合法化
2+
3+
**baseline**: S1 commit `70e88ed`
4+
**完成时间**: 2026-05-24
5+
**目标**: 把 S0-inv 抽出的 28 链 chain template(调研格式)normalize 成 baseline 7 字段格式,**消除"调研 schema vs baseline schema"双源 parallel-entry-trap**;附带修复带 `-` 链名(`avalanche-c` / `cosmos-hub` / `zksync-era` / `avalanche-x`)在 `config_loader.sh` cache var name 处的 bash 语法错误。
6+
7+
## 决策与执行回顾
8+
9+
### 路线选择(A vs B vs C)
10+
11+
| 选项 | 走法 || 理由 |
12+
|------|------|-----|------|
13+
| **A** | 一次性 normalize 全 28 链 + 单脚本可复跑 || 0 技术债,后续 wave 0 schema 负担 |
14+
| B | wave A 内逐链改 6 个,defer 余下 22 个 || 每 wave 重复一遍转换逻辑 = 隐性 parallel-entry-trap 变种 |
15+
| C | 暂停 S2,先回 S0.7 做 schema 校准 | ≈A | 实质同 A,只是 phase 命名问题 |
16+
17+
最终走 A,作为 S0.7 一个独立 wave 完成。
18+
19+
### 字段映射(调研 → baseline)
20+
21+
| baseline 字段 | 调研字段 | 转换规则 |
22+
|---------------|----------|----------|
23+
| `chain_type` | `chain_type` | 复用 |
24+
| `rpc_url` || 常量 `"LOCAL_RPC_URL"`(同 baseline 8 链)|
25+
| `rpc_methods.single` | `single_method` | 字符串 |
26+
| `rpc_methods.mixed` | `mixed_methods[]` | `,`.join |
27+
| `methods` || `{}`(framework 别名,新链 S3 用到再补)|
28+
| `param_formats` | `param_formats` | 复用 |
29+
| `params` | `target_address` | 标准 6-key 模板 + `target_address` 真值 |
30+
| `system_addresses` | `system_addresses` | 复用 |
31+
32+
调研专有字段(`chain` / `public_endpoints` / `single_method` / `mixed_methods` / `rpc_protocol` / `target_address` / `notes`)**保留到 `_meta.original_*`**,转换可追溯。
33+
34+
## 重要发现
35+
36+
### Finding 1: `cosmos.json` 0 字节 ≠ 文件缺失
37+
38+
S2 wave A 入口校验时报 `cosmos.json` 0 字节缺失。实际是 S0-inv 抽稿时按调研稿文件名 `05-cosmos-hub.md` 命名,生成的是 `cosmos-hub.json`(1886B 完整)。**校验脚本写死 `cosmos` 名字误判。**
39+
40+
教训:wave 入口校验时 chain 名要按真实文件名(`ls config/chains/*.json`),不能预设。
41+
42+
### Finding 2: 20/28 链标 `adapter_required = true`(71%)
43+
44+
|| 真接口 | adapter_required |
45+
|----|--------|-----|
46+
| EVM L2(arbitrum/optimism/linea/zksync-era/avalanche-c) | 纯 JSON-RPC | ❌(可直跑) |
47+
| EVM L1 变种(kusama/near) | 纯 JSON-RPC ||
48+
| Cosmos 系(cosmos-hub/osmosis/celestia/injective/sei) | Tendermint RPC + REST 双栈 ||
49+
| UTXO 系(bitcoin/litecoin/dogecoin/bch) | JSON-RPC 1.0 + Esplora REST ||
50+
| 其他(aptos/cardano/polkadot/tezos/algorand/tron/ton/hedera + Substrate 系) | REST / 各种 ||
51+
52+
`adapter_required = true` **不是技术债,是真实业务边界**:framework master_qps_executor 只发 JSON-RPC POST,REST 链需 adapter。S3 阶段统一加 adapter,本 wave 只 normalize schema。
53+
54+
### Finding 3: bash cache var name bug — 文件名带 `-` 全挂
55+
56+
`config_loader.sh:494` `export "$cache_var_name"=...`,cache var name 含 `-` 时 bash 报 `invalid variable name`。baseline 8 链都是单 token,没暴露;normalize 后 4 个新链(`avalanche-c` / `avalanche-x` / `cosmos-hub` / `zksync-era`)立刻挂掉。
57+
58+
**修法**:cache var name 用 `${blockchain_node_lower//-/_}` 替换 `-``_`,3 处:
59+
- L494 `cache_var_name="CACHED_CHAIN_CONFIG_${blockchain_node_var_safe}"`
60+
- L466 `rpc_cache_var_name="CACHED_RPC_METHODS_${...//-/_}_${rpc_mode_lower}"`
61+
- L535 同上(另一处出现)
62+
63+
文件名不动,chain_type 字段不动,影响最小。
64+
65+
## 改造文件
66+
67+
| 文件 | 变更 |
68+
|------|------|
69+
| `tools/normalize_chain_templates.py` | **NEW** 215 行,一次性 normalizer + 幂等检测 |
70+
| `config/chains/<chain>.json` × 28 | 全量 rewrite(28 新链,baseline 8 不动)|
71+
| `config/config_loader.sh` | 3 处 cache var name 加 `//-/_` 替换 |
72+
| `analysis-notes/p2-exec/wave-S0.7-norm.md` | **NEW** 本报告 |
73+
74+
## 验证(全 PASS)
75+
76+
### L1 36 链全跑 `source loader && generate_auto_config`
77+
78+
```
79+
baseline 8 链: 8/8 unchanged (字节级 == snapshot)
80+
新 28 链: 28/28 keys complete (chain_type/methods/param_formats/params/
81+
rpc_methods/rpc_url/system_addresses 全在)
82+
```
83+
84+
### 反转策略已具备
85+
86+
```bash
87+
git diff HEAD~1 config/chains/ # 看完整 normalize diff
88+
git checkout HEAD~1 -- config/chains/ # 回滚到 normalize 前
89+
```
90+
91+
normalize 脚本幂等,再跑无副作用。
92+
93+
## 下一步(回到 S2 wave A)
94+
95+
S2 wave A = wave1+2 = Bitcoin / Aptos / Cosmos-Hub / Cardano / Polkadot / NEAR(6 链)。
96+
97+
:wave A 6 链中:
98+
- `bitcoin` `cardano` `aptos` `polkadot` 4 链 `adapter_required = true` → 只验证 L1+L2 配置层,L3 mock route 在 S3 adapter 层做(本 wave 不算回归)
99+
- `near` `cosmos-hub` 2 链:near 纯 JSON-RPC ✅、cosmos-hub `adapter_required` → 同上
100+
101+
wave A 每链 3 步:
102+
1. **mock handler 增量**(若为纯 JSON-RPC 链,加 handler 到 `CHAIN_HANDLERS`)
103+
2. **L1+L2 验证**(配置 + smoke)
104+
3. **L3 验证仅对非 adapter_required 链**(目前 wave A 只有 `near` 一条)
105+
4. **commit + push**
106+
107+
`adapter_required` 链的 L3 mock 跑通推迟到 S3 adapter 层,**不算 defer**(是真实业务边界顺序问题)。

config/chains/acala.json

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,52 @@
11
{
2-
"_meta": {
3-
"source": "research-md",
4-
"research_doc": "docs/zh/chains/27-acala.md",
5-
"extracted_at": "2026-05-24T00:26:38Z",
6-
"extracted_by": "subagent_batch_S0-inv",
7-
"baseline_sha": "ffbeeee",
8-
"note": "Extracted from research-md by subagent. param_formats may need normalization in S1 alignment with adapters."
9-
},
10-
"chain": "acala",
112
"chain_type": "acala",
12-
"public_endpoints": [
13-
{
14-
"url": "https://acala-rpc-0.aca-api.network",
15-
"auth": false,
16-
"verified": "E2",
17-
"notes": "Substrate JSON-RPC"
18-
},
19-
{
20-
"url": "https://eth-rpc-acala.aca-api.network",
21-
"auth": false,
22-
"verified": "E2",
23-
"notes": "EVM+ JSON-RPC ChainID 787"
24-
}
25-
],
26-
"single_method": "system_chain",
27-
"mixed_methods": [
28-
"system_chain",
29-
"chain_getHeader",
30-
"state_getRuntimeVersion",
31-
"eth_chainId",
32-
"eth_blockNumber"
33-
],
3+
"methods": {},
344
"param_formats": {
355
"system_chain": "no_params",
366
"chain_getHeader": "no_params",
377
"state_getRuntimeVersion": "no_params",
388
"eth_chainId": "no_params",
399
"eth_blockNumber": "no_params"
4010
},
11+
"params": {
12+
"account_count": "ACCOUNT_COUNT",
13+
"max_signatures": "ACCOUNT_MAX_SIGNATURES",
14+
"output_file": "ACCOUNTS_OUTPUT_FILE",
15+
"semaphore_limit": "ACCOUNT_SEMAPHORE_LIMIT",
16+
"target_address": "0x0000000000000000000000000000000000000000",
17+
"tx_batch_size": "ACCOUNT_TX_BATCH_SIZE"
18+
},
19+
"rpc_methods": {
20+
"single": "system_chain",
21+
"mixed": "system_chain,chain_getHeader,state_getRuntimeVersion,eth_chainId,eth_blockNumber"
22+
},
23+
"rpc_url": "LOCAL_RPC_URL",
4124
"system_addresses": [],
42-
"target_address": "0x0000000000000000000000000000000000000000",
43-
"rpc_protocol": "mixed",
44-
"notes": "Polkadot parachain 2000;Substrate + EVM+ 双协议;多 token system [ACA,AUSD,DOT,LDOT];in-protocol shared-block EVM"
45-
}
25+
"_meta": {
26+
"source": "research-md",
27+
"research_doc": "docs/zh/chains/27-acala.md",
28+
"extracted_at": "2026-05-24T00:26:38Z",
29+
"extracted_by": "subagent_batch_S0-inv",
30+
"baseline_sha": "ffbeeee",
31+
"note": "Extracted from research-md by subagent. param_formats may need normalization in S1 alignment with adapters.",
32+
"normalized_at": "2026-05-24T04:43:09.932379+00:00",
33+
"normalized_by": "tools/normalize_chain_templates.py (S0.7-norm)",
34+
"original_rpc_protocol": "mixed",
35+
"original_public_endpoints": [
36+
{
37+
"url": "https://acala-rpc-0.aca-api.network",
38+
"auth": false,
39+
"verified": "E2",
40+
"notes": "Substrate JSON-RPC"
41+
},
42+
{
43+
"url": "https://eth-rpc-acala.aca-api.network",
44+
"auth": false,
45+
"verified": "E2",
46+
"notes": "EVM+ JSON-RPC ChainID 787"
47+
}
48+
],
49+
"original_notes": "Polkadot parachain 2000;Substrate + EVM+ 双协议;多 token system [ACA,AUSD,DOT,LDOT];in-protocol shared-block EVM",
50+
"adapter_required": true
51+
}
52+
}

config/chains/algorand.json

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,58 @@
11
{
2-
"_meta": {
3-
"source": "research-md",
4-
"research_doc": "docs/zh/chains/10-algorand.md",
5-
"extracted_at": "2026-05-24T00:26:38Z",
6-
"extracted_by": "subagent_batch_S0-inv",
7-
"baseline_sha": "ffbeeee",
8-
"note": "Extracted from research-md by subagent. param_formats may need normalization in S1 alignment with adapters."
9-
},
10-
"chain": "algorand",
112
"chain_type": "algorand",
12-
"public_endpoints": [
13-
{
14-
"url": "https://mainnet-api.algonode.cloud",
15-
"auth": false,
16-
"verified": "E2",
17-
"notes": "algod 实时节点 0.21s"
18-
},
19-
{
20-
"url": "https://mainnet-idx.algonode.cloud",
21-
"auth": false,
22-
"verified": "E2",
23-
"notes": "indexer 历史查询节点 0.15s"
24-
},
25-
{
26-
"url": "https://mainnet-api.4160.nodely.dev",
27-
"auth": false,
28-
"verified": "E2",
29-
"notes": "Nodely 备用"
30-
}
31-
],
32-
"single_method": "GET /v2/status",
33-
"mixed_methods": [
34-
"GET /v2/accounts/{address}",
35-
"GET /v2/transactions/{txid}",
36-
"GET /v2/blocks/{round}",
37-
"GET /v2/assets/{asset_id}",
38-
"GET /v2/accounts/{address}/transactions"
39-
],
3+
"methods": {},
404
"param_formats": {
415
"GET /v2/accounts/{address}": "path_addr_base32",
426
"GET /v2/transactions/{txid}": "path_txid_base32",
437
"GET /v2/blocks/{round}": "path_round_int",
448
"GET /v2/assets/{asset_id}": "path_asset_id_int",
459
"GET /v2/accounts/{address}/transactions": "path_addr_query_limit"
4610
},
11+
"params": {
12+
"account_count": "ACCOUNT_COUNT",
13+
"max_signatures": "ACCOUNT_MAX_SIGNATURES",
14+
"output_file": "ACCOUNTS_OUTPUT_FILE",
15+
"semaphore_limit": "ACCOUNT_SEMAPHORE_LIMIT",
16+
"target_address": "Q5WOHVUKNEM4XOVL725KH77WS6GODZSI4HTSWZAILM36ANSYVHW5RJI3KE",
17+
"tx_batch_size": "ACCOUNT_TX_BATCH_SIZE"
18+
},
19+
"rpc_methods": {
20+
"single": "GET /v2/status",
21+
"mixed": "GET /v2/accounts/{address},GET /v2/transactions/{txid},GET /v2/blocks/{round},GET /v2/assets/{asset_id},GET /v2/accounts/{address}/transactions"
22+
},
23+
"rpc_url": "LOCAL_RPC_URL",
4724
"system_addresses": [],
48-
"target_address": "Q5WOHVUKNEM4XOVL725KH77WS6GODZSI4HTSWZAILM36ANSYVHW5RJI3KE",
49-
"rpc_protocol": "rest",
50-
"notes": "双节点架构(algod + indexer),每 method 需 node_role 路由;Base32 地址 58 字符;ASA 持仓内嵌于 accounts 响应"
51-
}
25+
"_meta": {
26+
"source": "research-md",
27+
"research_doc": "docs/zh/chains/10-algorand.md",
28+
"extracted_at": "2026-05-24T00:26:38Z",
29+
"extracted_by": "subagent_batch_S0-inv",
30+
"baseline_sha": "ffbeeee",
31+
"note": "Extracted from research-md by subagent. param_formats may need normalization in S1 alignment with adapters.",
32+
"normalized_at": "2026-05-24T04:43:09.933176+00:00",
33+
"normalized_by": "tools/normalize_chain_templates.py (S0.7-norm)",
34+
"original_rpc_protocol": "rest",
35+
"original_public_endpoints": [
36+
{
37+
"url": "https://mainnet-api.algonode.cloud",
38+
"auth": false,
39+
"verified": "E2",
40+
"notes": "algod 实时节点 0.21s"
41+
},
42+
{
43+
"url": "https://mainnet-idx.algonode.cloud",
44+
"auth": false,
45+
"verified": "E2",
46+
"notes": "indexer 历史查询节点 0.15s"
47+
},
48+
{
49+
"url": "https://mainnet-api.4160.nodely.dev",
50+
"auth": false,
51+
"verified": "E2",
52+
"notes": "Nodely 备用"
53+
}
54+
],
55+
"original_notes": "双节点架构(algod + indexer),每 method 需 node_role 路由;Base32 地址 58 字符;ASA 持仓内嵌于 accounts 响应",
56+
"adapter_required": true
57+
}
58+
}

config/chains/aptos.json

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,26 @@
11
{
2-
"_meta": {
3-
"source": "research-md",
4-
"research_doc": "docs/zh/chains/04-aptos.md",
5-
"extracted_at": "2026-05-24T00:26:38Z",
6-
"extracted_by": "subagent_batch_S0-inv",
7-
"baseline_sha": "ffbeeee",
8-
"note": "Extracted from research-md by subagent. param_formats may need normalization in S1 alignment with adapters."
9-
},
10-
"chain": "aptos",
112
"chain_type": "aptos",
12-
"public_endpoints": [
13-
{
14-
"url": "https://fullnode.mainnet.aptoslabs.com/v1",
15-
"auth": false,
16-
"verified": "E2",
17-
"notes": "主推 endpoint,HTTP 200 0.24s"
18-
},
19-
{
20-
"url": "https://api.mainnet.aptoslabs.com/v1",
21-
"auth": false,
22-
"verified": "E2",
23-
"notes": "别名,/-/healthy=aptos-node:ok"
24-
}
25-
],
26-
"single_method": "GET /v1",
27-
"mixed_methods": [
28-
"POST /v1/view",
29-
"GET /v1",
30-
"GET /v1/accounts/{addr}",
31-
"GET /v1/accounts/{addr}/resources",
32-
"GET /v1/transactions/by_hash/{hash}"
33-
],
3+
"methods": {},
344
"param_formats": {
355
"POST /v1/view": "move_view_call",
366
"GET /v1": "no_params",
377
"GET /v1/accounts/{addr}": "path_addr",
388
"GET /v1/accounts/{addr}/resources": "path_addr",
399
"GET /v1/transactions/by_hash/{hash}": "path_hash"
4010
},
11+
"params": {
12+
"account_count": "ACCOUNT_COUNT",
13+
"max_signatures": "ACCOUNT_MAX_SIGNATURES",
14+
"output_file": "ACCOUNTS_OUTPUT_FILE",
15+
"semaphore_limit": "ACCOUNT_SEMAPHORE_LIMIT",
16+
"target_address": "0xd503b95164384a5ebbccbb5c4bdc8b4a5893d9651e9953abda8e1c22fcc1181d",
17+
"tx_batch_size": "ACCOUNT_TX_BATCH_SIZE"
18+
},
19+
"rpc_methods": {
20+
"single": "GET /v1",
21+
"mixed": "POST /v1/view,GET /v1,GET /v1/accounts/{addr},GET /v1/accounts/{addr}/resources,GET /v1/transactions/by_hash/{hash}"
22+
},
23+
"rpc_url": "LOCAL_RPC_URL",
4124
"system_addresses": [
4225
"0x1",
4326
"0x2",
@@ -48,7 +31,31 @@
4831
"0x7",
4932
"0xa"
5033
],
51-
"target_address": "0xd503b95164384a5ebbccbb5c4bdc8b4a5893d9651e9953abda8e1c22fcc1181d",
52-
"rpc_protocol": "rest",
53-
"notes": "REST 而非 JSON-RPC,POST JSON-RPC 返 405;响应自带 x-aptos-* header 免去 ledger 调用"
54-
}
34+
"_meta": {
35+
"source": "research-md",
36+
"research_doc": "docs/zh/chains/04-aptos.md",
37+
"extracted_at": "2026-05-24T00:26:38Z",
38+
"extracted_by": "subagent_batch_S0-inv",
39+
"baseline_sha": "ffbeeee",
40+
"note": "Extracted from research-md by subagent. param_formats may need normalization in S1 alignment with adapters.",
41+
"normalized_at": "2026-05-24T04:43:09.933707+00:00",
42+
"normalized_by": "tools/normalize_chain_templates.py (S0.7-norm)",
43+
"original_rpc_protocol": "rest",
44+
"original_public_endpoints": [
45+
{
46+
"url": "https://fullnode.mainnet.aptoslabs.com/v1",
47+
"auth": false,
48+
"verified": "E2",
49+
"notes": "主推 endpoint,HTTP 200 0.24s"
50+
},
51+
{
52+
"url": "https://api.mainnet.aptoslabs.com/v1",
53+
"auth": false,
54+
"verified": "E2",
55+
"notes": "别名,/-/healthy=aptos-node:ok"
56+
}
57+
],
58+
"original_notes": "REST 而非 JSON-RPC,POST JSON-RPC 返 405;响应自带 x-aptos-* header 免去 ledger 调用",
59+
"adapter_required": true
60+
}
61+
}

0 commit comments

Comments
 (0)