作者:PaperMoon 团队
如果你是一个在以太坊或 L2 上写了几年合约的开发者,最近可能听说了一件事——Polkadot 开了一个叫 Polkadot Hub 的合约部署入口,号称"用你原来的 Solidity 代码就能直接跑"。听到这种话的第一反应通常不是兴奋,而是怀疑——因为过去几年类似的口号见得太多了,九成九落地后都会出现一句"但是……"。
docs.polkadot.com 最近更新的这一页——/smart-contracts/for-eth-devs/json-rpc-apis/,其实就是那句"但是"的完整版。它把 Polkadot Hub 对标 Ethereum JSON-RPC 的所有方法列得清清楚楚,也把两处非常容易踩坑的兼容性差异直接标在了文档里。看懂这一页,基本就等于看懂了"我的 ethers.js 代码要不要改"这个问题的答案。
这篇文章不讲"Polkadot 是什么",假设读者已经写过几年智能合约。我们只聊三件事:Polkadot Hub 到底开放了哪些 JSON-RPC 方法、哪些直接能用、哪两个必须单独拎出来看的坑。
一、一张清单:Polkadot Hub 目前开放的 31 个 JSON-RPC 方法
按 namespace 分,文档列出的兼容方法如下。
eth_* 命名空间(23 个,覆盖最常用的读写操作)
常用读方法:
eth_blockNumber、eth_chainId、eth_gasPrice、eth_maxPriorityFeePerGaseth_getBalance、eth_getCode、eth_getStorageAt、eth_getTransactionCounteth_getBlockByHash、eth_getBlockByNumbereth_getBlockTransactionCountByHash、eth_getBlockTransactionCountByNumbereth_getTransactionByHash、eth_getTransactionByBlockHashAndIndex、eth_getTransactionByBlockNumberAndIndexeth_getTransactionReceipt、eth_getLogseth_syncing、eth_accounts
核心写方法:
eth_sendRawTransaction(签名后发送,生产环境最常用的那个)eth_sendTransaction(需要节点持有账户,通常用于测试)
模拟类:
eth_call(只读模拟调用)eth_estimateGas(gas 估算)
net_* 命名空间(3 个)
net_listening、net_peerCount、net_version
web3_* 命名空间(1 个)
web3_clientVersion
system_* 命名空间(1 个)
system_health
debug_* 命名空间(3 个,调试和 tracing 刚需)
debug_traceBlockByNumber、debug_traceTransaction、debug_traceCall
这张清单给出的信号非常直接——绝大多数做 DApp 业务、做链上数据读取、做合约模拟的场景,基本都能原地用。你现在用的 ethers.js、viem、web3.js、Hardhat、Foundry,底层依赖的就是这个集合里的方法。
二、可以"几乎无感"迁移的部分
先说好消息。对大多数常见场景,你的现有代码几乎不用改:
- 查询类代码:
getBalance、getCode、getStorageAt、getTransactionCount、getBlockByNumber这些都原样支持,ABI 和参数也和 Ethereum 一致。 - 交易广播:
sendRawTransaction原样支持,你原本用来签名后推交易的逻辑可以直接复用。 - 日志索引:
getLogs支持,The Graph、Dune 类索引工具的底层查询逻辑能搬过来。 - Tracing 支持:
debug_traceTransaction/debug_traceCall都开放了,意味着 Tenderly 这类调试平台、MEV 数据管道、审计工具的移植门槛不高。
这一点在 L1 兼容历史里其实不多见。过去很多声称"EVM 兼容"的链,要么 debug namespace 残缺、要么 getLogs 性能极差、要么 receipt 结构字段不一致——这三项是做 dev tool 的人最常被坑的地方。Polkadot Hub 这一版至少在接口契约上把这三件都兜住了。
但是——有两个方法你必须单独看一眼,因为它们文档里明确标注了和 Geth 不一样的行为。
三、坑一:eth_call 的 code 字段会自动识别 EVM 和 PVM
这是 Polkadot Hub 专有的一个扩展,也是它区别于所有其他"EVM 兼容链"的最核心细节。
eth_call 在 Geth 上支持一个叫 State Override 的可选参数集,允许你在模拟调用时临时替换账户的余额、nonce、code、storage——常用于"如果我这个合约这样改了,会是什么结果?"类的假设性测试。
Polkadot Hub 完整支持了这套 State Override 规范,包括 balance、nonce、code、state、stateDiff 这些标准字段。但它对 code 字段做了一个扩展——这个字段同时接受 EVM 字节码和 PolkaVM(PVM)字节码,系统通过 blob 起始位置的 magic bytes 自动识别类型。
这意味着什么?意味着你可以在同一个 eth_call 调用里做两种模拟:
- 传入标准 EVM 字节码——走传统 EVM 路径,和 Geth 行为完全一致。
- 传入 PVM 字节码——走 Polkadot Hub 原生的 PolkaVM 路径,拿到 PolkaVM 执行下的结果。
这个设计隐含了一件事——Polkadot Hub 不是"伪装成 EVM 的链",它是一个同时支持 EVM ABI 兼容和原生 PVM 的双 VM 系统,eth_call 是目前唯一把这两种执行路径暴露给 JSON-RPC 用户的入口。对构建开发者工具、IDE、审计器的人来说,这是一个值得重点研究的点,它给 Solidity → PolkaVM 的运行时对比提供了一个干净的 API 边界。
另外文档还提到一个兼容性细节:movePrecompileToAddress 字段接受但不生效——也就是说它不会抛错,但也什么都不做,纯粹为了和 Geth API 形状保持一致,让你的 viem / ethers 代码能照常序列化和发送,不至于因为这个字段报错。
四、坑二:debug_traceTransaction 的 gasCost 和 Geth 算法不一样
这是第二个、也是更隐蔽的一个差异。
在 Geth 里,当 tracer 逐条记录 CALL / DELEGATECALL / STATICCALL / CREATE / CREATE2 这类"call-like" opcode 的时候,gasCost 字段包含的是——该 opcode 自身的固定成本 + 所有转发给子调用的 gas。简单说,它是一个"包含后续执行的全部代价"的数字。
Polkadot Hub 这里改了算法:gasCost 只包含该 opcode 自身的固定成本,不包含转发给子调用的那部分。
这个差异在日常业务合约里多半看不出来。但如果你做的是以下这些场景,必须重新校准:
- Gas 账单分析工具:把"一次调用的总成本"按 opcode 拆开展示的工具,在 Polkadot Hub 上会显示出和 Etherscan 完全不一样的分布。
- MEV 机器人的内部预算:如果你的 bot 用 tracer 的
gasCost之和来估算总消耗,Polkadot Hub 上会低估真实消耗——因为子调用的成本被从gasCost里剥离了。 - 合约审计脚本:基于 tracer 的 gas 热点分析如果沿用 Geth 的
gasCost语义,会把 call 类节点的"热度"算偏。
官方文档在这里的措辞非常直白,没有试图掩饰兼容性差异。这其实是一个正面信号——很多链在做"EVM 兼容"的时候,最喜欢说"完全一致",结果开发者上手踩了半年坑才意识到差异;Polkadot Hub 的做法是把这两处不一样的地方明明白白写在文档里,让你在迁移前就能知道。
五、这份清单上"没有"的东西:三个值得注意的缺口
对一个成熟的以太坊开发者来说,看清单一半是看"有什么",另一半是看"没什么"。
第一,没有 eth_subscribe / WebSocket 订阅。文档这一页没提这个方法,也没提对 WebSocket 订阅的支持状态。如果你的应用依赖 newHeads、logs、newPendingTransactions 这类实时推送(比如一个监听交易的前端),你需要要么走轮询模式(用 eth_blockNumber + eth_getLogs 定期拉取),要么关注官方后续的更新。
第二,主网 endpoint 暂未在这一页公开。文档给出的 endpoint 是 services.polkadothub-rpc.com/testnet——显式标注为 testnet。生产环境部署的开发者需要等官方主网 endpoint 公布,或走自己的 RPC 节点。
第三,速率限制没有公开描述。对生产环境来说,这是一个必须提前摸底的变量。建议正式上生产前先跑一次压测,或者直接联系官方确认配额。
这三点不影响你现在做测试和移植,但要写进项目 risk log 里。
六、迁移决策:你的 ethers.js 代码到底要不要改
把这一页文档消化完之后,对一个典型以太坊开发者来说,迁移路径大概可以这样定:
- 读流(index / explorer / 查询类):可以直接切换 RPC endpoint,代码几乎不动。
- 写流(交易签名 + 广播):
sendRawTransaction原样支持,但要注意 Polkadot Hub 的 gas 模型是权重时间 + 字节费的双维度(这和eth_gasPrice返回的"单一 gas price"抽象是有细微差别的,见同站 2026-03-17 那篇《以太坊开发者必看|Polkadot 的 Gas 不是你以为的 Gas》)。估算 gas 时一律用eth_estimateGas的返回,不要自己拍脑袋乘系数。 - 调试流(tracer / MEV / 审计):能工作,但
debug_traceTransaction里的gasCost语义要重写一次。 - 实时流(WebSocket 订阅):暂时走轮询。
- 状态模拟(eth_call + State Override):可以工作,而且多了一个 PVM 字节码可选分支——这是 Polkadot Hub 独有的能力。
一句话总结:读流和写流的兼容性非常高,调试和实时流需要单独适配,状态模拟多了一个 PVM 新维度。整体看,这份 JSON-RPC 文档给 Polkadot Hub 的兼容性打了一个相当高的分数——它不是靠"和 Geth 完全一样"拿这个分,而是靠"不一样的地方一定写在文档里"拿这个分。后者比前者更值得信任。
小结
一条 L1 要想真正吸引到以太坊生态里的存量开发者,光喊"我们 EVM 兼容"是不够的。真正决定迁移难度的,是两件事——接口契约列得有多清楚、差异标得有多诚实。这两件事都需要文档级别的精细功夫,而不是一篇 Medium 博文能糊弄过去的。
Polkadot Hub 这一页 JSON-RPC 文档,某种程度上就是它对这两个问题的答卷。它不避讳 debug_traceTransaction 的 gasCost 差异,它在 eth_call 的 State Override 里老老实实把 movePrecompileToAddress 标注为"接受但无效",它明确指出 endpoint 是 testnet。这些细节加起来,传递的是一种比口号更重要的东西——这条链是想让你的代码跑起来的,不是想让你的代码"先跑再说"的。
对一个以太坊开发者来说,Polkadot Hub 目前的兼容性已经过了"值得试一下"这条线。把你项目里最常用的那十几个 RPC 调用贴到这张清单上对一下,大概率你会发现——能直接用的比你想的多,需要改的比你怕的少。

578

被折叠的 条评论
为什么被折叠?



