Fix logging in gas price service (#583)

This commit is contained in:
Kirill Fedoseev 2021-07-05 13:50:18 +03:00 committed by GitHub
parent 3e5e50c06e
commit c8eb0f1ed8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 89 deletions

@ -9,7 +9,8 @@
}, },
"dependencies": { "dependencies": {
"gas-price-oracle": "^0.1.5", "gas-price-oracle": "^0.1.5",
"web3-utils": "^1.3.0" "web3-utils": "^1.3.0",
"node-fetch": "^2.1.2"
}, },
"devDependencies": { "devDependencies": {
"bn-chai": "^1.0.1", "bn-chai": "^1.0.1",

@ -1,5 +1,6 @@
const { toWei, toBN, BN } = require('web3-utils') const { toWei, toBN, BN } = require('web3-utils')
const { GasPriceOracle } = require('gas-price-oracle') const { GasPriceOracle } = require('gas-price-oracle')
const fetch = require('node-fetch')
const { BRIDGE_MODES } = require('./constants') const { BRIDGE_MODES } = require('./constants')
const { REWARDABLE_VALIDATORS_ABI } = require('./abis') const { REWARDABLE_VALIDATORS_ABI } = require('./abis')
@ -178,17 +179,16 @@ const normalizeGasPrice = (oracleGasPrice, factor, limits = null) => {
return toBN(toWei(gasPrice.toFixed(2).toString(), 'gwei')) return toBN(toWei(gasPrice.toFixed(2).toString(), 'gwei'))
} }
// fetchFn has to be supplied (instead of just url to oracle), const gasPriceFromSupplier = async (url, options = {}) => {
// because this utility function is shared between Browser and Node,
// we use built-in 'fetch' on browser side, and `node-fetch` package in Node.
const gasPriceFromSupplier = async (fetchFn, options = {}) => {
try { try {
let json let json
if (fetchFn) { if (url === 'gas-price-oracle') {
const response = await fetchFn() json = await gasPriceOracle.fetchGasPricesOffChain()
} else if (url) {
const response = await fetch(url, { timeout: 2000 })
json = await response.json() json = await response.json()
} else { } else {
json = await gasPriceOracle.fetchGasPricesOffChain() return null
} }
const oracleGasPrice = json[options.speedType] const oracleGasPrice = json[options.speedType]

@ -8,12 +8,12 @@ COMMON_HOME_BRIDGE_ADDRESS=0x8397be90BCF57b0B71219f555Fe121b22e5a994C
COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E COMMON_FOREIGN_BRIDGE_ADDRESS=0x1feB40aD9420b186F019A717c37f5546165d411E
ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b ORACLE_VALIDATOR_ADDRESS=0xaaB52d66283F7A1D5978bcFcB55721ACB467384b
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9 ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY=8e829f695aed89a154550f30262f1529582cc49dc30eff74a6b491359e0230f9
COMMON_HOME_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/ COMMON_HOME_GAS_PRICE_SUPPLIER_URL=
COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard COMMON_HOME_GAS_PRICE_SPEED_TYPE=standard
COMMON_HOME_GAS_PRICE_FALLBACK=1000000000 COMMON_HOME_GAS_PRICE_FALLBACK=1000000000
ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000 ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL=600000
COMMON_HOME_GAS_PRICE_FACTOR=1 COMMON_HOME_GAS_PRICE_FACTOR=1
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/ COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
COMMON_FOREIGN_GAS_PRICE_FALLBACK=10000000000 COMMON_FOREIGN_GAS_PRICE_FALLBACK=10000000000
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000 ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000

@ -1,6 +1,5 @@
require('dotenv').config() require('dotenv').config()
const Web3Utils = require('web3').utils const Web3Utils = require('web3').utils
const fetch = require('node-fetch')
const logger = require('./logger')('validators') const logger = require('./logger')('validators')
const { getBridgeABIs, BRIDGE_VALIDATORS_ABI, gasPriceFromSupplier } = require('../commons') const { getBridgeABIs, BRIDGE_VALIDATORS_ABI, gasPriceFromSupplier } = require('../commons')
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./utils/web3') const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./utils/web3')
@ -81,7 +80,7 @@ async function main(bridgeMode) {
if (MONITOR_VALIDATOR_HOME_TX_LIMIT) { if (MONITOR_VALIDATOR_HOME_TX_LIMIT) {
logger.debug('calling home getGasPrices') logger.debug('calling home getGasPrices')
homeGasPrice = homeGasPrice =
(await gasPriceFromSupplier(() => fetch(COMMON_HOME_GAS_PRICE_SUPPLIER_URL), homeGasPriceSupplierOpts)) || (await gasPriceFromSupplier(COMMON_HOME_GAS_PRICE_SUPPLIER_URL, homeGasPriceSupplierOpts)) ||
Web3Utils.toBN(COMMON_HOME_GAS_PRICE_FALLBACK) Web3Utils.toBN(COMMON_HOME_GAS_PRICE_FALLBACK)
homeGasPriceGwei = Web3Utils.fromWei(homeGasPrice.toString(), 'gwei') homeGasPriceGwei = Web3Utils.fromWei(homeGasPrice.toString(), 'gwei')
homeTxCost = homeGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_HOME_TX_LIMIT)) homeTxCost = homeGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_HOME_TX_LIMIT))
@ -93,13 +92,9 @@ async function main(bridgeMode) {
if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) { if (MONITOR_VALIDATOR_FOREIGN_TX_LIMIT) {
logger.debug('calling foreign getGasPrices') 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 = foreignGasPrice =
(await gasPriceFromSupplier(fetchFn, foreignGasPriceSupplierOpts)) || (await gasPriceFromSupplier(COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL, foreignGasPriceSupplierOpts)) ||
Web3Utils.toBN(COMMON_FOREIGN_GAS_PRICE_FALLBACK) Web3Utils.toBN(COMMON_FOREIGN_GAS_PRICE_FALLBACK)
foreignGasPriceGwei = Web3Utils.fromWei(foreignGasPrice.toString(), 'gwei') foreignGasPriceGwei = Web3Utils.fromWei(foreignGasPrice.toString(), 'gwei')
foreignTxCost = foreignGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_FOREIGN_TX_LIMIT)) foreignTxCost = foreignGasPrice.mul(Web3Utils.toBN(MONITOR_VALIDATOR_FOREIGN_TX_LIMIT))

@ -1,5 +1,4 @@
require('../../env') require('../../env')
const fetch = require('node-fetch')
const { home, foreign } = require('../../config/base.config') const { home, foreign } = require('../../config/base.config')
const logger = require('../services/logger').child({ const logger = require('../services/logger').child({
module: 'gasPrice' module: 'gasPrice'
@ -25,11 +24,11 @@ let cachedGasPrice = null
let fetchGasPriceInterval = null let fetchGasPriceInterval = null
const fetchGasPrice = async (speedType, factor, bridgeContract, gasPriceSupplierFetchFn) => { const fetchGasPrice = async (speedType, factor, bridgeContract, gasPriceSupplierUrl) => {
const contractOptions = { logger } const contractOptions = { logger }
const supplierOptions = { speedType, factor, limits: GAS_PRICE_BOUNDARIES, logger } const supplierOptions = { speedType, factor, limits: GAS_PRICE_BOUNDARIES, logger }
cachedGasPrice = cachedGasPrice =
(await gasPriceFromSupplier(gasPriceSupplierFetchFn, supplierOptions)) || (await gasPriceFromSupplier(gasPriceSupplierUrl, supplierOptions)) ||
(await gasPriceFromContract(bridgeContract, contractOptions)) || (await gasPriceFromContract(bridgeContract, contractOptions)) ||
cachedGasPrice cachedGasPrice
return cachedGasPrice return cachedGasPrice
@ -63,16 +62,15 @@ async function start(chainId, fetchOnce) {
throw new Error(`Unrecognized chainId '${chainId}'`) throw new Error(`Unrecognized chainId '${chainId}'`)
} }
let fetchFn = null if (!gasPriceSupplierUrl) {
if (gasPriceSupplierUrl !== 'gas-price-oracle') { logger.warn({ chainId }, 'Gas price API is not configured, will fallback to the contract-supplied gas price')
fetchFn = () => fetch(gasPriceSupplierUrl, { timeout: 2000 })
} }
if (fetchOnce) { if (fetchOnce) {
await fetchGasPrice(speedType, factor, contract, fetchFn) await fetchGasPrice(speedType, factor, contract, gasPriceSupplierUrl)
} else { } else {
fetchGasPriceInterval = await setIntervalAndRun( fetchGasPriceInterval = await setIntervalAndRun(
() => fetchGasPrice(speedType, factor, contract, fetchFn), () => fetchGasPrice(speedType, factor, contract, gasPriceSupplierUrl),
updateInterval updateInterval
) )
} }

@ -3,77 +3,75 @@ const { expect } = require('chai')
const proxyquire = require('proxyquire').noPreserveCache() const proxyquire = require('proxyquire').noPreserveCache()
const { DEFAULT_UPDATE_INTERVAL } = require('../src/utils/constants') const { DEFAULT_UPDATE_INTERVAL } = require('../src/utils/constants')
describe('gasPrice', () => { const utils = { setIntervalAndRun: sinon.spy() }
describe('start', () => { const fetchStub = () => ({
const utils = { setIntervalAndRun: sinon.spy() } json: () => ({
beforeEach(() => { standard: '103'
utils.setIntervalAndRun.resetHistory() })
}) })
it('should call setIntervalAndRun with ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL interval value on Home', async () => { const fakeLogger = { error: sinon.spy(), warn: sinon.spy(), child: () => fakeLogger }
// given fetchStub['@global'] = true
process.env.ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL = 15000 const gasPriceDefault = proxyquire('../src/services/gasPrice', {
const gasPrice = proxyquire('../src/services/gasPrice', { '../utils/utils': utils }) '../utils/utils': utils,
'node-fetch': fetchStub,
'../services/logger': { child: () => fakeLogger }
})
process.env.ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL = 15000
process.env.ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL = 30000
process.env.COMMON_HOME_GAS_PRICE_FALLBACK = '101000000000'
const gasPrice = proxyquire('../src/services/gasPrice', {
'../utils/utils': utils,
'node-fetch': fetchStub,
'../services/logger': { child: () => fakeLogger }
})
describe('gasPrice', () => {
beforeEach(() => {
utils.setIntervalAndRun.resetHistory()
fakeLogger.error.resetHistory()
fakeLogger.warn.resetHistory()
})
describe('start', () => {
it('should call setIntervalAndRun with ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL interval value on Home', async () => {
// when // when
await gasPrice.start('home') await gasPrice.start('home')
// then // then
expect(process.env.ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL).to.equal('15000')
expect(process.env.ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL).to.not.equal(DEFAULT_UPDATE_INTERVAL.toString())
expect(utils.setIntervalAndRun.args[0][1]).to.equal(process.env.ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL.toString()) expect(utils.setIntervalAndRun.args[0][1]).to.equal(process.env.ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL.toString())
}) })
it('should call setIntervalAndRun with ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL interval value on Foreign', async () => { it('should call setIntervalAndRun with ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL interval value on Foreign', async () => {
// given
process.env.ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL = 15000
const gasPrice = proxyquire('../src/services/gasPrice', { '../utils/utils': utils })
// when // when
await gasPrice.start('foreign') await gasPrice.start('foreign')
// then // then
expect(process.env.ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL).to.equal('15000')
expect(process.env.ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL).to.not.equal(DEFAULT_UPDATE_INTERVAL.toString())
expect(utils.setIntervalAndRun.args[0][1]).to.equal( expect(utils.setIntervalAndRun.args[0][1]).to.equal(
process.env.ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL.toString() process.env.ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL.toString()
) )
}) })
it('should call setIntervalAndRun with default interval value on Home', async () => { it('should call setIntervalAndRun with default interval value on Home', async () => {
// given
delete process.env.ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL
const gasPrice = proxyquire('../src/services/gasPrice', { '../utils/utils': utils })
// when // when
await gasPrice.start('home') await gasPriceDefault.start('home')
// then // then
expect(process.env.ORACLE_HOME_GAS_PRICE_UPDATE_INTERVAL).to.equal(undefined)
expect(utils.setIntervalAndRun.args[0][1]).to.equal(DEFAULT_UPDATE_INTERVAL) expect(utils.setIntervalAndRun.args[0][1]).to.equal(DEFAULT_UPDATE_INTERVAL)
}) })
it('should call setIntervalAndRun with default interval value on Foreign', async () => { it('should call setIntervalAndRun with default interval value on Foreign', async () => {
// given
delete process.env.ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL
const gasPrice = proxyquire('../src/services/gasPrice', { '../utils/utils': utils })
// when // when
await gasPrice.start('foreign') await gasPriceDefault.start('foreign')
// then // then
expect(process.env.ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL).to.equal(undefined)
expect(utils.setIntervalAndRun.args[0][1]).to.equal(DEFAULT_UPDATE_INTERVAL) expect(utils.setIntervalAndRun.args[0][1]).to.equal(DEFAULT_UPDATE_INTERVAL)
}) })
}) })
describe('fetching gas price', () => { describe('fetching gas price', () => {
const utils = { setIntervalAndRun: () => {} }
it('should fall back to default if contract and supplier are not working', async () => { it('should fall back to default if contract and supplier are not working', async () => {
// given // given
process.env.COMMON_HOME_GAS_PRICE_FALLBACK = '101000000000'
const gasPrice = proxyquire('../src/services/gasPrice', { '../utils/utils': utils })
await gasPrice.start('home') await gasPrice.start('home')
// when // when
await gasPrice.fetchGasPrice('standard', 1, null, () => null) await gasPrice.fetchGasPrice('standard', 1, null, null)
// then // then
expect(gasPrice.getPrice()).to.equal('101000000000') expect(gasPrice.getPrice()).to.equal('101000000000')
@ -81,18 +79,10 @@ describe('gasPrice', () => {
it('should fetch gas from supplier', async () => { it('should fetch gas from supplier', async () => {
// given // given
process.env.COMMON_HOME_GAS_PRICE_FALLBACK = '101000000000'
const gasPrice = proxyquire('../src/services/gasPrice', { '../utils/utils': utils })
await gasPrice.start('home') await gasPrice.start('home')
const gasPriceSupplierFetchFn = () => ({
json: () => ({
standard: '103'
})
})
// when // when
await gasPrice.fetchGasPrice('standard', 1, null, gasPriceSupplierFetchFn) await gasPrice.fetchGasPrice('standard', 1, null, 'url')
// then // then
expect(gasPrice.getPrice().toString()).to.equal('103000000000') expect(gasPrice.getPrice().toString()).to.equal('103000000000')
@ -100,8 +90,6 @@ describe('gasPrice', () => {
it('should fetch gas from contract', async () => { it('should fetch gas from contract', async () => {
// given // given
process.env.COMMON_HOME_GAS_PRICE_FALLBACK = '101000000000'
const gasPrice = proxyquire('../src/services/gasPrice', { '../utils/utils': utils })
await gasPrice.start('home') await gasPrice.start('home')
const bridgeContractMock = { const bridgeContractMock = {
@ -113,7 +101,7 @@ describe('gasPrice', () => {
} }
// when // when
await gasPrice.fetchGasPrice('standard', 1, bridgeContractMock, () => {}) await gasPrice.fetchGasPrice('standard', 1, bridgeContractMock, null)
// then // then
expect(gasPrice.getPrice().toString()).to.equal('102000000000') expect(gasPrice.getPrice().toString()).to.equal('102000000000')
@ -121,8 +109,6 @@ describe('gasPrice', () => {
it('should fetch the gas price from the oracle first', async () => { it('should fetch the gas price from the oracle first', async () => {
// given // given
process.env.COMMON_HOME_GAS_PRICE_FALLBACK = '101000000000'
const gasPrice = proxyquire('../src/services/gasPrice', { '../utils/utils': utils })
await gasPrice.start('home') await gasPrice.start('home')
const bridgeContractMock = { const bridgeContractMock = {
@ -133,33 +119,23 @@ describe('gasPrice', () => {
} }
} }
const gasPriceSupplierFetchFn = () => ({
json: () => ({
standard: '103'
})
})
// when // when
await gasPrice.fetchGasPrice('standard', 1, bridgeContractMock, gasPriceSupplierFetchFn) await gasPrice.fetchGasPrice('standard', 1, bridgeContractMock, 'url')
// then // then
expect(gasPrice.getPrice().toString()).to.equal('103000000000') expect(gasPrice.getPrice().toString()).to.equal('103000000000')
}) })
it('log errors using the logger', async () => { it('log error using the logger', async () => {
// given // given
const fakeLogger = { error: sinon.spy() }
const gasPrice = proxyquire('../src/services/gasPrice', {
'../utils/utils': utils,
'../services/logger': { child: () => fakeLogger }
})
await gasPrice.start('home') await gasPrice.start('home')
// when // when
await gasPrice.fetchGasPrice('standard', 1, null, () => {}) await gasPrice.fetchGasPrice('standard', 1, null, null)
// then // then
expect(fakeLogger.error.calledTwice).to.equal(true) // two errors expect(fakeLogger.warn.calledOnce).to.equal(true) // one warning
expect(fakeLogger.error.calledOnce).to.equal(true) // one error
}) })
}) })
}) })