钱包对接 RPC 节点 - 搭建多链统一 RPC 节点支持

在钱包开发中,我们经常要使用到rpc节点的调用,但是每一个链的rpc接口又有着差异,我们必须去对每一个链进行适配,十分麻烦。而多链RPC应用这个项目将会拯救你。

多链 RPC 应用

在钱包开发中,我们经常要使用到 rpc 节点的调用,但是每一个链的 rpc 接口又有着差异,我们必须去对每一个链进行适配,十分麻烦。而多链 RPC 应用这个项目将会拯救你。

多链 RPC 应用是一个轻量级高性能的 Go RPC 服务,通过聚合多链的 rpc 接口,提供统一的接口调用。

✨ 核心特性

  • 通过策略模式去调用每一条链,提供统一的接口
  • 模块化结构,新增链支持只需编写某个链的代码即可
  • 基于 GRPC 通信协议,简单高性能
  • 易于配置,只需提供必要配置即可运行

多链 rpc 应用的系统架构图

image.png 多链 rpc 应用的系统架构相对而言比较简单。我们的策略工厂和每一个对接的链实现上都实现了 25 个必须的接口,在调用的时候,通过一个策略工厂来为每一个用户请求分发到不同的链实现上。

例如: 一个调用者需要调用以太坊上的根据hash获取区块的一个接口,调用者只需传入以太坊的字符串“ethereum”和对应的 hash 值,我们程序中即可进行按照 ethereum 这个标志进行分发策略到以太坊的 rpc 实现上去完成调用。对调用者而言,无须关心这次调用的细节。

搭建一个多链 rpc 应用的步骤

详细代码可见: chain-union-rpc

⭐️ 1. 项目架构

├── bin               protobuf 命令管理       
├── chains            支持的链       
├── chaindispatcher   接口分发
├── common            通用工具库
├── config            配置代码
├── proto             grpc 生成的 protobuf代码
├── main.go           程序主入口
├── go.mod            依赖管理
├── config.yml        配置文件
├── Makefile          shell 命令管理
├── README.md         项目文档
├── DEVSTEPTS.md      项目开发步骤

2. 编写 proto 文件

  • proto 中,编写 account.proto文件
  • 定义消息、接口
  • 调用 make proto 生成相应的 go 代码

3. 搭建 grpc 框架

  • 新建 grpcServer
    /*注册拦截器*/
    grpcServer := grpc.NewServer(grpc.UnaryInterceptor(dispatcher.Interceptor))
    defer grpcServer.GracefulStop()
  • 注册 chainDispatcher
/*注册实现的接口路由*/
chainsunion.RegisterChainsUnionServiceServer(grpcServer, dispatcher)
  • tcp 端口监听启动
    if err := grpcServer.Serve(listen); err != nil {
        log.Error("failed to serve", "port", conf.Server.Port, "err", err)
        panic(err)
    }
  • 实现 dispatcher.go 负责接口的转发给不同链的调用,实例需继承 IChainAdaptor
/*新建处理器*/
func New(conf *config.Config) (*ChainDispatcher, error) {
    dispatcher := &ChainDispatcher{
        registry: make(map[ChainType]chains.IChainAdaptor),
    }
    /*适配器工厂,根据key 按策略分发给不同 adaptor 实现*/
    chainAdaptorFactoryMap := map[string]func(conf *config.Config) (chains.IChainAdaptor, error){
        strings.ToLower(ethereum.ChainName): ethereum.NewChainAdaptor,
    }
    supportedChains := []string{
        strings.ToLower(ethereum.ChainName),
    }

    /*全部 new 出来放到工厂 map 中*/
    for _, c := range conf.Chains {
        chainName := strings.ToLower(c)
        if factory, ok := chainAdaptorFactoryMap[chainName]; ok {
            adaptor, err := factory(conf)
            if err != nil {
                log.Crit("Failed to create chain adaptor", "err", err)
            }
            dispatcher.registry[chainName] = adaptor
        } else {
            log.Error("Unsupported chain type", "chain", chainName, "supportedChains", supportedChains)
        }
    }
    return dispatcher, nil
}
  • 构建 所有链调用实例的代码,如 ethereum.go, 实现 IChainAdaptor

4. 实现对接 rpc 节点和数据平台的 client

  • 实现 ethclient.go 对接区块链 rpc 节点
type EthClient interface {
    BlockHeaderByNumber(*big.Int) (*types.Header, error)
    BlockHeaderByHash(common.Hash) (*types.Header, error)
    BlockHeadersByRange(*big.Int, *big.Int, uint) ([]types.Header, error)
    BlockByNumber(*big.Int) (*RpcBlock, error)
    BlockByHash(common.Hash) (*RpcBlock, error)
    LatestSafeBlockHeader() (*types.Header, error)
    LatestFinalizedBlockHeader() (*types.Header, error)
    TxCountByAddress(common.Address) (hexutil.Uint64, error)
    SuggestGasPrice() (*big.Int, error)
    SuggestGasTipCap() (*big.Int, error)
    SendRawTransaction(rawTx string) (*common.Hash, error)
    TxByHash(common.Hash) (*types.Transaction, error)
    TxReceiptByHash(common.Hash) (*types.Receipt, error)
    StorageHash(common.Address, *big.Int) (common.Hash, error)
    EthGetCode(common.Address) (string, error)
    GetBalance(address common.Address) (*big.Int, error)
    FilterLogs(filterQuery ethereum.FilterQuery, chainId uint) (Logs, error)
    Close()
}
  • 实现 erc20data.go 对接区块链数据平台 实现在 evmbase 包下

    5. 实现对接链的接口

    实现在 ethereum 包下,实现 IChainAdaptor 接口,负责实现我们在 protobuf 中定义的所有接口。

    1. 链支持
    2. 地址转换
    3. 地址校验
    4. 根据区块号获取区块
    5. 根据 hash 获取区块
    6. 根据 hash 获取区块头
    7. 根据区块号获取区块头
    8. 根据范围获取区块头
    9. 获取账号信息
    10. 获取手续费
    11. 发送交易
    12. 根据地址获取交易
    13. 根据交易 hash 获取交易
    14. 构建未签名交易
    15. 构建已签名交易
    16. 交易解码,解析成可读形式
    17. 校验已签名交易
    18. 获取额外数据
    19. 获取某个地址的 NFT 列表
    20. 获取 NFT 的集合
    21. 获取 NFT 的细节
    22. 获取 NFT 的持有者列表
    23. 获取 NFT 的交易历史
    24. 获取某个地址的 NFT 交易历史
    25 获取范围内区块

运行测试

make test

image.png

grpc页面测试

  • base64 交易 eyJjaGFpbl9pZCI6IjE3MDAwIiwibm9uY2UiOjEsImZyb21fYWRkcmVzcyI6IjB4ZUQyRWI5N2I4NDM4NkNiNzRDMTIzMmU4MzNDOGNhMjZGY0QyZTFiOSIsInRvX2FkZHJlc3MiOiIweDcyZkZhQTI4OTk5M2JjYURhMkUwMTYxMjk5NUU1Yzc1ZEQ4MWNkQkMiLCJnYXNfbGltaXQiOjIxMDAwMCwiZ2FzIjoyMTAwMDAsIm1heF9mZWVfcGVyX2dhcyI6IjMwMDAwMDAwMDAwIiwibWF4X3ByaW9yaXR5X2ZlZV9wZXJfZ2FzIjoiMTUwMDAwMDAwMCIsImFtb3VudCI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJjb250cmFjdF9hZGRyZXNzIjoiMHgwMCJ9 image.png

image.png

点赞 0
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
shawn_shaw
shawn_shaw
web3潜水员、技术爱好者、web3钱包开发工程师。欢迎闲聊唠嗑、精进技术、交流工作机会。vx:cola_ocean