From f252ed261885b6bea43cc66e60c3deeb66362115 Mon Sep 17 00:00:00 2001 From: Kirill Fedoseev Date: Sun, 23 Aug 2020 22:56:59 +0300 Subject: [PATCH] Add a possibility to fetch gas price from multiple sources (#420) --- CONFIGURATION.md | 2 +- commons/package.json | 1 + commons/utils.js | 12 ++++++++++-- monitor/docker-compose-build.yml | 4 +++- monitor/validators.js | 7 ++++++- oracle/docker-compose-build.yml | 4 +++- oracle/src/services/gasPrice.js | 5 +++-- ui/src/stores/GasPriceStore.js | 3 ++- yarn.lock | 15 +++++++++++++++ 9 files changed, 44 insertions(+), 9 deletions(-) diff --git a/CONFIGURATION.md b/CONFIGURATION.md index 20251b9b..f13d24b8 100644 --- a/CONFIGURATION.md +++ b/CONFIGURATION.md @@ -12,7 +12,7 @@ COMMON_HOME_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from th COMMON_HOME_GAS_PRICE_SPEED_TYPE | Assuming the gas price oracle responds with the following JSON structure: `{"fast": 20.0, "block_time": 12.834, "health": true, "standard": 6.0, "block_number": 6470469, "instant": 71.0, "slow": 1.889}`, this parameter specifies the desirable transaction speed. The speed type can be omitted when `COMMON_HOME_GAS_PRICE_SUPPLIER_URL` is not used. | `instant` / `fast` / `standard` / `slow` COMMON_HOME_GAS_PRICE_FALLBACK | The gas price (in Wei) that is used if both the oracle and the fall back gas price specified in the Home Bridge contract are not available. | integer COMMON_HOME_GAS_PRICE_FACTOR | A value that will multiply the gas price of the oracle to convert it to gwei. If the oracle API returns gas prices in gwei then this can be set to `1`. Also, it could be used to intentionally pay more gas than suggested by the oracle to guarantee the transaction verification. E.g. `1.25` or `1.5`. | integer -COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from the gas price prediction oracle for the Foreign network. The provided gas price is used to send the validator's transactions to the RPC node. If the Foreign network is Ethereum Foundation mainnet, the oracle URL can be: https://gasprice.poa.network. Otherwise this parameter can be omitted. | URL +COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL | The URL used to get a JSON response from the gas price prediction oracle for the Foreign network. The provided gas price is used to send the validator's transactions to the RPC node. If the Foreign network is Ethereum Foundation mainnet, the oracle URL can be: https://gasprice.poa.network. Otherwise this parameter can be omitted. Set to `gas-price-oracle` if you want to use npm `gas-price-oracle` package for retrieving gas price from multiple sources. | URL COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE | Assuming the gas price oracle responds with the following JSON structure: `{"fast": 20.0, "block_time": 12.834, "health": true, "standard": 6.0, "block_number": 6470469, "instant": 71.0, "slow": 1.889}`, this parameter specifies the desirable transaction speed. The speed type can be omitted when `COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL`is not used. | `instant` / `fast` / `standard` / `slow` COMMON_FOREIGN_GAS_PRICE_FALLBACK | The gas price (in Wei) used if both the oracle and fall back gas price specified in the Foreign Bridge contract are not available. | integer COMMON_FOREIGN_GAS_PRICE_FACTOR | A value that will multiply the gas price of the oracle to convert it to gwei. If the oracle API returns gas prices in gwei then this can be set to `1`. Also, it could be used to intentionally pay more gas than suggested by the oracle to guarantee the transaction verification. E.g. `1.25` or `1.5`. | integer diff --git a/commons/package.json b/commons/package.json index 200922ac..5c30bf55 100644 --- a/commons/package.json +++ b/commons/package.json @@ -8,6 +8,7 @@ "test": "NODE_ENV=test mocha" }, "dependencies": { + "gas-price-oracle": "^0.1.5", "web3-utils": "1.0.0-beta.34" }, "devDependencies": { diff --git a/commons/utils.js b/commons/utils.js index 965eb008..520008c1 100644 --- a/commons/utils.js +++ b/commons/utils.js @@ -1,7 +1,10 @@ const { toWei, toBN } = require('web3-utils') +const { GasPriceOracle } = require('gas-price-oracle') const { BRIDGE_MODES, FEE_MANAGER_MODE, ERC_TYPES } = require('./constants') const { REWARDABLE_VALIDATORS_ABI } = require('./abis') +const gasPriceOracle = new GasPriceOracle() + function decodeBridgeMode(bridgeModeHash) { switch (bridgeModeHash) { case '0x92a8d7fe': @@ -235,8 +238,13 @@ const normalizeGasPrice = (oracleGasPrice, factor, limits = null) => { // we use built-in 'fetch' on browser side, and `node-fetch` package in Node. const gasPriceFromSupplier = async (fetchFn, options = {}) => { try { - const response = await fetchFn() - const json = await response.json() + let json + if (fetchFn) { + const response = await fetchFn() + json = await response.json() + } else { + json = await gasPriceOracle.fetchGasPricesOffChain() + } const oracleGasPrice = json[options.speedType] if (!oracleGasPrice) { diff --git a/monitor/docker-compose-build.yml b/monitor/docker-compose-build.yml index 08faa198..124f89c5 100644 --- a/monitor/docker-compose-build.yml +++ b/monitor/docker-compose-build.yml @@ -3,4 +3,6 @@ version: '2.4' services: monitor: image: poanetwork/tokenbridge-monitor - build: . + build: + context: .. + dockerfile: ./monitor/Dockerfile diff --git a/monitor/validators.js b/monitor/validators.js index e298b06b..e8f71dfc 100644 --- a/monitor/validators.js +++ b/monitor/validators.js @@ -100,8 +100,13 @@ async function main(bridgeMode) { if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) { logger.debug('calling foreign getGasPrices') + const fetchFn = + COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL === 'gas-price-oracle' + ? null + : () => fetch(COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL) + foreignGasPrice = - (await gasPriceFromSupplier(() => fetch(COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL), foreignGasPriceSupplierOpts)) || + (await gasPriceFromSupplier(fetchFn, foreignGasPriceSupplierOpts)) || Web3Utils.toBN(COMMON_FOREIGN_GAS_PRICE_FALLBACK) foreignGasPriceGwei = Web3Utils.fromWei(foreignGasPrice.toString(), 'gwei') foreignTxCost = foreignGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_FOREIGN_TX_LIMIT)) diff --git a/oracle/docker-compose-build.yml b/oracle/docker-compose-build.yml index c129d662..5905acd2 100644 --- a/oracle/docker-compose-build.yml +++ b/oracle/docker-compose-build.yml @@ -3,4 +3,6 @@ version: '2.4' services: oracle: image: poanetwork/tokenbridge-oracle - build: . + build: + context: .. + dockerfile: ./oracle/Dockerfile diff --git a/oracle/src/services/gasPrice.js b/oracle/src/services/gasPrice.js index 96a4c8ac..6cd25c1d 100644 --- a/oracle/src/services/gasPrice.js +++ b/oracle/src/services/gasPrice.js @@ -73,13 +73,14 @@ async function start(chainId, fetchOnce) { throw new Error(`Unrecognized chainId '${chainId}'`) } + const fetchFn = gasPriceSupplierUrl === 'gas-price-oracle' ? null : () => fetch(gasPriceSupplierUrl) if (fetchOnce) { - await fetchGasPrice(speedType, factor, bridgeContract, () => fetch(gasPriceSupplierUrl)) + await fetchGasPrice(speedType, factor, bridgeContract, fetchFn) return getPrice() } fetchGasPriceInterval = setIntervalAndRun( - () => fetchGasPrice(speedType, factor, bridgeContract, () => fetch(gasPriceSupplierUrl)), + () => fetchGasPrice(speedType, factor, bridgeContract, fetchFn), updateInterval ) return null diff --git a/ui/src/stores/GasPriceStore.js b/ui/src/stores/GasPriceStore.js index 328c588e..20a28655 100644 --- a/ui/src/stores/GasPriceStore.js +++ b/ui/src/stores/GasPriceStore.js @@ -53,7 +53,8 @@ class GasPriceStore { } const oracleOptions = { speedType: this.speedType, factor: this.factor, logger: console } - this.gasPrice = (await gasPriceFromSupplier(() => fetch(this.gasPriceSupplierUrl), oracleOptions)) || this.gasPrice + const fetchFn = this.gasPriceSupplierUrl === 'gas-price-oracle' ? null : () => fetch(this.gasPriceSupplierUrl) + this.gasPrice = (await gasPriceFromSupplier(fetchFn, oracleOptions)) || this.gasPrice setTimeout(() => this.updateGasPrice(), this.updateInterval) } diff --git a/yarn.lock b/yarn.lock index e86569d0..2263a441 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4209,6 +4209,13 @@ axios@0.19.0: follow-redirects "1.5.10" is-buffer "^2.0.2" +axios@^0.19.2: + version "0.19.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" + integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== + dependencies: + follow-redirects "1.5.10" + axobject-query@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" @@ -9822,6 +9829,14 @@ ganache-core@^2.6.0: ethereumjs-wallet "0.6.3" web3 "1.2.4" +gas-price-oracle@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/gas-price-oracle/-/gas-price-oracle-0.1.5.tgz#09dd0d9806465c2f5e63b682e6742f96f6eb525c" + integrity sha512-fkaTXnxJcSVco/tMPEcN5gieoUNs8O6JYMXflGLN2+3YeGZAucUI0fgCliazM3nRVAk//bBEm9819/Zb83xhrw== + dependencies: + axios "^0.19.2" + bignumber.js "^9.0.0" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"