在钱包开发中,我们经常要使用到rpc节点的调用,但是每一个链的rpc接口又有着差异,我们必须去对每一个链进行适配,十分麻烦。而多链RPC应用这个项目将会拯救你。
在钱包开发中,我们经常要使用到 rpc 节点的调用,但是每一个链的 rpc 接口又有着差异,我们必须去对每一个链进行适配,十分麻烦。而多链 RPC 应用这个项目将会拯救你。
多链 RPC 应用是一个轻量级高性能的 Go RPC 服务,通过聚合多链的 rpc 接口,提供统一的接口调用。
多链 rpc 应用的系统架构相对而言比较简单。我们的策略工厂和每一个对接的链实现上都实现了 25 个必须的接口,在调用的时候,通过一个策略工厂来为每一个用户请求分发到不同的链实现上。
例如: 一个调用者需要调用以太坊上的根据hash获取区块的一个接口,调用者只需传入以太坊的字符串“ethereum”和对应的 hash 值,我们程序中即可进行按照 ethereum 这个标志进行分发策略到以太坊的 rpc 实现上去完成调用。对调用者而言,无须关心这次调用的细节。
详细代码可见: chain-union-rpc
├── bin protobuf 命令管理
├── chains 支持的链
├── chaindispatcher 接口分发
├── common 通用工具库
├── config 配置代码
├── proto grpc 生成的 protobuf代码
├── main.go 程序主入口
├── go.mod 依赖管理
├── config.yml 配置文件
├── Makefile shell 命令管理
├── README.md 项目文档
├── DEVSTEPTS.md 项目开发步骤
/*注册拦截器*/
grpcServer := grpc.NewServer(grpc.UnaryInterceptor(dispatcher.Interceptor))
defer grpcServer.GracefulStop()
/*注册实现的接口路由*/
chainsunion.RegisterChainsUnionServiceServer(grpcServer, dispatcher)
if err := grpcServer.Serve(listen); err != nil {
log.Error("failed to serve", "port", conf.Server.Port, "err", err)
panic(err)
}
/*新建处理器*/
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
}
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()
}
实现在 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
grpc页面测试
eyJjaGFpbl9pZCI6IjE3MDAwIiwibm9uY2UiOjEsImZyb21fYWRkcmVzcyI6IjB4ZUQyRWI5N2I4NDM4NkNiNzRDMTIzMmU4MzNDOGNhMjZGY0QyZTFiOSIsInRvX2FkZHJlc3MiOiIweDcyZkZhQTI4OTk5M2JjYURhMkUwMTYxMjk5NUU1Yzc1ZEQ4MWNkQkMiLCJnYXNfbGltaXQiOjIxMDAwMCwiZ2FzIjoyMTAwMDAsIm1heF9mZWVfcGVyX2dhcyI6IjMwMDAwMDAwMDAwIiwibWF4X3ByaW9yaXR5X2ZlZV9wZXJfZ2FzIjoiMTUwMDAwMDAwMCIsImFtb3VudCI6IjEwMDAwMDAwMDAwMDAwMDAwMDAiLCJjb250cmFjdF9hZGRyZXNzIjoiMHgwMCJ9
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!