当前位置:   article > 正文

RPC请求优化_eth的providers

eth的providers

场景,发送N个rpc请求

Tip: 以下调用的合约与https://web03.cn/blog/257是一样的

使用普通rpc发送请求

console.time('A')
        const web3 = new Web3(new Web3.providers.HttpProvider('https://bsc-dataseed.binance.org/'))
        var myContractInstance = new web3.eth.Contract(ABI, '0x948d2a81086A075b3130BAc19e4c6DEe1D2E3fE8');
        const promiseArr = []
        for (let i = 0; i < 10; i++) {
            promiseArr.push(myContractInstance.methods.balanceOf('0x23FCB0E1DDbC821Bd26D5429BA13B7D5c96C0DE0').call())
        }
        Promise.all(promiseArr).then(res => {
            console.timeEnd('A')
            console.log(res)
        })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

发送10个rpc请求的结果

发送300个rpc请求的结果

注意:可能发送20个就会导致一些rpc失败,可能100个…,rpc数量越多,失败概率越高

使用 ethers-multicall-x 发送请求

https://www.npmjs.com/package/ethers-multicall-x

npm install ethers-multicall-x
npm install @ethersproject/providers
  • 1
  • 2
console.time('B')
const concat = new Contract('0x948d2a81086A075b3130BAc19e4c6DEe1D2E3fE8', ABI)
const promiseArr = []
for (let i = 0; i < 100; i++) {
    promiseArr.push(concat.balanceOf('0x23FCB0E1DDbC821Bd26D5429BA13B7D5c96C0DE0'))
}
const provider = new JsonRpcProvider('https://bsc-dataseed.binance.org/', 56)
const multiCallProvider = new Provider(provider, 56);
multiCallProvider.all(promiseArr).then(res => {
    console.timeEnd('B')
    console.log(res)
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

请求100个数据的结果

你会发现它的数据都是BigNumber类型,需要手动解析

解析result

function processResult(data) {
  if (Array.isArray(data)){
    data.map((o, i) => {
      data[i] = processResult(o)
    })
    return data
  }else if(data.toString){
    return data.toString()
  } else{
    return data
  }
}
processResult(result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

解析后结果

将所有的rpc请求方法一次性提交给插件,插件通过自己的合约去调用目标合约的方法,拿到所有返回的内容后再返回给用户,相当于是中间代理,合约对合约的交互调用,省去了RPC请求

封装ethers-multicall-x

为了减少消耗,可以将ethers-multicall-x进行封装,只在第一次调用的时候进行初始化实例对象

import Web3 from "web3";
import ABI from '../ABI/abi.json'
import {Contract,Provider, setMulticallAddress} from "ethers-multicall-x";
import {JsonRpcProvider} from "@ethersproject/providers";

const ChainId = {
    BSC: 56
}

const ChainConfig = (chainId) => {
    return {
        [ChainId.BSC]: {
            rpc_url: 'https://bsc-dataseed.binance.org/',
            abi: ABI,
            address: '0x948d2a81086A075b3130BAc19e4c6DEe1D2E3fE8'
        }
    }[chainId]
}

const _CONTRACT = {}
export const getContract = (chainId) =>{
// 如果相同的chainId不同的address或者abi,此步骤是多余的,没必要缓存
    if (_CONTRACT[chainId]) {
        return _CONTRACT[chainId]
    }
    const config = ChainConfig(chainId)
    console.log(config)
    return _CONTRACT[chainId] = new Contract(config.address, config.abi)
}

let _PROVIDER = {}
export const getMultiCallProvider = (chainId) =>{
    if (_PROVIDER[chainId]) {
        return _PROVIDER[chainId]
    }
    const provider = new JsonRpcProvider(ChainConfig(chainId).rpc_url, chainId)
    // 添加插件外的链配置
    setMulticallAddress(137, "0x11ce4B23bD875D7F5C6a31084f55fDe1e9A87507")
    return _PROVIDER[chainId] = new Provider(provider, chainId);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
const concat = getContract(ChainId.BSC)
const multiCallProvider = getMultiCallProvider(ChainId.BSC)
  • 1
  • 2

总结

普通RPC请求

  1. 有并发限制,发送量大会报错
  2. 发送多个RPC请求,部分请求会处于Pending状态,请求阻塞
  3. 请求返回的结果可以直接使用
  4. 创建请求消耗低

ethers-multicall-x

  1. 可以一次性发送大量的’RPC’请求
  2. 解决并发问题,(实际上只发送了一个)
  3. 创建请求有一定的基础消耗
  4. 在某种情况,当计费模式为rpc请求数量的时候,可以大大减少请求的费用
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/55812
推荐阅读
相关标签
  

闽ICP备14008679号