@zhengkan2008/rpc-pool
v3.0.0
Published
Health-aware RPC pool with query load balancing and tx primary-backup failover.
Readme
RPC Pool(重写版)
@zhengkan2008/rpc-pool 在保留 v2 全部能力的前提下,v3 新增了显式 lane 模型:
slow:普通只读、provider caps、背景读取fast:simulation、路径 quote、扫描阶段预估tx-critical:nonce / send / replacement / cancel / 最终提交前检查archive:仅供 sandbox / fork / replaybundle:仅供 ETH builder / Flashbots relay
旧的 v2 通道仍然完整保留:
- 查询通道(
query):多 RPC 负载均衡,连续失败自动摘除,进入观察名单,探活后自动回池。 - 交易通道(
tx):单主 RPC 提交交易,连续失败自动切备,故障节点进入观察名单,恢复后回备池。
环境变量
以 Gnosis 为例:
# 查询池(负载均衡)
GNOSIS_RPC_HTTP_GNOSISCHAIN=https://rpc.gnosischain.com/
GNOSIS_RPC_HTTP_PUBLICNODE=https://gnosis-rpc.publicnode.com默认只需要配置查询池(*_RPC_HTTP_*)。交易通道会自动复用查询池,无需额外配置 TX 专用键。
v3 新 lane 使用新 env 命名,不回退旧 env:
BASE_RPC_HTTP_SLOW_1=https://...
BASE_RPC_HTTP_FAST_1=https://...
BASE_RPC_TX_CRITICAL_1=https://...
BASE_RPC_HTTP_ARCHIVE_1=https://...
ETH_RPC_BUNDLE_1=https://...支持链前缀:ETH、BSC、BASE、ARBITRUM、GNOSIS。
新增常用主网支持:POLYGON(137)、OPTIMISM(10)、AVALANCHE(43114)。
别名可用:polygon/matic、optimism/op、avalanche/avax。
Provider 分级(付费 / 公共)
当 RPC_PROVIDER_TIERING=true(默认)时:
query通道(getQueryClient/getQueryTransport)优先使用公共 RPC。simulation/write通道(getSimulationTransport/getTxTransport)优先使用付费或默认 RPC。
如果某一层没有可用节点,会自动回退到全部 HTTP 节点。
非 ETH 交易 RPC 的 MEV 排序
对非 ETH 链,tx 通道现在会先按 RPC 提供商“官方已公开、免费层可用”的
MEV 保护能力重排候选端点,再决定主备顺序:
- 优先支持 Bundle 工作流的提供商
- 其次是内建私有路由 / 私有内存池保护
- 再其次是隐私中继 / 交易清洗
- 最后是未知能力或普通公共 RPC
当前内置规则刻意保守,只提升已确认能力:
ALCHEMY:在base/arbitrum/bsc上按“内建 MEV 保护”提升; 其中base额外按 Bundle 工作流再加权。1RPC:在非 ETH 链按隐私中继与交易清洗能力提升。
没有明确免费层 MEV 保护文档的提供商会留在默认分组,并保持原有相对顺序。
可选覆盖:
RPC_TX_MEV_SORTING_ENABLED=true
RPC_TX_MEV_PROVIDER_PRIORITY=alchemy,1rpcRPC_TX_MEV_PROVIDER_PRIORITY 用 provider id 从高到低强制覆盖。当前内置 id:
alchemy、1rpc。
推荐命名:
- 公共:
<CHAIN>_RPC_HTTP_PUBLIC_<PROVIDER> - 付费:
<CHAIN>_RPC_HTTP_PAID_<PROVIDER>
策略参数
RPC_QUERY_FAIL_THRESHOLD=3
RPC_TX_FAIL_THRESHOLD=2
RPC_RECOVER_THRESHOLD=2
RPC_WATCH_COOLDOWN_MS=30000
RPC_HEALTHCHECK_MS=8000
RPC_PROBE_TIMEOUT_MS=2500
RPC_REQUEST_TIMEOUT_MS=10000
RPC_TRANSPORT_RETRY_DELAY_MS=150使用方式
import {
getQueryClient,
getQueryTransport,
getTxTransport,
getRpcPoolStats,
} from '@zhengkan2008/rpc-pool';
import { createWalletClient } from 'viem';
import { gnosis } from 'viem/chains';
const queryClient = getQueryClient('gnosis');
const block = await queryClient.getBlockNumber();
const txWallet = createWalletClient({
chain: gnosis,
transport: getTxTransport('gnosis'),
});
const stats = getRpcPoolStats('gnosis');
console.log(stats.tx.primaryUrl, stats.query.watchCount);新 API
getRpcPool(chainName)getQueryClient(chainName)getQueryTransport(chainName)getSimulationTransport(chainName)getTxTransport(chainName)getMaxPendingNonce(chainName, address, options?)sendNonceManagedRawTransaction(chainName, options)sendBundle(chainName, options)(当前 ETH)getBundleStats(chainName, options)(当前 ETH)getRpcPoolStats(chainName)listRpcPoolChains()
v3 lane API
getSlowClient/getSlowTransportgetFastClient/getFastTransportgetTxCriticalClient/getTxCriticalTransportgetArchiveClient/getArchiveTransportgetTxCriticalMaxPendingNoncesendTxCriticalNonceManagedRawTransactionsendBundleViaBundleLane(ETH)getBundleStatsViaBundleLane(ETH)
lane mode:
mode: 'fail-over' | 'load-balance'tx-critical的load-balance使用affinityKey做 sticky 绑定
其中:
fast + load-balance内建 hedged requestarchive只用于历史块读取,不参与普通运行时getRpcPoolStats()现在带schemaVersion: 3,并在配置 v3 lane 时返回每条 lane 的 stats
ETH Bundle 发送(builder / Flashbots relay)
ETH 链现在支持参考 futarchyArbitrage/scripts/arb-bot-production-v9.ts 的
bundle 广播方式:对多个 builder / Flashbots relay 并发提交 eth_sendBundle,
并自动附带 X-Flashbots-Signature。
默认 builder 列表:
https://relay.flashbots.nethttps://rpc.titanbuilder.xyzhttps://rpc.buildernet.orghttps://rpc.quasar.win
可通过环境变量覆盖:
ETH_RPC_BUNDLE_PRIMARY=https://relay.flashbots.net
ETH_RPC_BUNDLE_BACKUP_1=https://rpc.titanbuilder.xyz
ETH_RPC_BUNDLE_BACKUP_2=https://rpc.buildernet.org
ETH_RPC_BUNDLE_BACKUP_3=https://rpc.quasar.win
FLASHBOTS_RELAY_SIGNING_KEY=0x...示例:
import { sendBundle, getBundleStats } from '@zhengkan2008/rpc-pool';
import { privateKeyToAccount } from 'viem/accounts';
const signer = privateKeyToAccount(process.env.FLASHBOTS_RELAY_SIGNING_KEY as `0x${string}`);
const sent = await sendBundle('eth', {
signedTxs: ['0x...'],
targetBlocks: [21_000_001],
flashbotsSigner: signer,
});
const accepted = sent.results.find((item) => item.success && item.bundleHash);
if (accepted?.bundleHash) {
const stats = await getBundleStats('eth', {
bundleHash: accepted.bundleHash,
targetBlock: accepted.targetBlock,
flashbotsSigner: signer,
endpoint: accepted.endpoint,
});
console.log(stats);
}托管 Nonce 发送(简化调用方)
如果你用本地私钥签名,可以把 nonce 探测、冲突重同步、RPC failover 全部交给库:
import { sendNonceManagedRawTransaction } from '@zhengkan2008/rpc-pool';
import { privateKeyToAccount } from 'viem/accounts';
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const result = await sendNonceManagedRawTransaction('gnosis', {
from: account.address,
async signRawTransaction(nonce) {
return account.signTransaction({
to: '0x0000000000000000000000000000000000000000',
value: 0n,
gas: 21000n,
nonce,
chainId: 100,
});
},
});
console.log(result.hash, result.nonce.toString(), result.endpointUrl);交易专用 RPC(可选)
默认不需要 *_RPC_TX_*。只有你明确希望交易通道与查询通道分离时,才开启:
RPC_TX_USE_DEDICATED=true
GNOSIS_RPC_TX_PRIMARY=https://...
GNOSIS_RPC_TX_BACKUP_1=https://...发布到 npm / 私有仓库
1) 发布到 npm 官方仓库
cd shared/rpc-pool
npm run build
npm run pack:dry-run
npm login --registry https://registry.npmjs.org
npm run publish:npm2) 发布到私有 npm 仓库
cd shared/rpc-pool
export NPM_PRIVATE_REGISTRY="https://npm.company.internal/"
export NPM_PRIVATE_TOKEN="<token>"
npm run publish:private3) 凭据模板
可参考 .npmrc.example,按你的仓库地址和 token 替换。
4) scope 注意事项
当前包名是 @zhengkan2008/rpc-pool。如果你在 npm 官方不拥有 @zhengkan2008 scope,需要先改 package.json 的 name(例如改成你自己的 scope)。
