Compare commits

...

4 Commits

Author SHA1 Message Date
ce515a8635
Improve contract fetching
Some checks failed
tokenbridge / initialize (push) Has been cancelled
tokenbridge / build-e2e-images (push) Has been cancelled
tokenbridge / build-molecule-runner (push) Has been cancelled
tokenbridge / validate (build) (push) Has been cancelled
tokenbridge / validate (lint) (push) Has been cancelled
tokenbridge / validate (test) (push) Has been cancelled
tokenbridge / e2e (alm-e2e, true) (push) Has been cancelled
tokenbridge / e2e (monitor-e2e) (push) Has been cancelled
tokenbridge / e2e (oracle-e2e) (push) Has been cancelled
tokenbridge / deployment (monitor) (push) Has been cancelled
tokenbridge / deployment (multiple) (push) Has been cancelled
tokenbridge / deployment (oracle) (push) Has been cancelled
tokenbridge / deployment (repo) (push) Has been cancelled
tokenbridge / ultimate (amb) (push) Has been cancelled
tokenbridge / ultimate (erc-to-native) (push) Has been cancelled
2024-05-08 23:45:31 +00:00
Alexander Kolotov
961b12b9f3
Naming convention for oracle (#661) 2022-10-28 14:07:02 +03:00
Alexander Kolotov
ff9f3fb7d6
Merge the develop branch to the master branch, preparation to v3.7.0
This merge contains the following set of changes:
  * [Oracle, Improvement] Periodic check for RPC sync state (#656)
2022-05-25 14:09:36 +03:00
Kirill Fedoseev
297cb67895
Periodic check for RPC sync state (#656) 2022-05-25 13:54:47 +03:00
13 changed files with 116 additions and 77 deletions

View File

@ -56,9 +56,11 @@ ORACLE_JSONRPC_ERROR_CODES | Override default JSON rpc error codes that can trig
ORACLE_HOME_EVENTS_REPROCESSING | If set to `true`, home events happened in the past will be refetched and processed once again, to ensure that nothing was missed on the first pass. | `bool` ORACLE_HOME_EVENTS_REPROCESSING | If set to `true`, home events happened in the past will be refetched and processed once again, to ensure that nothing was missed on the first pass. | `bool`
ORACLE_HOME_EVENTS_REPROCESSING_BATCH_SIZE | Batch size for one `eth_getLogs` request when reprocessing old logs in the home chain. Defaults to `1000` | `integer` ORACLE_HOME_EVENTS_REPROCESSING_BATCH_SIZE | Batch size for one `eth_getLogs` request when reprocessing old logs in the home chain. Defaults to `1000` | `integer`
ORACLE_HOME_EVENTS_REPROCESSING_BLOCK_DELAY | Block confirmations number, after which old logs are being reprocessed in the home chain. Defaults to `500` | `integer` ORACLE_HOME_EVENTS_REPROCESSING_BLOCK_DELAY | Block confirmations number, after which old logs are being reprocessed in the home chain. Defaults to `500` | `integer`
ORACLE_HOME_RPC_SYNC_STATE_CHECK_INTERVAL | Interval for checking JSON RPC sync state, by requesting the latest block number. Oracle will switch to the fallback JSON RPC in case sync process is stuck | `integer`
ORACLE_FOREIGN_EVENTS_REPROCESSING | If set to `true`, foreign events happened in the past will be refetched and processed once again, to ensure that nothing was missed on the first pass. | `bool` ORACLE_FOREIGN_EVENTS_REPROCESSING | If set to `true`, foreign events happened in the past will be refetched and processed once again, to ensure that nothing was missed on the first pass. | `bool`
ORACLE_FOREIGN_EVENTS_REPROCESSING_BATCH_SIZE | Batch size for one `eth_getLogs` request when reprocessing old logs in the foreign chain. Defaults to `500` | `integer` ORACLE_FOREIGN_EVENTS_REPROCESSING_BATCH_SIZE | Batch size for one `eth_getLogs` request when reprocessing old logs in the foreign chain. Defaults to `500` | `integer`
ORACLE_FOREIGN_EVENTS_REPROCESSING_BLOCK_DELAY | Block confirmations number, after which old logs are being reprocessed in the foreign chain. Defaults to `250` | `integer` ORACLE_FOREIGN_EVENTS_REPROCESSING_BLOCK_DELAY | Block confirmations number, after which old logs are being reprocessed in the foreign chain. Defaults to `250` | `integer`
ORACLE_FOREIGN_RPC_SYNC_STATE_CHECK_INTERVAL | Interval for checking JSON RPC sync state, by requesting the latest block number. Oracle will switch to the fallback JSON RPC in case sync process is stuck | `integer`
## Monitor configuration ## Monitor configuration

View File

@ -19,7 +19,7 @@ Sub-repositories maintained within this monorepo are listed below.
| Sub-repository | Description | | Sub-repository | Description |
| --- | --- | | --- | --- |
| [Oracle](oracle/README.md) | Oracle responsible for listening to bridge related events and authorizing asset transfers. | | [Oracle](oracle/README.md) | Responsible for listening to bridge related events and authorizing asset transfers. |
| [Monitor](monitor/README.md) | Tool for checking balances and unprocessed events in bridged networks. | | [Monitor](monitor/README.md) | Tool for checking balances and unprocessed events in bridged networks. |
| [Deployment](deployment/README.md) | Ansible playbooks for deploying cross-chain bridges. | | [Deployment](deployment/README.md) | Ansible playbooks for deploying cross-chain bridges. |
| [Oracle-E2E](oracle-e2e/README.md) | End to end tests for the Oracle | | [Oracle-E2E](oracle-e2e/README.md) | End to end tests for the Oracle |

View File

@ -22,6 +22,16 @@ export const getRequiredBlockConfirmations = async (
web3: Web3 | null = null, web3: Web3 | null = null,
api: string = '' api: string = ''
) => { ) => {
let blockConfirmations
try {
blockConfirmations = await contract.methods.requiredBlockConfirmations().call()
} catch {}
if (blockConfirmations) {
return parseInt(blockConfirmations)
}
const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber) const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber)
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber() const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
@ -35,16 +45,10 @@ export const getRequiredBlockConfirmations = async (
const events = [...eventsFromSnapshot, ...contractEvents] const events = [...eventsFromSnapshot, ...contractEvents]
let blockConfirmations
if (events.length > 0) {
// Use the value from last event before the transaction // Use the value from last event before the transaction
const event = events[events.length - 1] const event = events[events.length - 1]
blockConfirmations = event.returnValues.requiredBlockConfirmations blockConfirmations = event.returnValues.requiredBlockConfirmations
} else {
// This is a special case where RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB
// of Sokol - Kovan. In this case the current value is used.
blockConfirmations = await contract.methods.requiredBlockConfirmations().call()
}
return parseInt(blockConfirmations) return parseInt(blockConfirmations)
} }
@ -57,6 +61,16 @@ export const getRequiredSignatures = async (
web3: Web3 | null = null, web3: Web3 | null = null,
api: string = '' api: string = ''
) => { ) => {
let requiredSignatures
try {
requiredSignatures = await contract.methods.requiredSignatures().call()
} catch {}
if (requiredSignatures) {
return parseInt(requiredSignatures)
}
if (blockNumber === 'latest') { if (blockNumber === 'latest') {
return contract.methods.requiredSignatures().call() return contract.methods.requiredSignatures().call()
} }
@ -76,7 +90,7 @@ export const getRequiredSignatures = async (
// Use the value form last event before the transaction // Use the value form last event before the transaction
const event = events[events.length - 1] const event = events[events.length - 1]
const { requiredSignatures } = event.returnValues ;({ requiredSignatures } = event.returnValues)
return parseInt(requiredSignatures) return parseInt(requiredSignatures)
} }
@ -87,9 +101,13 @@ export const getValidatorList = async (
web3: Web3 | null = null, web3: Web3 | null = null,
api: string = '' api: string = ''
) => { ) => {
if (blockNumber === 'latest') { try {
return contract.methods.validatorList().call() const currentList = await contract.methods.validatorList().call()
if (currentList) {
return currentList
} }
} catch {}
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber) const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber) const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)

View File

@ -1,10 +1,10 @@
# POA TokenBridge / Oracle # POA TokenBridge / Oracle
Oracle responsible for listening to bridge related events and authorizing asset transfers. An oracle responsible for listening to bridge related events and authorizing asset transfers.
## Overview ## Overview
Please refer to the [POA TokenBridge](../README.md) overview first of all. Please refer to the [POA TokenBridge](../README.md) overview first of all.
The Oracle is deployed on specified validator nodes (only nodes whose private keys correspond to addresses specified in the smart contracts) in the network. It connects to two chains via a Remote Procedure Call (RPC) and is responsible for: The oracle is deployed on specified validator nodes (only nodes whose private keys correspond to addresses specified in the smart contracts) in the network. It connects to two chains via a Remote Procedure Call (RPC) and is responsible for:
- listening to events related to bridge contracts - listening to events related to bridge contracts
- sending transactions to authorize asset transfers - sending transactions to authorize asset transfers
@ -69,7 +69,7 @@ For more information on the Redis/RabbitMQ requirements, see [#90](/../../issues
} }
``` ```
## Install and configure the Oracle ## Install and configure the oracle
1. [Initialize](../README.md#initializing-the-monorepository) the monorepository. 1. [Initialize](../README.md#initializing-the-monorepository) the monorepository.

View File

@ -7,7 +7,15 @@ const {
HOME_AMB_ABI, HOME_AMB_ABI,
FOREIGN_AMB_ABI FOREIGN_AMB_ABI
} = require('../../commons') } = require('../../commons')
const { web3Home, web3Foreign } = require('../src/services/web3') const {
web3Home,
web3Foreign,
web3HomeRedundant,
web3HomeFallback,
web3ForeignRedundant,
web3ForeignFallback,
web3ForeignArchive
} = require('../src/services/web3')
const { add0xPrefix, privateKeyToAddress } = require('../src/utils/utils') const { add0xPrefix, privateKeyToAddress } = require('../src/utils/utils')
const { EXIT_CODES } = require('../src/utils/constants') const { EXIT_CODES } = require('../src/utils/constants')
@ -27,9 +35,11 @@ const {
ORACLE_HOME_EVENTS_REPROCESSING, ORACLE_HOME_EVENTS_REPROCESSING,
ORACLE_HOME_EVENTS_REPROCESSING_BATCH_SIZE, ORACLE_HOME_EVENTS_REPROCESSING_BATCH_SIZE,
ORACLE_HOME_EVENTS_REPROCESSING_BLOCK_DELAY, ORACLE_HOME_EVENTS_REPROCESSING_BLOCK_DELAY,
ORACLE_HOME_RPC_SYNC_STATE_CHECK_INTERVAL,
ORACLE_FOREIGN_EVENTS_REPROCESSING, ORACLE_FOREIGN_EVENTS_REPROCESSING,
ORACLE_FOREIGN_EVENTS_REPROCESSING_BATCH_SIZE, ORACLE_FOREIGN_EVENTS_REPROCESSING_BATCH_SIZE,
ORACLE_FOREIGN_EVENTS_REPROCESSING_BLOCK_DELAY ORACLE_FOREIGN_EVENTS_REPROCESSING_BLOCK_DELAY,
ORACLE_FOREIGN_RPC_SYNC_STATE_CHECK_INTERVAL
} = process.env } = process.env
let homeAbi let homeAbi
@ -63,9 +73,12 @@ const homeConfig = {
bridgeAddress: COMMON_HOME_BRIDGE_ADDRESS, bridgeAddress: COMMON_HOME_BRIDGE_ADDRESS,
bridgeABI: homeAbi, bridgeABI: homeAbi,
pollingInterval: parseInt(ORACLE_HOME_RPC_POLLING_INTERVAL, 10), pollingInterval: parseInt(ORACLE_HOME_RPC_POLLING_INTERVAL, 10),
syncCheckInterval: parseInt(ORACLE_HOME_RPC_SYNC_STATE_CHECK_INTERVAL, 10) || 60000,
startBlock: parseInt(ORACLE_HOME_START_BLOCK, 10) || 0, startBlock: parseInt(ORACLE_HOME_START_BLOCK, 10) || 0,
blockPollingLimit: parseInt(ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT, 10), blockPollingLimit: parseInt(ORACLE_HOME_RPC_BLOCK_POLLING_LIMIT, 10),
web3: web3Home, web3: web3Home,
web3Redundant: web3HomeRedundant,
web3Fallback: web3HomeFallback,
bridgeContract: homeContract, bridgeContract: homeContract,
eventContract: homeContract, eventContract: homeContract,
reprocessingOptions: { reprocessingOptions: {
@ -81,9 +94,13 @@ const foreignConfig = {
bridgeAddress: COMMON_FOREIGN_BRIDGE_ADDRESS, bridgeAddress: COMMON_FOREIGN_BRIDGE_ADDRESS,
bridgeABI: foreignAbi, bridgeABI: foreignAbi,
pollingInterval: parseInt(ORACLE_FOREIGN_RPC_POLLING_INTERVAL, 10), pollingInterval: parseInt(ORACLE_FOREIGN_RPC_POLLING_INTERVAL, 10),
syncCheckInterval: parseInt(ORACLE_FOREIGN_RPC_SYNC_STATE_CHECK_INTERVAL, 10) || 60000,
startBlock: parseInt(ORACLE_FOREIGN_START_BLOCK, 10) || 0, startBlock: parseInt(ORACLE_FOREIGN_START_BLOCK, 10) || 0,
blockPollingLimit: parseInt(ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT, 10), blockPollingLimit: parseInt(ORACLE_FOREIGN_RPC_BLOCK_POLLING_LIMIT, 10),
web3: web3Foreign, web3: web3Foreign,
web3Redundant: web3ForeignRedundant,
web3Fallback: web3ForeignFallback,
web3Archive: web3ForeignArchive || web3Foreign,
bridgeContract: foreignContract, bridgeContract: foreignContract,
eventContract: foreignContract, eventContract: foreignContract,
reprocessingOptions: { reprocessingOptions: {

View File

@ -1,17 +1,14 @@
const baseConfig = require('./base.config') const baseConfig = require('./base.config')
const { DEFAULT_TRANSACTION_RESEND_INTERVAL } = require('../src/utils/constants') const { DEFAULT_TRANSACTION_RESEND_INTERVAL } = require('../src/utils/constants')
const { web3Foreign, web3ForeignRedundant, web3ForeignFallback } = require('../src/services/web3')
const { ORACLE_FOREIGN_TX_RESEND_INTERVAL } = process.env const { ORACLE_FOREIGN_TX_RESEND_INTERVAL } = process.env
module.exports = { module.exports = {
...baseConfig, ...baseConfig,
main: baseConfig.foreign,
queue: 'foreign-prioritized', queue: 'foreign-prioritized',
id: 'foreign', id: 'foreign',
name: 'sender-foreign', name: 'sender-foreign',
web3: web3Foreign,
web3Redundant: web3ForeignRedundant,
web3Fallback: web3ForeignFallback,
resendInterval: parseInt(ORACLE_FOREIGN_TX_RESEND_INTERVAL, 10) || DEFAULT_TRANSACTION_RESEND_INTERVAL resendInterval: parseInt(ORACLE_FOREIGN_TX_RESEND_INTERVAL, 10) || DEFAULT_TRANSACTION_RESEND_INTERVAL
} }

View File

@ -1,17 +1,14 @@
const baseConfig = require('./base.config') const baseConfig = require('./base.config')
const { DEFAULT_TRANSACTION_RESEND_INTERVAL } = require('../src/utils/constants') const { DEFAULT_TRANSACTION_RESEND_INTERVAL } = require('../src/utils/constants')
const { web3Home, web3HomeRedundant, web3HomeFallback } = require('../src/services/web3')
const { ORACLE_HOME_TX_RESEND_INTERVAL } = process.env const { ORACLE_HOME_TX_RESEND_INTERVAL } = process.env
module.exports = { module.exports = {
...baseConfig, ...baseConfig,
main: baseConfig.home,
queue: 'home-prioritized', queue: 'home-prioritized',
id: 'home', id: 'home',
name: 'sender-home', name: 'sender-home',
web3: web3Home,
web3Redundant: web3HomeRedundant,
web3Fallback: web3HomeFallback,
resendInterval: parseInt(ORACLE_HOME_TX_RESEND_INTERVAL, 10) || DEFAULT_TRANSACTION_RESEND_INTERVAL resendInterval: parseInt(ORACLE_HOME_TX_RESEND_INTERVAL, 10) || DEFAULT_TRANSACTION_RESEND_INTERVAL
} }

View File

@ -1,11 +1,9 @@
const baseConfig = require('./base.config') const baseConfig = require('./base.config')
const { web3ForeignArchive } = require('../src/services/web3')
const id = `${baseConfig.id}-information-request` const id = `${baseConfig.id}-information-request`
module.exports = { module.exports = {
...baseConfig, ...baseConfig,
web3ForeignArchive: web3ForeignArchive || baseConfig.foreign.web3,
main: baseConfig.home, main: baseConfig.home,
event: 'UserRequestForInformation', event: 'UserRequestForInformation',
sender: 'home', sender: 'home',

View File

@ -35,11 +35,13 @@ Object.keys(asyncCalls).forEach(method => {
}) })
function processInformationRequestsBuilder(config) { function processInformationRequestsBuilder(config) {
const { home, foreign, web3ForeignArchive } = config const { home, foreign } = config
let validatorContract = null let validatorContract = null
let blockFinder = null let blockFinder = null
foreign.web3Archive.currentProvider.startSyncStateChecker(foreign.syncCheckInterval)
return async function processInformationRequests(informationRequests) { return async function processInformationRequests(informationRequests) {
const txToSend = [] const txToSend = []
@ -49,13 +51,15 @@ function processInformationRequestsBuilder(config) {
if (blockFinder === null) { if (blockFinder === null) {
rootLogger.debug('Initializing block finder') rootLogger.debug('Initializing block finder')
blockFinder = await makeBlockFinder('foreign', foreign.web3) blockFinder = await makeBlockFinder('foreign', foreign.web3Archive)
} }
// latest foreign block is requested from an archive RPC, to ensure that it is synced with the network
// block confirmations can be requested from the regular JSON RPC
const foreignBlockNumber = const foreignBlockNumber =
(await getBlockNumber(foreign.web3)) - (await getRequiredBlockConfirmations(foreign.bridgeContract)) (await getBlockNumber(foreign.web3Archive)) - (await getRequiredBlockConfirmations(foreign.bridgeContract))
const homeBlock = await getBlock(home.web3, informationRequests[0].blockNumber) const homeBlock = await getBlock(home.web3, informationRequests[0].blockNumber)
const lastForeignBlock = await getBlock(foreign.web3, foreignBlockNumber) const lastForeignBlock = await getBlock(foreign.web3Archive, foreignBlockNumber)
if (homeBlock.timestamp > lastForeignBlock.timestamp) { if (homeBlock.timestamp > lastForeignBlock.timestamp) {
rootLogger.debug( rootLogger.debug(
@ -85,7 +89,7 @@ function processInformationRequestsBuilder(config) {
logger.info({ requestSelector, method: asyncCallMethod, data }, 'Processing async request') logger.info({ requestSelector, method: asyncCallMethod, data }, 'Processing async request')
const call = asyncCalls[asyncCallMethod] const call = asyncCalls[asyncCallMethod]
let [status, result] = await call(web3ForeignArchive, data, foreignClosestBlock).catch(e => { let [status, result] = await call(foreign.web3Archive, data, foreignClosestBlock).catch(e => {
if (e instanceof HttpListProviderError) { if (e instanceof HttpListProviderError) {
throw e throw e
} }

View File

@ -32,8 +32,8 @@ if (process.argv.length < 3) {
const config = require(path.join('../config/', process.argv[2])) const config = require(path.join('../config/', process.argv[2]))
const { web3, web3Fallback } = config const { web3, web3Fallback, syncCheckInterval } = config.main
const web3Redundant = ORACLE_TX_REDUNDANCY === 'true' ? config.web3Redundant : web3 const web3Redundant = ORACLE_TX_REDUNDANCY === 'true' ? config.main.web3Redundant : web3
const nonceKey = `${config.id}:nonce` const nonceKey = `${config.id}:nonce`
let chainId = 0 let chainId = 0
@ -43,6 +43,7 @@ async function initialize() {
const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger) const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger)
web3.currentProvider.urls.forEach(checkHttps(config.id)) web3.currentProvider.urls.forEach(checkHttps(config.id))
web3.currentProvider.startSyncStateChecker(syncCheckInterval)
GasPrice.start(config.id, web3) GasPrice.start(config.id, web3)

View File

@ -1,5 +1,6 @@
const fetch = require('node-fetch') const fetch = require('node-fetch')
const promiseRetry = require('promise-retry') const promiseRetry = require('promise-retry')
const { utils } = require('web3')
const { FALLBACK_RPC_URL_SWITCH_TIMEOUT } = require('../utils/constants') const { FALLBACK_RPC_URL_SWITCH_TIMEOUT } = require('../utils/constants')
const { onInjected } = require('./injectedLogger') const { onInjected } = require('./injectedLogger')
@ -39,19 +40,54 @@ function HttpListProvider(urls, options = {}) {
this.options = { ...defaultOptions, ...options } this.options = { ...defaultOptions, ...options }
this.currentIndex = 0 this.currentIndex = 0
this.lastTimeUsedPrimary = 0 this.lastTimeUsedPrimary = 0
this.latestBlock = 0
this.syncStateCheckerIntervalId = 0
onInjected(logger => { onInjected(logger => {
this.logger = logger.child({ module: `HttpListProvider:${this.options.name}` }) this.logger = logger.child({ module: `HttpListProvider:${this.options.name}` })
}) })
} }
HttpListProvider.prototype.switchToFallbackRPC = function() { HttpListProvider.prototype.startSyncStateChecker = function(syncCheckInterval) {
if (this.urls.length < 2) { if (this.urls.length > 1 && syncCheckInterval > 0 && this.syncStateCheckerIntervalId === 0) {
this.syncStateCheckerIntervalId = setInterval(this.checkLatestBlock.bind(this), syncCheckInterval)
}
}
HttpListProvider.prototype.checkLatestBlock = function() {
const payload = { jsonrpc: '2.0', id: 1, method: 'eth_blockNumber', params: [] }
this.send(payload, (error, result) => {
if (error) {
this.logger.warn({ oldBlock: this.latestBlock }, 'Failed to request latest block from all RPC urls')
} else if (result.error) {
this.logger.warn(
{ oldBlock: this.latestBlock, error: result.error.message },
'Failed to make eth_blockNumber request due to unknown error, switching to fallback RPC'
)
this.switchToFallbackRPC()
} else {
const blockNumber = utils.hexToNumber(result.result)
if (blockNumber > this.latestBlock) {
this.logger.debug({ oldBlock: this.latestBlock, newBlock: blockNumber }, 'Updating latest block number')
this.latestBlock = blockNumber
} else {
this.logger.warn(
{ oldBlock: this.latestBlock, newBlock: blockNumber },
'Latest block on the node was not updated since last request, switching to fallback RPC'
)
this.switchToFallbackRPC()
}
}
})
}
HttpListProvider.prototype.switchToFallbackRPC = function(index) {
const prevIndex = this.currentIndex
const newIndex = index || (prevIndex + 1) % this.urls.length
if (this.urls.length < 2 || prevIndex === newIndex) {
return return
} }
const prevIndex = this.currentIndex
const newIndex = (prevIndex + 1) % this.urls.length
this.logger.info( this.logger.info(
{ index: newIndex, oldURL: this.urls[prevIndex], newURL: this.urls[newIndex] }, { index: newIndex, oldURL: this.urls[prevIndex], newURL: this.urls[newIndex] },
'Switching to fallback JSON-RPC URL' 'Switching to fallback JSON-RPC URL'
@ -80,11 +116,7 @@ HttpListProvider.prototype.send = async function send(payload, callback) {
// if some of URLs failed to respond, current URL index is updated to the first URL that responded // if some of URLs failed to respond, current URL index is updated to the first URL that responded
if (currentIndex !== index) { if (currentIndex !== index) {
this.logger.info( this.switchToFallbackRPC(index)
{ index, oldURL: this.urls[currentIndex], newURL: this.urls[index] },
'Switching to fallback JSON-RPC URL'
)
this.currentIndex = index
} }
callback(null, result) callback(null, result)
} catch (e) { } catch (e) {

View File

@ -27,7 +27,6 @@ module.exports = {
MIN_GAS_PRICE_BUMP_FACTOR: 0.1, MIN_GAS_PRICE_BUMP_FACTOR: 0.1,
DEFAULT_TRANSACTION_RESEND_INTERVAL: 20 * 60 * 1000, DEFAULT_TRANSACTION_RESEND_INTERVAL: 20 * 60 * 1000,
FALLBACK_RPC_URL_SWITCH_TIMEOUT: 60 * 60 * 1000, FALLBACK_RPC_URL_SWITCH_TIMEOUT: 60 * 60 * 1000,
BLOCK_NUMBER_PROGRESS_ITERATIONS_LIMIT: 10,
SENDER_QUEUE_MAX_PRIORITY: 10, SENDER_QUEUE_MAX_PRIORITY: 10,
SENDER_QUEUE_SEND_PRIORITY: 5, SENDER_QUEUE_SEND_PRIORITY: 5,
SENDER_QUEUE_CHECK_STATUS_PRIORITY: 1, SENDER_QUEUE_CHECK_STATUS_PRIORITY: 1,

View File

@ -6,11 +6,7 @@ const logger = require('./services/logger')
const { getShutdownFlag } = require('./services/shutdownState') const { getShutdownFlag } = require('./services/shutdownState')
const { getBlockNumber, getRequiredBlockConfirmations, getEvents } = require('./tx/web3') const { getBlockNumber, getRequiredBlockConfirmations, getEvents } = require('./tx/web3')
const { checkHTTPS, watchdog } = require('./utils/utils') const { checkHTTPS, watchdog } = require('./utils/utils')
const { const { EXIT_CODES, MAX_HISTORY_BLOCK_TO_REPROCESS } = require('./utils/constants')
EXIT_CODES,
BLOCK_NUMBER_PROGRESS_ITERATIONS_LIMIT,
MAX_HISTORY_BLOCK_TO_REPROCESS
} = require('./utils/constants')
if (process.argv.length < 3) { if (process.argv.length < 3) {
logger.error('Please check the number of arguments, config file was not provided') logger.error('Please check the number of arguments, config file was not provided')
@ -38,21 +34,21 @@ const {
pollingInterval, pollingInterval,
chain, chain,
reprocessingOptions, reprocessingOptions,
blockPollingLimit blockPollingLimit,
syncCheckInterval
} = config.main } = config.main
const lastBlockRedisKey = `${config.id}:lastProcessedBlock` const lastBlockRedisKey = `${config.id}:lastProcessedBlock`
const lastReprocessedBlockRedisKey = `${config.id}:lastReprocessedBlock` const lastReprocessedBlockRedisKey = `${config.id}:lastReprocessedBlock`
const seenEventsRedisKey = `${config.id}:seenEvents` const seenEventsRedisKey = `${config.id}:seenEvents`
let lastProcessedBlock = Math.max(startBlock - 1, 0) let lastProcessedBlock = Math.max(startBlock - 1, 0)
let lastReprocessedBlock let lastReprocessedBlock
let lastSeenBlockNumber = 0
let sameBlockNumberCounter = 0
async function initialize() { async function initialize() {
try { try {
const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger) const checkHttps = checkHTTPS(process.env.ORACLE_ALLOW_HTTP_FOR_RPC, logger)
web3.currentProvider.urls.forEach(checkHttps(chain)) web3.currentProvider.urls.forEach(checkHttps(chain))
web3.currentProvider.startSyncStateChecker(syncCheckInterval)
await getLastProcessedBlock() await getLastProcessedBlock()
await getLastReprocessedBlock() await getLastReprocessedBlock()
@ -225,28 +221,6 @@ async function getLastBlockToProcess(web3, bridgeContract) {
getBlockNumber(web3), getBlockNumber(web3),
getRequiredBlockConfirmations(bridgeContract) getRequiredBlockConfirmations(bridgeContract)
]) ])
if (lastBlockNumber < lastSeenBlockNumber) {
sameBlockNumberCounter = 0
logger.warn({ lastBlockNumber, lastSeenBlockNumber }, 'Received block number less than already seen block')
web3.currentProvider.switchToFallbackRPC()
} else if (lastBlockNumber === lastSeenBlockNumber) {
sameBlockNumberCounter++
if (sameBlockNumberCounter > 1) {
logger.info({ lastBlockNumber, sameBlockNumberCounter }, 'Received the same block number more than twice')
if (sameBlockNumberCounter >= BLOCK_NUMBER_PROGRESS_ITERATIONS_LIMIT) {
sameBlockNumberCounter = 0
logger.warn(
{ lastBlockNumber, n: BLOCK_NUMBER_PROGRESS_ITERATIONS_LIMIT },
'Received the same block number for too many times. Probably node is not synced anymore'
)
web3.currentProvider.switchToFallbackRPC()
}
}
} else {
sameBlockNumberCounter = 0
lastSeenBlockNumber = lastBlockNumber
}
return lastBlockNumber - requiredBlockConfirmations return lastBlockNumber - requiredBlockConfirmations
} }