refactor: 落地 P0 —— 移除 TRON 源码密钥 + 全局运行态收口成可注入 Registry - #2
Open
lbtsm wants to merge 3 commits into
Open
Conversation
The TronGrid API key was hardcoded in Connect, so it shipped in every binary and could not be rotated without a release, and every environment shared one credential. Take it from the chain's `apiKey` opt instead. It stays optional: a self hosted FullNode gRPC endpoint needs no key, so an empty value only warns rather than failing startup. Deployments that talk to a hosted gateway must now set `apiKey` in config — and the leaked key needs rotating regardless. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The MAP client, per-chain contract callers, height providers and the light manager lived in package level vars in internal/mapprotocol, written by five chain constructors and by the expose proof API. Gin serves each proof request on its own goroutine, and chains.Proffer hands every request the same prototype, so those plain maps were written concurrently — a concurrent map write away from taking the process down — and tests could only work by mutating and restoring globals. Introduce mapprotocol.Registry: one owner for that state, every accessor guarded, snapshots handed to callers that iterate. Missing entries now report ErrNotRegistered instead of panicking (Map2OtherHeight was indexed and called in one expression) or silently returning a nil height (the Get2MapHeight/GetNodeTypeByManager function vars defaulted to (nil, nil) until startup swapped them out). The four Init* calls that installed those closures collapse into one LightManager object built from a client and an address, which a small ContractCaller interface makes unit testable. Also fold the five near-identical Proffer.Connect bodies into chain.ProofConnector. Each wrapped its registration in a sync.OnceFunc allocated inside the call, so the Once was fresh every time and deduped nothing: every proof request re-registered shared state and leaked a new connection. The connector caches per chain and endpoint, registers once, and stops swallowing ABI parse errors. Registry is still reached through Default() at the call sites, so the process wide instance is unchanged; what changed is that it is now a value that can be passed in, which is what the next step needs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
落地 WORK-19 评审里的两条 P0,从
main新切分支。范围只到「拿掉源码密钥」+「全局运行态收口成可注入对象」,Router 命令管道(P0-3)和链工厂/连接拆分(P1)没有动。1. TRON API Key 从源码搬到配置
chains/tron/conn.go的Connect里写死了一份 TronGrid API Key,随二进制发布、全环境共用、轮换必须改代码。改成从链配置的apiKeyopt 读取。与评审建议的一点差异:没有做成缺失即启动失败。自建 FullNode 的 gRPC 端点本来不需要 key,硬性要求会让自建部署起不来;所以空值只告警。已在
config.json.example补了 tron 示例段。2. 跨链运行态收口成
mapprotocol.Registry原先 MAP client、各链合约 caller、height provider、light manager 全是
internal/mapprotocol的包级变量,5 处链构造 + expose proof API 都在写。Gin 每个 proof 请求一个 goroutine,而chains.Proffer每次返回的是同一个原型对象,所以那些裸 map 是并发写的 —— 离concurrent map write崩进程只差流量。Registry:一个所有者、访问全部加锁、需要遍历的地方返回快照。ErrNotRegistered,而不是 panic(Map2OtherHeight[id]()这种取值即调用)或静默返回 nil height(Get2MapHeight/GetNodeTypeByManager这些函数变量在 Init 之前默认返回(nil, nil),调用方直接对 nil 做Cmp)。Init*(各装一个闭包进函数变量)合并成一个LightManager对象,依赖收窄到ContractCaller这一个方法的接口,因此可以脱离 RPC 单测。Registry仍通过Default()取用,进程内实例没变;变的是它现在是个能被传进去的值 —— 下一步(把CommonSync/writer/proof service 改成构造函数注入)才有落点。3. 顺手消掉 5 份重复的
Proffer.Connectbsc / matic / eth2 / ethereum / tron 各有一份几乎一样的
Connect。每份都把注册逻辑包在sync.OnceFunc里,但那个Once是在函数内部现场 new 的,所以每次调用都会重新执行 —— 也就是每个 proof 请求都重跑一遍共享状态注册,并且新建一条连接从不关闭。抽成
chain.ProofConnector:按 (chainId, endpoint) 缓存连接、只注册一次、ABI 解析错误不再被_吞掉。5 份实现各剩一行。影响面
apiKey(仅 tron)。MosMapping(现MosAddress)与GetDataByManager(现LightManagerData)本来就只写不读,这次保留但没有新增调用方,可以后续清理。自测
go1.26.3 darwin/arm64新增 11 个测试,其中两个专门跑
-race复现原来的并发写场景:TestRegistryConcurrentAccess(16 组读写 goroutine 打同一份状态)、TestProofConnectorConcurrentConnect(32 个 goroutine 同时 Connect,断言只 dial 一次)。go vet ./...只剩 issue 里已声明的三项既有问题(core与chains/sol测试包编译不过、internal/stream/btc.go重复 json tag,WORK-12 在跟)。config.Test_GetPrivateKeyFromFile失败与本分支无关:它写死了别人机器上的 keystore 路径/Users/xm/Desktop/...,git diff origin/main -- config/对该文件无改动。未跑需要真实链 RPC / keystore 的集成测试,未发起任何链上交易。
🤖 Generated with Claude Code