Compare commits
6 Commits
2.7.0-rc0
...
fix/monito
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c94fd93c2d | ||
|
|
ae83c76be9 | ||
|
|
dc3026e584 | ||
|
|
b6ba0744b9 | ||
|
|
4dba9a50e8 | ||
|
|
818bc4675d |
@@ -42,6 +42,8 @@ ORACLE_HOME_TO_FOREIGN_BLOCK_LIST | Filename with a list of addresses, separated
|
|||||||
ORACLE_HOME_TO_FOREIGN_CHECK_SENDER | If set to `true`, instructs the oracle to do an extra check for transaction origin in the block/allowance list. `false` by default. | `true` / `false`
|
ORACLE_HOME_TO_FOREIGN_CHECK_SENDER | If set to `true`, instructs the oracle to do an extra check for transaction origin in the block/allowance list. `false` by default. | `true` / `false`
|
||||||
ORACLE_ALWAYS_RELAY_SIGNATURES | If set to `true`, the oracle will always relay signatures even if it was not the last who finilized the signatures collecting process. The default is `false`. | `true` / `false`
|
ORACLE_ALWAYS_RELAY_SIGNATURES | If set to `true`, the oracle will always relay signatures even if it was not the last who finilized the signatures collecting process. The default is `false`. | `true` / `false`
|
||||||
ORACLE_RPC_REQUEST_TIMEOUT | Timeout in milliseconds for a single RPC request. Default value is `ORACLE_*_RPC_POLLING_INTERVAL * 2`. | integer
|
ORACLE_RPC_REQUEST_TIMEOUT | Timeout in milliseconds for a single RPC request. Default value is `ORACLE_*_RPC_POLLING_INTERVAL * 2`. | integer
|
||||||
|
ORACLE_HOME_TX_RESEND_INTERVAL | Interval in milliseconds for automatic resending of stuck transactions for Home sender service. Defaults to 20 minutes. | integer
|
||||||
|
ORACLE_FOREIGN_TX_RESEND_INTERVAL | Interval in milliseconds for automatic resending of stuck transactions for Foreign sender service. Defaults to 20 minutes. | integer
|
||||||
|
|
||||||
|
|
||||||
## UI configuration
|
## UI configuration
|
||||||
@@ -84,3 +86,5 @@ MONITOR_HOME_TO_FOREIGN_BLOCK_LIST | File with a list of addresses, separated by
|
|||||||
MONITOR_HOME_TO_FOREIGN_CHECK_SENDER | If set to `true`, instructs the oracle to do an extra check for transaction origin in the block/allowance list. `false` by default. | `true` / `false`
|
MONITOR_HOME_TO_FOREIGN_CHECK_SENDER | If set to `true`, instructs the oracle to do an extra check for transaction origin in the block/allowance list. `false` by default. | `true` / `false`
|
||||||
MONITOR_HOME_VALIDATORS_BALANCE_ENABLE | If set, defines the list of home validator addresses for which balance should be checked. | `string`
|
MONITOR_HOME_VALIDATORS_BALANCE_ENABLE | If set, defines the list of home validator addresses for which balance should be checked. | `string`
|
||||||
MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE | If set, defines the list of foreign validator addresses for which balance should be checked. | `string`
|
MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE | If set, defines the list of foreign validator addresses for which balance should be checked. | `string`
|
||||||
|
MONITOR_HOME_EXPLORER_API | The HTTPS URL of the Home network explorer API. If set, may be used as a fallback in case of the RPC node failure. | URL
|
||||||
|
MONITOR_FOREIGN_EXPLORER_API | The HTTPS URL of the Foreign network explorer API. If set, may be used as a fallback in case of the RPC node failure. | URL
|
||||||
@@ -19,7 +19,7 @@ COPY --from=contracts /mono/contracts/build ./contracts/build
|
|||||||
COPY commons/package.json ./commons/
|
COPY commons/package.json ./commons/
|
||||||
COPY alm/package.json ./alm/
|
COPY alm/package.json ./alm/
|
||||||
COPY yarn.lock .
|
COPY yarn.lock .
|
||||||
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile --production
|
RUN NOYARNPOSTINSTALL=1 yarn install --frozen-lockfile
|
||||||
|
|
||||||
COPY ./commons ./commons
|
COPY ./commons ./commons
|
||||||
COPY ./alm ./alm
|
COPY ./alm ./alm
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint-plugin-prettier": "^3.1.3"
|
"eslint-plugin-prettier": "^3.1.3",
|
||||||
|
"node-fetch": "^2.6.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ const { BRIDGE_VALIDATORS_ABI, HOME_AMB_ABI } = require('commons')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const Web3 = require('web3')
|
const Web3 = require('web3')
|
||||||
|
const fetch = require('node-fetch')
|
||||||
|
const { URL } = require('url')
|
||||||
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
|
|
||||||
@@ -10,7 +12,9 @@ const {
|
|||||||
COMMON_HOME_RPC_URL,
|
COMMON_HOME_RPC_URL,
|
||||||
COMMON_HOME_BRIDGE_ADDRESS,
|
COMMON_HOME_BRIDGE_ADDRESS,
|
||||||
COMMON_FOREIGN_RPC_URL,
|
COMMON_FOREIGN_RPC_URL,
|
||||||
COMMON_FOREIGN_BRIDGE_ADDRESS
|
COMMON_FOREIGN_BRIDGE_ADDRESS,
|
||||||
|
ALM_FOREIGN_EXPLORER_API,
|
||||||
|
ALM_HOME_EXPLORER_API
|
||||||
} = process.env
|
} = process.env
|
||||||
|
|
||||||
const generateSnapshot = async (side, url, bridgeAddress) => {
|
const generateSnapshot = async (side, url, bridgeAddress) => {
|
||||||
@@ -19,6 +23,31 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
const snapshot = {}
|
const snapshot = {}
|
||||||
|
|
||||||
const web3 = new Web3(new Web3.providers.HttpProvider(url))
|
const web3 = new Web3(new Web3.providers.HttpProvider(url))
|
||||||
|
const api = side === 'home' ? ALM_HOME_EXPLORER_API : ALM_FOREIGN_EXPLORER_API
|
||||||
|
|
||||||
|
const getPastEventsWithFallback = (contract, eventName, options) =>
|
||||||
|
contract.getPastEvents(eventName, options).catch(async e => {
|
||||||
|
if (e.message.includes('exceed maximum block range')) {
|
||||||
|
const abi = contract.options.jsonInterface.find(abi => abi.type === 'event' && abi.name === eventName)
|
||||||
|
|
||||||
|
const url = new URL(api)
|
||||||
|
url.searchParams.append('module', 'logs')
|
||||||
|
url.searchParams.append('action', 'getLogs')
|
||||||
|
url.searchParams.append('address', contract.options.address)
|
||||||
|
url.searchParams.append('fromBlock', options.fromBlock)
|
||||||
|
url.searchParams.append('toBlock', options.toBlock || 'latest')
|
||||||
|
url.searchParams.append('topic0', web3.eth.abi.encodeEventSignature(abi))
|
||||||
|
|
||||||
|
const logs = await fetch(url).then(res => res.json())
|
||||||
|
|
||||||
|
return logs.result.map(log => ({
|
||||||
|
transactionHash: log.transactionHash,
|
||||||
|
blockNumber: parseInt(log.blockNumber.slice(2), 16),
|
||||||
|
returnValues: web3.eth.abi.decodeLog(abi.inputs, log.data, log.topics.slice(1))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
throw e
|
||||||
|
})
|
||||||
|
|
||||||
const currentBlockNumber = await web3.eth.getBlockNumber()
|
const currentBlockNumber = await web3.eth.getBlockNumber()
|
||||||
snapshot.snapshotBlockNumber = currentBlockNumber
|
snapshot.snapshotBlockNumber = currentBlockNumber
|
||||||
@@ -29,10 +58,14 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
const bridgeContract = new web3.eth.Contract(HOME_AMB_ABI, bridgeAddress)
|
const bridgeContract = new web3.eth.Contract(HOME_AMB_ABI, bridgeAddress)
|
||||||
|
|
||||||
// Save RequiredBlockConfirmationChanged events
|
// Save RequiredBlockConfirmationChanged events
|
||||||
let requiredBlockConfirmationChangedEvents = await bridgeContract.getPastEvents('RequiredBlockConfirmationChanged', {
|
let requiredBlockConfirmationChangedEvents = await getPastEventsWithFallback(
|
||||||
fromBlock: 0,
|
bridgeContract,
|
||||||
toBlock: currentBlockNumber
|
'RequiredBlockConfirmationChanged',
|
||||||
})
|
{
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: currentBlockNumber
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// In case RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB
|
// In case RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB
|
||||||
// manually generate an event for this. Example Sokol - Kovan bridge
|
// manually generate an event for this. Example Sokol - Kovan bridge
|
||||||
@@ -59,10 +92,14 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorAddress)
|
const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorAddress)
|
||||||
|
|
||||||
// Save RequiredSignaturesChanged events
|
// Save RequiredSignaturesChanged events
|
||||||
const RequiredSignaturesChangedEvents = await validatorContract.getPastEvents('RequiredSignaturesChanged', {
|
const RequiredSignaturesChangedEvents = await getPastEventsWithFallback(
|
||||||
fromBlock: 0,
|
validatorContract,
|
||||||
toBlock: currentBlockNumber
|
'RequiredSignaturesChanged',
|
||||||
})
|
{
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: currentBlockNumber
|
||||||
|
}
|
||||||
|
)
|
||||||
snapshot.RequiredSignaturesChanged = RequiredSignaturesChangedEvents.map(e => ({
|
snapshot.RequiredSignaturesChanged = RequiredSignaturesChangedEvents.map(e => ({
|
||||||
blockNumber: e.blockNumber,
|
blockNumber: e.blockNumber,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -71,7 +108,7 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
// Save ValidatorAdded events
|
// Save ValidatorAdded events
|
||||||
const validatorAddedEvents = await validatorContract.getPastEvents('ValidatorAdded', {
|
const validatorAddedEvents = await getPastEventsWithFallback(validatorContract, 'ValidatorAdded', {
|
||||||
fromBlock: 0,
|
fromBlock: 0,
|
||||||
toBlock: currentBlockNumber
|
toBlock: currentBlockNumber
|
||||||
})
|
})
|
||||||
@@ -85,7 +122,7 @@ const generateSnapshot = async (side, url, bridgeAddress) => {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
// Save ValidatorRemoved events
|
// Save ValidatorRemoved events
|
||||||
const validatorRemovedEvents = await validatorContract.getPastEvents('ValidatorRemoved', {
|
const validatorRemovedEvents = await getPastEventsWithFallback(validatorContract, 'ValidatorRemoved', {
|
||||||
fromBlock: 0,
|
fromBlock: 0,
|
||||||
toBlock: currentBlockNumber
|
toBlock: currentBlockNumber
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
DOUBLE_EXECUTION_ATTEMPT_ERROR,
|
DOUBLE_EXECUTION_ATTEMPT_ERROR,
|
||||||
EXECUTION_FAILED_ERROR,
|
EXECUTION_FAILED_ERROR,
|
||||||
EXECUTION_OUT_OF_GAS_ERROR,
|
EXECUTION_OUT_OF_GAS_ERROR,
|
||||||
|
FOREIGN_EXPLORER_API,
|
||||||
INCORRECT_CHAIN_ERROR,
|
INCORRECT_CHAIN_ERROR,
|
||||||
VALIDATOR_CONFIRMATION_STATUS
|
VALIDATOR_CONFIRMATION_STATUS
|
||||||
} from '../config/constants'
|
} from '../config/constants'
|
||||||
@@ -92,7 +93,13 @@ export const ManualExecutionButton = ({
|
|||||||
})
|
})
|
||||||
.on('error', async (e: Error, receipt: TransactionReceipt) => {
|
.on('error', async (e: Error, receipt: TransactionReceipt) => {
|
||||||
if (e.message.includes('Transaction has been reverted by the EVM')) {
|
if (e.message.includes('Transaction has been reverted by the EVM')) {
|
||||||
const successExecutionData = await getSuccessExecutionData(bridge, 'RelayedMessage', library, messageId)
|
const successExecutionData = await getSuccessExecutionData(
|
||||||
|
bridge,
|
||||||
|
'RelayedMessage',
|
||||||
|
library,
|
||||||
|
messageId,
|
||||||
|
FOREIGN_EXPLORER_API
|
||||||
|
)
|
||||||
if (successExecutionData) {
|
if (successExecutionData) {
|
||||||
setExecutionData(successExecutionData)
|
setExecutionData(successExecutionData)
|
||||||
setError(DOUBLE_EXECUTION_ATTEMPT_ERROR)
|
setError(DOUBLE_EXECUTION_ATTEMPT_ERROR)
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { useStateProvider } from '../state/StateProvider'
|
|||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { getRequiredBlockConfirmations } from '../utils/contract'
|
import { getRequiredBlockConfirmations } from '../utils/contract'
|
||||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
|
import Web3 from 'web3'
|
||||||
|
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
||||||
|
|
||||||
export interface UseBlockConfirmationsParams {
|
export interface UseBlockConfirmationsParams {
|
||||||
fromHome: boolean
|
fromHome: boolean
|
||||||
@@ -19,9 +21,11 @@ export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmatio
|
|||||||
contract: Contract,
|
contract: Contract,
|
||||||
receipt: TransactionReceipt,
|
receipt: TransactionReceipt,
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
snapshotProvider: SnapshotProvider
|
snapshotProvider: SnapshotProvider,
|
||||||
|
web3: Web3,
|
||||||
|
api: string
|
||||||
) => {
|
) => {
|
||||||
const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber, snapshotProvider)
|
const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,10 +33,12 @@ export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmatio
|
|||||||
() => {
|
() => {
|
||||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||||
if (!bridgeContract || !receipt) return
|
const web3 = fromHome ? home.web3 : foreign.web3
|
||||||
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations, snapshotProvider)
|
const api = fromHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
||||||
|
if (!bridgeContract || !receipt || !web3) return
|
||||||
|
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations, snapshotProvider, web3, api)
|
||||||
},
|
},
|
||||||
[home.bridgeContract, foreign.bridgeContract, receipt, fromHome]
|
[home.bridgeContract, foreign.bridgeContract, receipt, fromHome, home.web3, foreign.web3]
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ import {
|
|||||||
VALIDATOR_CONFIRMATION_STATUS
|
VALIDATOR_CONFIRMATION_STATUS
|
||||||
} from '../config/constants'
|
} from '../config/constants'
|
||||||
import { homeBlockNumberProvider, foreignBlockNumberProvider } from '../services/BlockNumberProvider'
|
import { homeBlockNumberProvider, foreignBlockNumberProvider } from '../services/BlockNumberProvider'
|
||||||
import { checkSignaturesWaitingForBLocks } from '../utils/signatureWaitingForBlocks'
|
|
||||||
import { getCollectedSignaturesEvent } from '../utils/getCollectedSignaturesEvent'
|
|
||||||
import { checkWaitingBlocksForExecution } from '../utils/executionWaitingForBlocks'
|
|
||||||
import { getConfirmationsForTx } from '../utils/getConfirmationsForTx'
|
import { getConfirmationsForTx } from '../utils/getConfirmationsForTx'
|
||||||
import { getFinalizationEvent } from '../utils/getFinalizationEvent'
|
import { getFinalizationEvent } from '../utils/getFinalizationEvent'
|
||||||
import {
|
import {
|
||||||
@@ -64,11 +61,11 @@ export const useMessageConfirmations = ({
|
|||||||
blockConfirmations
|
blockConfirmations
|
||||||
}: useMessageConfirmationsParams) => {
|
}: useMessageConfirmationsParams) => {
|
||||||
const { home, foreign } = useStateProvider()
|
const { home, foreign } = useStateProvider()
|
||||||
const [confirmations, setConfirmations] = useState([])
|
const [confirmations, setConfirmations] = useState<ConfirmationParam[]>([])
|
||||||
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
|
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
|
||||||
const [waitingBlocks, setWaitingBlocks] = useState(false)
|
const [waitingBlocks, setWaitingBlocks] = useState(false)
|
||||||
const [waitingBlocksResolved, setWaitingBlocksResolved] = useState(false)
|
const [waitingBlocksResolved, setWaitingBlocksResolved] = useState(false)
|
||||||
const [signatureCollected, setSignatureCollected] = useState(false)
|
const [signatureCollected, setSignatureCollected] = useState<boolean | string[]>(false)
|
||||||
const [executionEventsFetched, setExecutionEventsFetched] = useState(false)
|
const [executionEventsFetched, setExecutionEventsFetched] = useState(false)
|
||||||
const [collectedSignaturesEvent, setCollectedSignaturesEvent] = useState<Maybe<EventData>>(null)
|
const [collectedSignaturesEvent, setCollectedSignaturesEvent] = useState<Maybe<EventData>>(null)
|
||||||
const [executionData, setExecutionData] = useState<ExecutionData>({
|
const [executionData, setExecutionData] = useState<ExecutionData>({
|
||||||
@@ -85,12 +82,10 @@ export const useMessageConfirmations = ({
|
|||||||
const [pendingConfirmations, setPendingConfirmations] = useState(false)
|
const [pendingConfirmations, setPendingConfirmations] = useState(false)
|
||||||
const [pendingExecution, setPendingExecution] = useState(false)
|
const [pendingExecution, setPendingExecution] = useState(false)
|
||||||
|
|
||||||
const existsConfirmation = (confirmationArray: ConfirmationParam[]) => {
|
const existsConfirmation = (confirmationArray: ConfirmationParam[]) =>
|
||||||
const filteredList = confirmationArray.filter(
|
confirmationArray.some(
|
||||||
c => c.status !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED && c.status !== VALIDATOR_CONFIRMATION_STATUS.WAITING
|
c => c.status !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED && c.status !== VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||||
)
|
)
|
||||||
return filteredList.length > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// start watching blocks at the start
|
// start watching blocks at the start
|
||||||
useEffect(
|
useEffect(
|
||||||
@@ -108,129 +103,154 @@ export const useMessageConfirmations = ({
|
|||||||
() => {
|
() => {
|
||||||
if (!receipt || !blockConfirmations || waitingBlocksResolved) return
|
if (!receipt || !blockConfirmations || waitingBlocksResolved) return
|
||||||
|
|
||||||
const subscriptions: Array<number> = []
|
let timeoutId: number
|
||||||
|
|
||||||
const unsubscribe = () => {
|
|
||||||
subscriptions.forEach(s => {
|
|
||||||
clearTimeout(s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const blockProvider = fromHome ? homeBlockNumberProvider : foreignBlockNumberProvider
|
const blockProvider = fromHome ? homeBlockNumberProvider : foreignBlockNumberProvider
|
||||||
const interval = fromHome ? HOME_RPC_POLLING_INTERVAL : FOREIGN_RPC_POLLING_INTERVAL
|
const interval = fromHome ? HOME_RPC_POLLING_INTERVAL : FOREIGN_RPC_POLLING_INTERVAL
|
||||||
const targetBlock = receipt.blockNumber + blockConfirmations
|
const targetBlock = receipt.blockNumber + blockConfirmations
|
||||||
|
const validatorsWaiting = validatorList.map(validator => ({
|
||||||
|
validator,
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
|
||||||
|
txHash: '',
|
||||||
|
timestamp: 0
|
||||||
|
}))
|
||||||
|
|
||||||
checkSignaturesWaitingForBLocks(
|
const checkSignaturesWaitingForBLocks = () => {
|
||||||
targetBlock,
|
const currentBlock = blockProvider.get()
|
||||||
setWaitingBlocks,
|
|
||||||
setWaitingBlocksResolved,
|
|
||||||
validatorList,
|
|
||||||
setConfirmations,
|
|
||||||
blockProvider,
|
|
||||||
interval,
|
|
||||||
subscriptions
|
|
||||||
)
|
|
||||||
|
|
||||||
return () => {
|
if (currentBlock && currentBlock >= targetBlock) {
|
||||||
unsubscribe()
|
setWaitingBlocksResolved(true)
|
||||||
|
setWaitingBlocks(false)
|
||||||
|
} else if (currentBlock) {
|
||||||
|
setWaitingBlocks(true)
|
||||||
|
setConfirmations(validatorsWaiting)
|
||||||
|
timeoutId = setTimeout(checkSignaturesWaitingForBLocks, interval)
|
||||||
|
} else {
|
||||||
|
timeoutId = setTimeout(checkSignaturesWaitingForBLocks, 500)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkSignaturesWaitingForBLocks()
|
||||||
|
|
||||||
|
return () => clearTimeout(timeoutId)
|
||||||
},
|
},
|
||||||
[
|
[blockConfirmations, fromHome, receipt, validatorList, waitingBlocksResolved]
|
||||||
blockConfirmations,
|
|
||||||
foreign.web3,
|
|
||||||
fromHome,
|
|
||||||
validatorList,
|
|
||||||
home.web3,
|
|
||||||
receipt,
|
|
||||||
setConfirmations,
|
|
||||||
waitingBlocksResolved
|
|
||||||
]
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
|
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
|
||||||
// the execution tx on the foreign network is waiting for block confirmations
|
// the execution tx on the foreign network is waiting for block confirmations
|
||||||
// This is executed if the message is in Home to Foreign direction only
|
// This is executed if the message is in Home to Foreign direction only
|
||||||
|
const hasCollectedSignatures = !!signatureCollected // true or string[]
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!fromHome || !receipt || !home.web3 || !signatureCollected) return
|
if (!fromHome || !receipt || !home.web3 || !home.bridgeContract || !hasCollectedSignatures) return
|
||||||
|
|
||||||
const subscriptions: Array<number> = []
|
let timeoutId: number
|
||||||
|
let isCancelled = false
|
||||||
|
|
||||||
const unsubscribe = () => {
|
const messageHash = home.web3.utils.soliditySha3Raw(message.data)
|
||||||
subscriptions.forEach(s => {
|
const contract = home.bridgeContract
|
||||||
clearTimeout(s)
|
|
||||||
})
|
const getCollectedSignaturesEvent = async (fromBlock: number, toBlock: number) => {
|
||||||
|
const currentBlock = homeBlockNumberProvider.get()
|
||||||
|
|
||||||
|
if (currentBlock) {
|
||||||
|
// prevent errors if the toBlock parameter is bigger than the latest
|
||||||
|
const securedToBlock = toBlock >= currentBlock ? currentBlock : toBlock
|
||||||
|
const events = await contract.getPastEvents('CollectedSignatures', {
|
||||||
|
fromBlock,
|
||||||
|
toBlock: securedToBlock
|
||||||
|
})
|
||||||
|
const event = events.find(e => e.returnValues.messageHash === messageHash)
|
||||||
|
if (event) {
|
||||||
|
setCollectedSignaturesEvent(event)
|
||||||
|
} else if (!isCancelled) {
|
||||||
|
timeoutId = setTimeout(() => getCollectedSignaturesEvent(securedToBlock, securedToBlock + BLOCK_RANGE), 500)
|
||||||
|
}
|
||||||
|
} else if (!isCancelled) {
|
||||||
|
timeoutId = setTimeout(() => getCollectedSignaturesEvent(fromBlock, toBlock), 500)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fromBlock = receipt.blockNumber
|
getCollectedSignaturesEvent(receipt.blockNumber, receipt.blockNumber + BLOCK_RANGE)
|
||||||
const toBlock = fromBlock + BLOCK_RANGE
|
|
||||||
const messageHash = home.web3.utils.soliditySha3Raw(message.data)
|
|
||||||
|
|
||||||
getCollectedSignaturesEvent(
|
|
||||||
home.web3,
|
|
||||||
home.bridgeContract,
|
|
||||||
fromBlock,
|
|
||||||
toBlock,
|
|
||||||
messageHash,
|
|
||||||
setCollectedSignaturesEvent,
|
|
||||||
subscriptions
|
|
||||||
)
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribe()
|
clearTimeout(timeoutId)
|
||||||
|
isCancelled = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[fromHome, home.bridgeContract, home.web3, message.data, receipt, signatureCollected]
|
[fromHome, home.bridgeContract, home.web3, message.data, receipt, hasCollectedSignatures]
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check if the responsible validator is waiting for block confirmations to execute the message on foreign network
|
// Check if the responsible validator is waiting for block confirmations to execute the message on foreign network
|
||||||
// This is executed if the message is in Home to Foreign direction only
|
// This is executed if the message is in Home to Foreign direction only
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent || !blockConfirmations) return
|
if (!fromHome || !home.web3 || !collectedSignaturesEvent || !blockConfirmations) return
|
||||||
if (waitingBlocksForExecutionResolved) return
|
if (waitingBlocksForExecutionResolved) return
|
||||||
|
|
||||||
const subscriptions: Array<number> = []
|
let timeoutId: number
|
||||||
|
|
||||||
const unsubscribe = () => {
|
|
||||||
subscriptions.forEach(s => {
|
|
||||||
clearTimeout(s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetBlock = collectedSignaturesEvent.blockNumber + blockConfirmations
|
const targetBlock = collectedSignaturesEvent.blockNumber + blockConfirmations
|
||||||
|
|
||||||
checkWaitingBlocksForExecution(
|
const checkWaitingBlocksForExecution = () => {
|
||||||
homeBlockNumberProvider,
|
const currentBlock = homeBlockNumberProvider.get()
|
||||||
HOME_RPC_POLLING_INTERVAL,
|
|
||||||
targetBlock,
|
|
||||||
collectedSignaturesEvent,
|
|
||||||
setWaitingBlocksForExecution,
|
|
||||||
setWaitingBlocksForExecutionResolved,
|
|
||||||
setExecutionData,
|
|
||||||
subscriptions
|
|
||||||
)
|
|
||||||
|
|
||||||
return () => {
|
if (currentBlock && currentBlock >= targetBlock) {
|
||||||
unsubscribe()
|
const undefinedExecutionState = {
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
|
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||||
|
txHash: '',
|
||||||
|
timestamp: 0,
|
||||||
|
executionResult: false
|
||||||
|
}
|
||||||
|
setExecutionData(
|
||||||
|
(data: any) =>
|
||||||
|
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED ||
|
||||||
|
data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||||
|
? undefinedExecutionState
|
||||||
|
: data
|
||||||
|
)
|
||||||
|
setWaitingBlocksForExecutionResolved(true)
|
||||||
|
setWaitingBlocksForExecution(false)
|
||||||
|
} else if (currentBlock) {
|
||||||
|
setWaitingBlocksForExecution(true)
|
||||||
|
const waitingExecutionState = {
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
|
||||||
|
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
||||||
|
txHash: '',
|
||||||
|
timestamp: 0,
|
||||||
|
executionResult: false
|
||||||
|
}
|
||||||
|
setExecutionData(
|
||||||
|
(data: any) =>
|
||||||
|
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED ||
|
||||||
|
data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
||||||
|
? waitingExecutionState
|
||||||
|
: data
|
||||||
|
)
|
||||||
|
timeoutId = setTimeout(() => checkWaitingBlocksForExecution(), HOME_RPC_POLLING_INTERVAL)
|
||||||
|
} else {
|
||||||
|
timeoutId = setTimeout(() => checkWaitingBlocksForExecution(), 500)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkWaitingBlocksForExecution()
|
||||||
|
|
||||||
|
return () => clearTimeout(timeoutId)
|
||||||
},
|
},
|
||||||
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, receipt, waitingBlocksForExecutionResolved]
|
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, waitingBlocksForExecutionResolved]
|
||||||
)
|
)
|
||||||
|
|
||||||
// Checks if validators verified the message
|
// Checks if validators verified the message
|
||||||
// To avoid making extra requests, this is only executed when validators finished waiting for blocks confirmations
|
// To avoid making extra requests, this is only executed when validators finished waiting for blocks confirmations
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!waitingBlocksResolved || !homeStartBlock || !requiredSignatures) return
|
if (!waitingBlocksResolved || !homeStartBlock || !requiredSignatures || !home.web3 || !home.bridgeContract) return
|
||||||
|
if (!validatorList || !validatorList.length) return
|
||||||
|
|
||||||
const subscriptions: Array<number> = []
|
let timeoutId: number
|
||||||
|
let isCancelled = false
|
||||||
const unsubscribe = () => {
|
|
||||||
subscriptions.forEach(s => {
|
|
||||||
clearTimeout(s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
getConfirmationsForTx(
|
getConfirmationsForTx(
|
||||||
message.data,
|
message.data,
|
||||||
@@ -241,8 +261,8 @@ export const useMessageConfirmations = ({
|
|||||||
setConfirmations,
|
setConfirmations,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
waitingBlocksResolved,
|
id => (timeoutId = id),
|
||||||
subscriptions,
|
() => isCancelled,
|
||||||
homeStartBlock,
|
homeStartBlock,
|
||||||
getValidatorFailedTransactionsForMessage,
|
getValidatorFailedTransactionsForMessage,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -252,7 +272,8 @@ export const useMessageConfirmations = ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribe()
|
clearTimeout(timeoutId)
|
||||||
|
isCancelled = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
@@ -263,8 +284,7 @@ export const useMessageConfirmations = ({
|
|||||||
home.bridgeContract,
|
home.bridgeContract,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
waitingBlocksResolved,
|
waitingBlocksResolved,
|
||||||
homeStartBlock,
|
homeStartBlock
|
||||||
setConfirmations
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -274,32 +294,23 @@ export const useMessageConfirmations = ({
|
|||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if ((fromHome && !waitingBlocksForExecutionResolved) || (!fromHome && !waitingBlocksResolved)) return
|
if ((fromHome && !waitingBlocksForExecutionResolved) || (!fromHome && !waitingBlocksResolved)) return
|
||||||
const startBlock = fromHome ? foreignStartBlock : homeStartBlock
|
|
||||||
if (!startBlock) return
|
|
||||||
|
|
||||||
const subscriptions: Array<number> = []
|
|
||||||
|
|
||||||
const unsubscribe = () => {
|
|
||||||
subscriptions.forEach(s => {
|
|
||||||
clearTimeout(s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const contractEvent = fromHome ? 'RelayedMessage' : 'AffirmationCompleted'
|
|
||||||
const bridgeContract = fromHome ? foreign.bridgeContract : home.bridgeContract
|
const bridgeContract = fromHome ? foreign.bridgeContract : home.bridgeContract
|
||||||
const providedWeb3 = fromHome ? foreign.web3 : home.web3
|
const web3 = fromHome ? foreign.web3 : home.web3
|
||||||
const interval = fromHome ? FOREIGN_RPC_POLLING_INTERVAL : HOME_RPC_POLLING_INTERVAL
|
const startBlock = fromHome ? foreignStartBlock : homeStartBlock
|
||||||
|
if (!startBlock || !bridgeContract || !web3) return
|
||||||
|
|
||||||
|
let timeoutId: number
|
||||||
|
let isCancelled = false
|
||||||
|
|
||||||
getFinalizationEvent(
|
getFinalizationEvent(
|
||||||
fromHome,
|
fromHome,
|
||||||
bridgeContract,
|
bridgeContract,
|
||||||
contractEvent,
|
web3,
|
||||||
providedWeb3,
|
|
||||||
setExecutionData,
|
setExecutionData,
|
||||||
waitingBlocksResolved,
|
|
||||||
message,
|
message,
|
||||||
interval,
|
id => (timeoutId = id),
|
||||||
subscriptions,
|
() => isCancelled,
|
||||||
startBlock,
|
startBlock,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getExecutionFailedTransactionForMessage,
|
getExecutionFailedTransactionForMessage,
|
||||||
@@ -310,7 +321,8 @@ export const useMessageConfirmations = ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribe()
|
clearTimeout(timeoutId)
|
||||||
|
isCancelled = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -11,40 +11,23 @@ export const useTransactionFinder = ({ txHash, web3 }: { txHash: string; web3: M
|
|||||||
() => {
|
() => {
|
||||||
if (!txHash || !web3) return
|
if (!txHash || !web3) return
|
||||||
|
|
||||||
const subscriptions: number[] = []
|
let timeoutId: number
|
||||||
|
|
||||||
const unsubscribe = () => {
|
const getReceipt = async () => {
|
||||||
subscriptions.forEach(s => {
|
|
||||||
clearTimeout(s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const getReceipt = async (
|
|
||||||
web3: Web3,
|
|
||||||
txHash: string,
|
|
||||||
setReceipt: Function,
|
|
||||||
setStatus: Function,
|
|
||||||
subscriptions: number[]
|
|
||||||
) => {
|
|
||||||
const txReceipt = await web3.eth.getTransactionReceipt(txHash)
|
const txReceipt = await web3.eth.getTransactionReceipt(txHash)
|
||||||
setReceipt(txReceipt)
|
setReceipt(txReceipt)
|
||||||
|
|
||||||
if (!txReceipt) {
|
if (!txReceipt) {
|
||||||
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
||||||
const timeoutId = setTimeout(
|
timeoutId = setTimeout(getReceipt, HOME_RPC_POLLING_INTERVAL)
|
||||||
() => getReceipt(web3, txHash, setReceipt, setStatus, subscriptions),
|
|
||||||
HOME_RPC_POLLING_INTERVAL
|
|
||||||
)
|
|
||||||
subscriptions.push(timeoutId)
|
|
||||||
} else {
|
} else {
|
||||||
setStatus(TRANSACTION_STATUS.FOUND)
|
setStatus(TRANSACTION_STATUS.FOUND)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getReceipt(web3, txHash, setReceipt, setStatus, subscriptions)
|
getReceipt()
|
||||||
return () => {
|
|
||||||
unsubscribe()
|
return () => clearTimeout(timeoutId)
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[txHash, web3]
|
[txHash, web3]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -31,19 +31,14 @@ export const useTransactionStatus = ({
|
|||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
const subscriptions: Array<number> = []
|
if (!chainId || !txHash || !home.chainId || !foreign.chainId || !home.web3 || !foreign.web3) return
|
||||||
|
const isHome = chainId === home.chainId
|
||||||
|
const web3 = isHome ? home.web3 : foreign.web3
|
||||||
|
|
||||||
const unsubscribe = () => {
|
let timeoutId: number
|
||||||
subscriptions.forEach(s => {
|
|
||||||
clearTimeout(s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const getReceipt = async () => {
|
const getReceipt = async () => {
|
||||||
if (!chainId || !txHash || !home.chainId || !foreign.chainId || !home.web3 || !foreign.web3) return
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const isHome = chainId === home.chainId
|
|
||||||
const web3 = isHome ? home.web3 : foreign.web3
|
|
||||||
|
|
||||||
let txReceipt
|
let txReceipt
|
||||||
|
|
||||||
@@ -59,8 +54,7 @@ export const useTransactionStatus = ({
|
|||||||
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
setStatus(TRANSACTION_STATUS.NOT_FOUND)
|
||||||
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.NOT_FOUND))
|
setDescription(getTransactionStatusDescription(TRANSACTION_STATUS.NOT_FOUND))
|
||||||
setMessages([{ id: txHash, data: '' }])
|
setMessages([{ id: txHash, data: '' }])
|
||||||
const timeoutId = setTimeout(() => getReceipt(), HOME_RPC_POLLING_INTERVAL)
|
timeoutId = setTimeout(() => getReceipt(), HOME_RPC_POLLING_INTERVAL)
|
||||||
subscriptions.push(timeoutId)
|
|
||||||
} else {
|
} else {
|
||||||
const blockNumber = txReceipt.blockNumber
|
const blockNumber = txReceipt.blockNumber
|
||||||
const block = await getBlock(web3, blockNumber)
|
const block = await getBlock(web3, blockNumber)
|
||||||
@@ -70,9 +64,9 @@ export const useTransactionStatus = ({
|
|||||||
if (txReceipt.status) {
|
if (txReceipt.status) {
|
||||||
let bridgeMessages: Array<MessageObject>
|
let bridgeMessages: Array<MessageObject>
|
||||||
if (isHome) {
|
if (isHome) {
|
||||||
bridgeMessages = getHomeMessagesFromReceipt(txReceipt, home.web3, home.bridgeAddress)
|
bridgeMessages = getHomeMessagesFromReceipt(txReceipt, web3, home.bridgeAddress)
|
||||||
} else {
|
} else {
|
||||||
bridgeMessages = getForeignMessagesFromReceipt(txReceipt, foreign.web3, foreign.bridgeAddress)
|
bridgeMessages = getForeignMessagesFromReceipt(txReceipt, web3, foreign.bridgeAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bridgeMessages.length === 0) {
|
if (bridgeMessages.length === 0) {
|
||||||
@@ -98,14 +92,9 @@ export const useTransactionStatus = ({
|
|||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsubscribe from previous txHash
|
|
||||||
unsubscribe()
|
|
||||||
|
|
||||||
getReceipt()
|
getReceipt()
|
||||||
return () => {
|
|
||||||
// unsubscribe when unmount component
|
return () => clearTimeout(timeoutId)
|
||||||
unsubscribe()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
txHash,
|
txHash,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { BRIDGE_VALIDATORS_ABI } from '../abis'
|
|||||||
import { useStateProvider } from '../state/StateProvider'
|
import { useStateProvider } from '../state/StateProvider'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
import { TransactionReceipt } from 'web3-eth'
|
||||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
|
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
||||||
|
|
||||||
export interface useValidatorContractParams {
|
export interface useValidatorContractParams {
|
||||||
fromHome: boolean
|
fromHome: boolean
|
||||||
@@ -30,10 +31,12 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
|||||||
contract: Maybe<Contract>,
|
contract: Maybe<Contract>,
|
||||||
receipt: TransactionReceipt,
|
receipt: TransactionReceipt,
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
snapshotProvider: SnapshotProvider
|
snapshotProvider: SnapshotProvider,
|
||||||
|
web3: Web3,
|
||||||
|
api: string
|
||||||
) => {
|
) => {
|
||||||
if (!contract) return
|
if (!contract) return
|
||||||
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider)
|
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,32 +44,35 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
|||||||
contract: Maybe<Contract>,
|
contract: Maybe<Contract>,
|
||||||
receipt: TransactionReceipt,
|
receipt: TransactionReceipt,
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
snapshotProvider: SnapshotProvider
|
snapshotProvider: SnapshotProvider,
|
||||||
|
web3: Web3,
|
||||||
|
api: string
|
||||||
) => {
|
) => {
|
||||||
if (!contract) return
|
if (!contract) return
|
||||||
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider)
|
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const web3 = fromHome ? home.web3 : foreign.web3
|
||||||
|
const api = fromHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
||||||
|
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||||
|
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
const web3 = fromHome ? home.web3 : foreign.web3
|
|
||||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
|
||||||
|
|
||||||
if (!web3 || !bridgeContract) return
|
if (!web3 || !bridgeContract) return
|
||||||
callValidatorContract(bridgeContract, web3, setValidatorContract)
|
callValidatorContract(bridgeContract, web3, setValidatorContract)
|
||||||
},
|
},
|
||||||
[home.web3, foreign.web3, home.bridgeContract, foreign.bridgeContract, fromHome]
|
[web3, bridgeContract]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!receipt) return
|
if (!web3 || !receipt) return
|
||||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider, web3, api)
|
||||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider)
|
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider, web3, api)
|
||||||
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider)
|
|
||||||
},
|
},
|
||||||
[validatorContract, receipt, fromHome]
|
[validatorContract, receipt, web3, snapshotProvider, api]
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
|
|
||||||
test('Should call requiredBlockConfirmations method if no events present', async () => {
|
test('Should call requiredBlockConfirmations method if no events present', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: () => {
|
getPastEvents: async () => {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
methods: methodsBuilder('1')
|
methods: methodsBuilder('1')
|
||||||
@@ -37,7 +37,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
})
|
})
|
||||||
test('Should not call to get events if block number was included in the snapshot', async () => {
|
test('Should not call to get events if block number was included in the snapshot', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
getPastEvents: jest.fn().mockImplementation(async () => []),
|
||||||
methods: methodsBuilder('3')
|
methods: methodsBuilder('3')
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
})
|
})
|
||||||
test('Should call to get events if block number was not included in the snapshot', async () => {
|
test('Should call to get events if block number was not included in the snapshot', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(() => [
|
getPastEvents: jest.fn().mockImplementation(async () => [
|
||||||
{
|
{
|
||||||
blockNumber: 9,
|
blockNumber: 9,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -102,7 +102,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
})
|
})
|
||||||
test('Should use the most updated event', async () => {
|
test('Should use the most updated event', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(() => [
|
getPastEvents: jest.fn().mockImplementation(async () => [
|
||||||
{
|
{
|
||||||
blockNumber: 9,
|
blockNumber: 9,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -141,7 +141,7 @@ describe('getRequiredBlockConfirmations', () => {
|
|||||||
describe('getRequiredSignatures', () => {
|
describe('getRequiredSignatures', () => {
|
||||||
test('Should not call to get events if block number was included in the snapshot', async () => {
|
test('Should not call to get events if block number was included in the snapshot', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(() => [])
|
getPastEvents: jest.fn().mockImplementation(async () => [])
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
const snapshotProvider = ({
|
const snapshotProvider = ({
|
||||||
@@ -173,7 +173,7 @@ describe('getRequiredSignatures', () => {
|
|||||||
})
|
})
|
||||||
test('Should call to get events if block number is higher than the snapshot block number', async () => {
|
test('Should call to get events if block number is higher than the snapshot block number', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(() => [
|
getPastEvents: jest.fn().mockImplementation(async () => [
|
||||||
{
|
{
|
||||||
blockNumber: 15,
|
blockNumber: 15,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -216,7 +216,7 @@ describe('getRequiredSignatures', () => {
|
|||||||
})
|
})
|
||||||
test('Should use the most updated event before the block number', async () => {
|
test('Should use the most updated event before the block number', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(() => [
|
getPastEvents: jest.fn().mockImplementation(async () => [
|
||||||
{
|
{
|
||||||
blockNumber: 15,
|
blockNumber: 15,
|
||||||
returnValues: {
|
returnValues: {
|
||||||
@@ -270,7 +270,7 @@ describe('getValidatorList', () => {
|
|||||||
test('Should return the current validator list if no events found', async () => {
|
test('Should return the current validator list if no events found', async () => {
|
||||||
const currentValidators = [validator1, validator2, validator3]
|
const currentValidators = [validator1, validator2, validator3]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
getPastEvents: jest.fn().mockImplementation(async () => []),
|
||||||
methods: methodsBuilder(currentValidators)
|
methods: methodsBuilder(currentValidators)
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
@@ -301,7 +301,7 @@ describe('getValidatorList', () => {
|
|||||||
test('If validator was added later from snapshot it should not include it', async () => {
|
test('If validator was added later from snapshot it should not include it', async () => {
|
||||||
const currentValidators = [validator1, validator2, validator3]
|
const currentValidators = [validator1, validator2, validator3]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
getPastEvents: jest.fn().mockImplementation(async () => []),
|
||||||
methods: methodsBuilder(currentValidators)
|
methods: methodsBuilder(currentValidators)
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
@@ -340,7 +340,7 @@ describe('getValidatorList', () => {
|
|||||||
test('If validator was added later from chain it should not include it', async () => {
|
test('If validator was added later from chain it should not include it', async () => {
|
||||||
const currentValidators = [validator1, validator2, validator3]
|
const currentValidators = [validator1, validator2, validator3]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(event => {
|
getPastEvents: jest.fn().mockImplementation(async event => {
|
||||||
if (event === 'ValidatorAdded') {
|
if (event === 'ValidatorAdded') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -385,7 +385,7 @@ describe('getValidatorList', () => {
|
|||||||
test('If validator was removed later from snapshot it should include it', async () => {
|
test('If validator was removed later from snapshot it should include it', async () => {
|
||||||
const currentValidators = [validator1, validator2]
|
const currentValidators = [validator1, validator2]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
getPastEvents: jest.fn().mockImplementation(async () => []),
|
||||||
methods: methodsBuilder(currentValidators)
|
methods: methodsBuilder(currentValidators)
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
|
|
||||||
@@ -424,7 +424,7 @@ describe('getValidatorList', () => {
|
|||||||
test('If validator was removed later from chain it should include it', async () => {
|
test('If validator was removed later from chain it should include it', async () => {
|
||||||
const currentValidators = [validator1, validator2]
|
const currentValidators = [validator1, validator2]
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: jest.fn().mockImplementation(event => {
|
getPastEvents: jest.fn().mockImplementation(async event => {
|
||||||
if (event === 'ValidatorRemoved') {
|
if (event === 'ValidatorRemoved') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const bridgeContract = {
|
|||||||
}
|
}
|
||||||
} as Contract
|
} as Contract
|
||||||
const requiredSignatures = 2
|
const requiredSignatures = 2
|
||||||
const waitingBlocksResolved = true
|
const isCancelled = () => false
|
||||||
let subscriptions: Array<number> = []
|
let subscriptions: Array<number> = []
|
||||||
const timestamp = 1594045859
|
const timestamp = 1594045859
|
||||||
const getFailedTransactions = (): Promise<APITransaction[]> => Promise.resolve([])
|
const getFailedTransactions = (): Promise<APITransaction[]> => Promise.resolve([])
|
||||||
@@ -94,8 +94,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
waitingBlocksResolved,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -177,8 +177,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
waitingBlocksResolved,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -241,8 +241,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
waitingBlocksResolved,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -340,8 +340,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
waitingBlocksResolved,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -453,8 +453,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
waitingBlocksResolved,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -557,8 +557,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
waitingBlocksResolved,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -678,8 +678,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
waitingBlocksResolved,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
@@ -746,8 +746,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
setResult,
|
setResult,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
setSignatureCollected,
|
setSignatureCollected,
|
||||||
waitingBlocksResolved,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
getFailedTransactions,
|
getFailedTransactions,
|
||||||
setFailedConfirmations,
|
setFailedConfirmations,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import Web3 from 'web3'
|
|||||||
import { getFinalizationEvent } from '../getFinalizationEvent'
|
import { getFinalizationEvent } from '../getFinalizationEvent'
|
||||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
|
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
|
||||||
|
|
||||||
const eventName = 'RelayedMessage'
|
|
||||||
const timestamp = 1594045859
|
const timestamp = 1594045859
|
||||||
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
||||||
const txHash = '0xdab36c9210e7e45fb82af10ffe4960461e41661dce0c9cd36b2843adaa1df156'
|
const txHash = '0xdab36c9210e7e45fb82af10ffe4960461e41661dce0c9cd36b2843adaa1df156'
|
||||||
@@ -20,12 +19,11 @@ const web3 = ({
|
|||||||
toChecksumAddress: (a: string) => a
|
toChecksumAddress: (a: string) => a
|
||||||
}
|
}
|
||||||
} as unknown) as Web3
|
} as unknown) as Web3
|
||||||
const waitingBlocksResolved = true
|
|
||||||
const message = {
|
const message = {
|
||||||
id: '0x123',
|
id: '0x123',
|
||||||
data: '0x123456789'
|
data: '0x123456789'
|
||||||
}
|
}
|
||||||
const interval = 10000
|
const isCancelled = () => false
|
||||||
let subscriptions: Array<number> = []
|
let subscriptions: Array<number> = []
|
||||||
|
|
||||||
const event = {
|
const event = {
|
||||||
@@ -50,7 +48,7 @@ beforeEach(() => {
|
|||||||
describe('getFinalizationEvent', () => {
|
describe('getFinalizationEvent', () => {
|
||||||
test('should get finalization event and not try to get failed or pending transactions', async () => {
|
test('should get finalization event and not try to get failed or pending transactions', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: () => {
|
getPastEvents: async () => {
|
||||||
return [event]
|
return [event]
|
||||||
}
|
}
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
@@ -66,13 +64,11 @@ describe('getFinalizationEvent', () => {
|
|||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
true,
|
||||||
contract,
|
contract,
|
||||||
eventName,
|
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
waitingBlocksResolved,
|
|
||||||
message,
|
message,
|
||||||
interval,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
@@ -102,7 +98,7 @@ describe('getFinalizationEvent', () => {
|
|||||||
})
|
})
|
||||||
test('should retry to get finalization event and not try to get failed or pending transactions if foreign to home transaction', async () => {
|
test('should retry to get finalization event and not try to get failed or pending transactions if foreign to home transaction', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: () => {
|
getPastEvents: async () => {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
} as unknown) as Contract
|
} as unknown) as Contract
|
||||||
@@ -118,13 +114,11 @@ describe('getFinalizationEvent', () => {
|
|||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
true,
|
||||||
contract,
|
contract,
|
||||||
eventName,
|
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
waitingBlocksResolved,
|
|
||||||
message,
|
message,
|
||||||
interval,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
@@ -147,7 +141,7 @@ describe('getFinalizationEvent', () => {
|
|||||||
})
|
})
|
||||||
test('should retry to get finalization event and try to get failed and pending transactions if home to foreign transaction', async () => {
|
test('should retry to get finalization event and try to get failed and pending transactions if home to foreign transaction', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: () => {
|
getPastEvents: async () => {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@@ -170,13 +164,11 @@ describe('getFinalizationEvent', () => {
|
|||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
true,
|
||||||
contract,
|
contract,
|
||||||
eventName,
|
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
waitingBlocksResolved,
|
|
||||||
message,
|
message,
|
||||||
interval,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
@@ -199,7 +191,7 @@ describe('getFinalizationEvent', () => {
|
|||||||
})
|
})
|
||||||
test('should retry to get finalization event and not to try to get failed transaction if pending transactions found if home to foreign transaction', async () => {
|
test('should retry to get finalization event and not to try to get failed transaction if pending transactions found if home to foreign transaction', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: () => {
|
getPastEvents: async () => {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@@ -222,13 +214,11 @@ describe('getFinalizationEvent', () => {
|
|||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
true,
|
||||||
contract,
|
contract,
|
||||||
eventName,
|
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
waitingBlocksResolved,
|
|
||||||
message,
|
message,
|
||||||
interval,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
@@ -258,7 +248,7 @@ describe('getFinalizationEvent', () => {
|
|||||||
})
|
})
|
||||||
test('should retry to get finalization event even if failed transaction found if home to foreign transaction', async () => {
|
test('should retry to get finalization event even if failed transaction found if home to foreign transaction', async () => {
|
||||||
const contract = ({
|
const contract = ({
|
||||||
getPastEvents: () => {
|
getPastEvents: async () => {
|
||||||
return []
|
return []
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
@@ -281,13 +271,11 @@ describe('getFinalizationEvent', () => {
|
|||||||
await getFinalizationEvent(
|
await getFinalizationEvent(
|
||||||
true,
|
true,
|
||||||
contract,
|
contract,
|
||||||
eventName,
|
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
waitingBlocksResolved,
|
|
||||||
message,
|
message,
|
||||||
interval,
|
subscriptions.push.bind(subscriptions),
|
||||||
subscriptions,
|
isCancelled,
|
||||||
timestamp,
|
timestamp,
|
||||||
collectedSignaturesEvent,
|
collectedSignaturesEvent,
|
||||||
getFailedExecution,
|
getFailedExecution,
|
||||||
|
|||||||
@@ -1,18 +1,33 @@
|
|||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { EventData } from 'web3-eth-contract'
|
import { EventData } from 'web3-eth-contract'
|
||||||
import { SnapshotProvider } from '../services/SnapshotProvider'
|
import { SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
|
import { getLogs } from './explorer'
|
||||||
|
import Web3 from 'web3'
|
||||||
|
|
||||||
|
const getPastEventsWithFallback = (
|
||||||
|
api: string,
|
||||||
|
web3: Web3 | null,
|
||||||
|
contract: Contract,
|
||||||
|
eventName: string,
|
||||||
|
options: any
|
||||||
|
) =>
|
||||||
|
contract
|
||||||
|
.getPastEvents(eventName, options)
|
||||||
|
.catch(() => (api && web3 ? getLogs(api, web3, contract, eventName, options) : []))
|
||||||
|
|
||||||
export const getRequiredBlockConfirmations = async (
|
export const getRequiredBlockConfirmations = async (
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
blockNumber: number,
|
blockNumber: number,
|
||||||
snapshotProvider: SnapshotProvider
|
snapshotProvider: SnapshotProvider,
|
||||||
|
web3: Web3 | null = null,
|
||||||
|
api: string = ''
|
||||||
) => {
|
) => {
|
||||||
const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber)
|
const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber)
|
||||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
|
|
||||||
let contractEvents: EventData[] = []
|
let contractEvents: EventData[] = []
|
||||||
if (blockNumber > snapshotBlockNumber) {
|
if (blockNumber > snapshotBlockNumber) {
|
||||||
contractEvents = await contract.getPastEvents('RequiredBlockConfirmationChanged', {
|
contractEvents = await getPastEventsWithFallback(api, web3, contract, 'RequiredBlockConfirmationChanged', {
|
||||||
fromBlock: snapshotBlockNumber + 1,
|
fromBlock: snapshotBlockNumber + 1,
|
||||||
toBlock: blockNumber
|
toBlock: blockNumber
|
||||||
})
|
})
|
||||||
@@ -38,14 +53,16 @@ export const getValidatorAddress = (contract: Contract) => contract.methods.vali
|
|||||||
export const getRequiredSignatures = async (
|
export const getRequiredSignatures = async (
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
blockNumber: number,
|
blockNumber: number,
|
||||||
snapshotProvider: SnapshotProvider
|
snapshotProvider: SnapshotProvider,
|
||||||
|
web3: Web3 | null = null,
|
||||||
|
api: string = ''
|
||||||
) => {
|
) => {
|
||||||
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
|
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
|
||||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
|
|
||||||
let contractEvents: EventData[] = []
|
let contractEvents: EventData[] = []
|
||||||
if (blockNumber > snapshotBlockNumber) {
|
if (blockNumber > snapshotBlockNumber) {
|
||||||
contractEvents = await contract.getPastEvents('RequiredSignaturesChanged', {
|
contractEvents = await getPastEventsWithFallback(api, web3, contract, 'RequiredSignaturesChanged', {
|
||||||
fromBlock: snapshotBlockNumber + 1,
|
fromBlock: snapshotBlockNumber + 1,
|
||||||
toBlock: blockNumber
|
toBlock: blockNumber
|
||||||
})
|
})
|
||||||
@@ -59,7 +76,13 @@ export const getRequiredSignatures = async (
|
|||||||
return parseInt(requiredSignatures)
|
return parseInt(requiredSignatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getValidatorList = async (contract: Contract, blockNumber: number, snapshotProvider: SnapshotProvider) => {
|
export const getValidatorList = async (
|
||||||
|
contract: Contract,
|
||||||
|
blockNumber: number,
|
||||||
|
snapshotProvider: SnapshotProvider,
|
||||||
|
web3: Web3 | null = null,
|
||||||
|
api: string = ''
|
||||||
|
) => {
|
||||||
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
||||||
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
|
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
|
||||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
@@ -67,10 +90,10 @@ export const getValidatorList = async (contract: Contract, blockNumber: number,
|
|||||||
const fromBlock = snapshotBlockNumber > blockNumber ? snapshotBlockNumber + 1 : blockNumber
|
const fromBlock = snapshotBlockNumber > blockNumber ? snapshotBlockNumber + 1 : blockNumber
|
||||||
const [currentList, added, removed] = await Promise.all([
|
const [currentList, added, removed] = await Promise.all([
|
||||||
contract.methods.validatorList().call(),
|
contract.methods.validatorList().call(),
|
||||||
contract.getPastEvents('ValidatorAdded', {
|
getPastEventsWithFallback(api, web3, contract, 'ValidatorAdded', {
|
||||||
fromBlock
|
fromBlock
|
||||||
}),
|
}),
|
||||||
contract.getPastEvents('ValidatorRemoved', {
|
getPastEventsWithFallback(api, web3, contract, 'ValidatorRemoved', {
|
||||||
fromBlock
|
fromBlock
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
import { BlockNumberProvider } from '../services/BlockNumberProvider'
|
|
||||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
|
||||||
import { EventData } from 'web3-eth-contract'
|
|
||||||
|
|
||||||
export const checkWaitingBlocksForExecution = async (
|
|
||||||
blockProvider: BlockNumberProvider,
|
|
||||||
interval: number,
|
|
||||||
targetBlock: number,
|
|
||||||
collectedSignaturesEvent: EventData,
|
|
||||||
setWaitingBlocksForExecution: Function,
|
|
||||||
setWaitingBlocksForExecutionResolved: Function,
|
|
||||||
setExecutionData: Function,
|
|
||||||
subscriptions: number[]
|
|
||||||
) => {
|
|
||||||
const currentBlock = blockProvider.get()
|
|
||||||
|
|
||||||
if (currentBlock && currentBlock >= targetBlock) {
|
|
||||||
const undefinedExecutionState = {
|
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
|
||||||
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
|
||||||
txHash: '',
|
|
||||||
timestamp: 0,
|
|
||||||
executionResult: false
|
|
||||||
}
|
|
||||||
setExecutionData(
|
|
||||||
(data: any) =>
|
|
||||||
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
|
||||||
? undefinedExecutionState
|
|
||||||
: data
|
|
||||||
)
|
|
||||||
setWaitingBlocksForExecutionResolved(true)
|
|
||||||
setWaitingBlocksForExecution(false)
|
|
||||||
} else {
|
|
||||||
let nextInterval = interval
|
|
||||||
if (!currentBlock) {
|
|
||||||
nextInterval = 500
|
|
||||||
} else {
|
|
||||||
setWaitingBlocksForExecution(true)
|
|
||||||
const waitingExecutionState = {
|
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
|
|
||||||
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
|
|
||||||
txHash: '',
|
|
||||||
timestamp: 0,
|
|
||||||
executionResult: false
|
|
||||||
}
|
|
||||||
setExecutionData(
|
|
||||||
(data: any) =>
|
|
||||||
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED ||
|
|
||||||
data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
|
|
||||||
? waitingExecutionState
|
|
||||||
: data
|
|
||||||
)
|
|
||||||
}
|
|
||||||
const timeoutId = setTimeout(
|
|
||||||
() =>
|
|
||||||
checkWaitingBlocksForExecution(
|
|
||||||
blockProvider,
|
|
||||||
interval,
|
|
||||||
targetBlock,
|
|
||||||
collectedSignaturesEvent,
|
|
||||||
setWaitingBlocksForExecution,
|
|
||||||
setWaitingBlocksForExecutionResolved,
|
|
||||||
setExecutionData,
|
|
||||||
subscriptions
|
|
||||||
),
|
|
||||||
nextInterval
|
|
||||||
)
|
|
||||||
subscriptions.push(timeoutId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -7,6 +7,9 @@ import {
|
|||||||
MAX_TX_SEARCH_BLOCK_RANGE,
|
MAX_TX_SEARCH_BLOCK_RANGE,
|
||||||
SUBMIT_SIGNATURE_HASH
|
SUBMIT_SIGNATURE_HASH
|
||||||
} from '../config/constants'
|
} from '../config/constants'
|
||||||
|
import { AbiItem } from 'web3-utils'
|
||||||
|
import Web3 from 'web3'
|
||||||
|
import { Contract } from 'web3-eth-contract'
|
||||||
|
|
||||||
export interface APITransaction {
|
export interface APITransaction {
|
||||||
timeStamp: string
|
timeStamp: string
|
||||||
@@ -47,10 +50,15 @@ export interface GetTransactionParams extends GetPendingTransactionParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const fetchAccountTransactions = async ({ account, startBlock, endBlock, api }: AccountTransactionsParams) => {
|
export const fetchAccountTransactions = async ({ account, startBlock, endBlock, api }: AccountTransactionsParams) => {
|
||||||
const params = `module=account&action=txlist&address=${account}&filterby=from&startblock=${startBlock}&endblock=${endBlock}`
|
const url = new URL(api)
|
||||||
const url = api.includes('blockscout') ? `${api}?${params}` : `${api}&${params}`
|
url.searchParams.append('module', 'account')
|
||||||
|
url.searchParams.append('action', 'txlist')
|
||||||
|
url.searchParams.append('address', account)
|
||||||
|
url.searchParams.append('filterby', 'from')
|
||||||
|
url.searchParams.append('startblock', startBlock.toString())
|
||||||
|
url.searchParams.append('endblock', endBlock.toString())
|
||||||
|
|
||||||
const result = await fetch(url).then(res => res.json())
|
const result = await fetch(url.toString()).then(res => res.json())
|
||||||
|
|
||||||
if (result.message === 'No transactions found') {
|
if (result.message === 'No transactions found') {
|
||||||
return []
|
return []
|
||||||
@@ -66,10 +74,13 @@ export const fetchPendingTransactions = async ({
|
|||||||
if (!api.includes('blockscout')) {
|
if (!api.includes('blockscout')) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
const url = `${api}?module=account&action=pendingtxlist&address=${account}`
|
const url = new URL(api)
|
||||||
|
url.searchParams.append('module', 'account')
|
||||||
|
url.searchParams.append('action', 'pendingtxlist')
|
||||||
|
url.searchParams.append('address', account)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await fetch(url).then(res => res.json())
|
const result = await fetch(url.toString()).then(res => res.json())
|
||||||
if (result.status === '0') {
|
if (result.status === '0') {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@@ -85,9 +96,13 @@ export const getClosestBlockByTimestamp = async (api: string, timestamp: number)
|
|||||||
throw new Error('Blockscout does not support getblocknobytime')
|
throw new Error('Blockscout does not support getblocknobytime')
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `${api}&module=block&action=getblocknobytime×tamp=${timestamp}&closest=before`
|
const url = new URL(api)
|
||||||
|
url.searchParams.append('module', 'block')
|
||||||
|
url.searchParams.append('action', 'getblocknobytime')
|
||||||
|
url.searchParams.append('timestamp', timestamp.toString())
|
||||||
|
url.searchParams.append('closest', 'before')
|
||||||
|
|
||||||
const blockNumber = await fetch(url).then(res => res.json())
|
const blockNumber = await fetch(url.toString()).then(res => res.json())
|
||||||
|
|
||||||
return parseInt(blockNumber.result)
|
return parseInt(blockNumber.result)
|
||||||
}
|
}
|
||||||
@@ -144,6 +159,41 @@ export const getAccountTransactions = async ({
|
|||||||
return transactionsCache[key].transactions
|
return transactionsCache[key].transactions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getLogs = async (
|
||||||
|
api: string,
|
||||||
|
web3: Web3,
|
||||||
|
contract: Contract,
|
||||||
|
event: string,
|
||||||
|
options: { fromBlock: number; toBlock: number | 'latest'; topics: (string | null)[] }
|
||||||
|
) => {
|
||||||
|
const abi = contract.options.jsonInterface.find((abi: AbiItem) => abi.type === 'event' && abi.name === event)!
|
||||||
|
|
||||||
|
const url = new URL(api)
|
||||||
|
url.searchParams.append('module', 'logs')
|
||||||
|
url.searchParams.append('action', 'getLogs')
|
||||||
|
url.searchParams.append('address', contract.options.address)
|
||||||
|
url.searchParams.append('fromBlock', options.fromBlock.toString())
|
||||||
|
url.searchParams.append('toBlock', (options.toBlock || 'latest').toString())
|
||||||
|
|
||||||
|
const topics = [web3.eth.abi.encodeEventSignature(abi), ...(options.topics || [])]
|
||||||
|
for (let i = 0; i < topics.length; i++) {
|
||||||
|
if (topics[i] !== null) {
|
||||||
|
url.searchParams.append(`topic${i}`, topics[i] as string)
|
||||||
|
for (let j = 0; j < i; j++) {
|
||||||
|
url.searchParams.append(`topic${j}_${i}_opr`, 'and')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const logs = await fetch(url.toString()).then(res => res.json())
|
||||||
|
|
||||||
|
return logs.result.map((log: any) => ({
|
||||||
|
transactionHash: log.transactionHash,
|
||||||
|
blockNumber: parseInt(log.blockNumber.slice(2), 16),
|
||||||
|
returnValues: web3.eth.abi.decodeLog(abi.inputs!, log.data, log.topics.slice(1))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
const filterReceiver = (to: string) => (tx: APITransaction) => tx.to.toLowerCase() === to.toLowerCase()
|
const filterReceiver = (to: string) => (tx: APITransaction) => tx.to.toLowerCase() === to.toLowerCase()
|
||||||
|
|
||||||
export const getFailedTransactions = async (
|
export const getFailedTransactions = async (
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
import Web3 from 'web3'
|
|
||||||
import { Contract, EventData } from 'web3-eth-contract'
|
|
||||||
import { homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
|
||||||
import { BLOCK_RANGE } from '../config/constants'
|
|
||||||
|
|
||||||
export const getCollectedSignaturesEvent = async (
|
|
||||||
web3: Maybe<Web3>,
|
|
||||||
contract: Maybe<Contract>,
|
|
||||||
fromBlock: number,
|
|
||||||
toBlock: number,
|
|
||||||
messageHash: string,
|
|
||||||
setCollectedSignaturesEvent: Function,
|
|
||||||
subscriptions: number[]
|
|
||||||
) => {
|
|
||||||
if (!web3 || !contract) return
|
|
||||||
const currentBlock = homeBlockNumberProvider.get()
|
|
||||||
|
|
||||||
let events: EventData[] = []
|
|
||||||
let securedToBlock = toBlock
|
|
||||||
if (currentBlock) {
|
|
||||||
// prevent errors if the toBlock parameter is bigger than the latest
|
|
||||||
securedToBlock = toBlock >= currentBlock ? currentBlock : toBlock
|
|
||||||
events = await contract.getPastEvents('CollectedSignatures', {
|
|
||||||
fromBlock,
|
|
||||||
toBlock: securedToBlock
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const filteredEvents = events.filter(e => e.returnValues.messageHash === messageHash)
|
|
||||||
|
|
||||||
if (filteredEvents.length) {
|
|
||||||
const event = filteredEvents[0]
|
|
||||||
setCollectedSignaturesEvent(event)
|
|
||||||
} else {
|
|
||||||
const newFromBlock = currentBlock ? securedToBlock : fromBlock
|
|
||||||
const newToBlock = currentBlock ? toBlock + BLOCK_RANGE : toBlock
|
|
||||||
const timeoutId = setTimeout(
|
|
||||||
() =>
|
|
||||||
getCollectedSignaturesEvent(
|
|
||||||
web3,
|
|
||||||
contract,
|
|
||||||
newFromBlock,
|
|
||||||
newToBlock,
|
|
||||||
messageHash,
|
|
||||||
setCollectedSignaturesEvent,
|
|
||||||
subscriptions
|
|
||||||
),
|
|
||||||
500
|
|
||||||
)
|
|
||||||
subscriptions.push(timeoutId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,15 +29,15 @@ const mergeConfirmations = (oldConfirmations: BasicConfirmationParam[], newConfi
|
|||||||
|
|
||||||
export const getConfirmationsForTx = async (
|
export const getConfirmationsForTx = async (
|
||||||
messageData: string,
|
messageData: string,
|
||||||
web3: Maybe<Web3>,
|
web3: Web3,
|
||||||
validatorList: string[],
|
validatorList: string[],
|
||||||
bridgeContract: Maybe<Contract>,
|
bridgeContract: Contract,
|
||||||
fromHome: boolean,
|
fromHome: boolean,
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
requiredSignatures: number,
|
requiredSignatures: number,
|
||||||
setSignatureCollected: Function,
|
setSignatureCollected: Function,
|
||||||
waitingBlocksResolved: boolean,
|
setTimeoutId: (timeoutId: number) => void,
|
||||||
subscriptions: number[],
|
isCancelled: () => boolean,
|
||||||
startBlock: number,
|
startBlock: number,
|
||||||
getFailedTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>,
|
getFailedTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>,
|
||||||
setFailedConfirmations: Function,
|
setFailedConfirmations: Function,
|
||||||
@@ -45,8 +45,6 @@ export const getConfirmationsForTx = async (
|
|||||||
setPendingConfirmations: Function,
|
setPendingConfirmations: Function,
|
||||||
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
||||||
) => {
|
) => {
|
||||||
if (!web3 || !validatorList || !validatorList.length || !bridgeContract || !waitingBlocksResolved) return
|
|
||||||
|
|
||||||
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
|
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
|
||||||
|
|
||||||
const hashMsg = web3.utils.soliditySha3Raw(messageData)
|
const hashMsg = web3.utils.soliditySha3Raw(messageData)
|
||||||
@@ -144,28 +142,30 @@ export const getConfirmationsForTx = async (
|
|||||||
(!hasEnoughSignatures && missingConfirmations.length > 0) ||
|
(!hasEnoughSignatures && missingConfirmations.length > 0) ||
|
||||||
successConfirmationWithTxFound.length < successConfirmationWithData.length
|
successConfirmationWithTxFound.length < successConfirmationWithData.length
|
||||||
) {
|
) {
|
||||||
const timeoutId = setTimeout(
|
if (!isCancelled()) {
|
||||||
() =>
|
const timeoutId = setTimeout(
|
||||||
getConfirmationsForTx(
|
() =>
|
||||||
messageData,
|
getConfirmationsForTx(
|
||||||
web3,
|
messageData,
|
||||||
validatorList,
|
web3,
|
||||||
bridgeContract,
|
validatorList,
|
||||||
fromHome,
|
bridgeContract,
|
||||||
setResult,
|
fromHome,
|
||||||
requiredSignatures,
|
setResult,
|
||||||
setSignatureCollected,
|
requiredSignatures,
|
||||||
waitingBlocksResolved,
|
setSignatureCollected,
|
||||||
subscriptions,
|
setTimeoutId,
|
||||||
startBlock,
|
isCancelled,
|
||||||
getFailedTransactions,
|
startBlock,
|
||||||
setFailedConfirmations,
|
getFailedTransactions,
|
||||||
getPendingTransactions,
|
setFailedConfirmations,
|
||||||
setPendingConfirmations,
|
getPendingTransactions,
|
||||||
getSuccessTransactions
|
setPendingConfirmations,
|
||||||
),
|
getSuccessTransactions
|
||||||
HOME_RPC_POLLING_INTERVAL
|
),
|
||||||
)
|
HOME_RPC_POLLING_INTERVAL
|
||||||
subscriptions.push(timeoutId)
|
)
|
||||||
|
setTimeoutId(timeoutId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,47 @@
|
|||||||
import { Contract, EventData } from 'web3-eth-contract'
|
import { Contract, EventData } from 'web3-eth-contract'
|
||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import { CACHE_KEY_EXECUTION_FAILED, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
import {
|
||||||
|
CACHE_KEY_EXECUTION_FAILED,
|
||||||
|
FOREIGN_EXPLORER_API,
|
||||||
|
FOREIGN_RPC_POLLING_INTERVAL,
|
||||||
|
HOME_EXPLORER_API,
|
||||||
|
HOME_RPC_POLLING_INTERVAL,
|
||||||
|
VALIDATOR_CONFIRMATION_STATUS
|
||||||
|
} from '../config/constants'
|
||||||
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
||||||
import { APIPendingTransaction, APITransaction, GetTransactionParams, GetPendingTransactionParams } from './explorer'
|
import {
|
||||||
|
APIPendingTransaction,
|
||||||
|
APITransaction,
|
||||||
|
GetTransactionParams,
|
||||||
|
GetPendingTransactionParams,
|
||||||
|
getLogs
|
||||||
|
} from './explorer'
|
||||||
import { getBlock, MessageObject } from './web3'
|
import { getBlock, MessageObject } from './web3'
|
||||||
import validatorsCache from '../services/ValidatorsCache'
|
import validatorsCache from '../services/ValidatorsCache'
|
||||||
import { foreignBlockNumberProvider, homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
import { foreignBlockNumberProvider, homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
||||||
|
|
||||||
export const getSuccessExecutionData = async (contract: Contract, eventName: string, web3: Web3, messageId: string) => {
|
const getPastEventsWithFallback = (api: string, web3: Web3, contract: Contract, eventName: string, options: any) =>
|
||||||
|
contract.getPastEvents(eventName, options).catch(
|
||||||
|
() =>
|
||||||
|
api
|
||||||
|
? getLogs(api, web3, contract, eventName, {
|
||||||
|
fromBlock: options.fromBlock,
|
||||||
|
toBlock: options.toBlock,
|
||||||
|
topics: [null, null, options.filter.messageId]
|
||||||
|
})
|
||||||
|
: []
|
||||||
|
)
|
||||||
|
|
||||||
|
export const getSuccessExecutionData = async (
|
||||||
|
contract: Contract,
|
||||||
|
eventName: string,
|
||||||
|
web3: Web3,
|
||||||
|
messageId: string,
|
||||||
|
api: string = ''
|
||||||
|
) => {
|
||||||
// Since it filters by the message id, only one event will be fetched
|
// Since it filters by the message id, only one event will be fetched
|
||||||
// so there is no need to limit the range of the block to reduce the network traffic
|
// so there is no need to limit the range of the block to reduce the network traffic
|
||||||
const events: EventData[] = await contract.getPastEvents(eventName, {
|
const events: EventData[] = await getPastEventsWithFallback(api, web3, contract, eventName, {
|
||||||
fromBlock: 0,
|
fromBlock: 0,
|
||||||
toBlock: 'latest',
|
toBlock: 'latest',
|
||||||
filter: {
|
filter: {
|
||||||
@@ -40,14 +71,12 @@ export const getSuccessExecutionData = async (contract: Contract, eventName: str
|
|||||||
|
|
||||||
export const getFinalizationEvent = async (
|
export const getFinalizationEvent = async (
|
||||||
fromHome: boolean,
|
fromHome: boolean,
|
||||||
contract: Maybe<Contract>,
|
contract: Contract,
|
||||||
eventName: string,
|
web3: Web3,
|
||||||
web3: Maybe<Web3>,
|
|
||||||
setResult: React.Dispatch<React.SetStateAction<ExecutionData>>,
|
setResult: React.Dispatch<React.SetStateAction<ExecutionData>>,
|
||||||
waitingBlocksResolved: boolean,
|
|
||||||
message: MessageObject,
|
message: MessageObject,
|
||||||
interval: number,
|
setTimeoutId: (timeoutId: number) => void,
|
||||||
subscriptions: number[],
|
isCancelled: () => boolean,
|
||||||
startBlock: number,
|
startBlock: number,
|
||||||
collectedSignaturesEvent: Maybe<EventData>,
|
collectedSignaturesEvent: Maybe<EventData>,
|
||||||
getFailedExecution: (args: GetTransactionParams) => Promise<APITransaction[]>,
|
getFailedExecution: (args: GetTransactionParams) => Promise<APITransaction[]>,
|
||||||
@@ -56,8 +85,11 @@ export const getFinalizationEvent = async (
|
|||||||
setPendingExecution: Function,
|
setPendingExecution: Function,
|
||||||
setExecutionEventsFetched: Function
|
setExecutionEventsFetched: Function
|
||||||
) => {
|
) => {
|
||||||
if (!contract || !web3 || !waitingBlocksResolved) return
|
const eventName = fromHome ? 'RelayedMessage' : 'AffirmationCompleted'
|
||||||
const successExecutionData = await getSuccessExecutionData(contract, eventName, web3, message.id)
|
const api = fromHome ? FOREIGN_EXPLORER_API : HOME_EXPLORER_API
|
||||||
|
|
||||||
|
const successExecutionData = await getSuccessExecutionData(contract, eventName, web3, message.id, api)
|
||||||
|
|
||||||
if (successExecutionData) {
|
if (successExecutionData) {
|
||||||
setResult(successExecutionData)
|
setResult(successExecutionData)
|
||||||
} else {
|
} else {
|
||||||
@@ -120,28 +152,28 @@ export const getFinalizationEvent = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeoutId = setTimeout(
|
if (!isCancelled()) {
|
||||||
() =>
|
const timeoutId = setTimeout(
|
||||||
getFinalizationEvent(
|
() =>
|
||||||
fromHome,
|
getFinalizationEvent(
|
||||||
contract,
|
fromHome,
|
||||||
eventName,
|
contract,
|
||||||
web3,
|
web3,
|
||||||
setResult,
|
setResult,
|
||||||
waitingBlocksResolved,
|
message,
|
||||||
message,
|
setTimeoutId,
|
||||||
interval,
|
isCancelled,
|
||||||
subscriptions,
|
startBlock,
|
||||||
startBlock,
|
collectedSignaturesEvent,
|
||||||
collectedSignaturesEvent,
|
getFailedExecution,
|
||||||
getFailedExecution,
|
setFailedExecution,
|
||||||
setFailedExecution,
|
getPendingExecution,
|
||||||
getPendingExecution,
|
setPendingExecution,
|
||||||
setPendingExecution,
|
setExecutionEventsFetched
|
||||||
setExecutionEventsFetched
|
),
|
||||||
),
|
fromHome ? FOREIGN_RPC_POLLING_INTERVAL : HOME_RPC_POLLING_INTERVAL
|
||||||
interval
|
)
|
||||||
)
|
setTimeoutId(timeoutId)
|
||||||
subscriptions.push(timeoutId)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
|
||||||
import { BlockNumberProvider } from '../services/BlockNumberProvider'
|
|
||||||
|
|
||||||
export const checkSignaturesWaitingForBLocks = async (
|
|
||||||
targetBlock: number,
|
|
||||||
setWaitingStatus: Function,
|
|
||||||
setWaitingBlocksResolved: Function,
|
|
||||||
validatorList: string[],
|
|
||||||
setConfirmations: Function,
|
|
||||||
blockProvider: BlockNumberProvider,
|
|
||||||
interval: number,
|
|
||||||
subscriptions: number[]
|
|
||||||
) => {
|
|
||||||
const currentBlock = blockProvider.get()
|
|
||||||
|
|
||||||
if (currentBlock && currentBlock >= targetBlock) {
|
|
||||||
setWaitingBlocksResolved(true)
|
|
||||||
setWaitingStatus(false)
|
|
||||||
} else {
|
|
||||||
let nextInterval = interval
|
|
||||||
if (!currentBlock) {
|
|
||||||
nextInterval = 500
|
|
||||||
} else {
|
|
||||||
const validatorsWaiting = validatorList.map(validator => {
|
|
||||||
return {
|
|
||||||
validator,
|
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.WAITING
|
|
||||||
}
|
|
||||||
})
|
|
||||||
setWaitingStatus(true)
|
|
||||||
setConfirmations(validatorsWaiting)
|
|
||||||
}
|
|
||||||
const timeoutId = setTimeout(
|
|
||||||
() =>
|
|
||||||
checkSignaturesWaitingForBLocks(
|
|
||||||
targetBlock,
|
|
||||||
setWaitingStatus,
|
|
||||||
setWaitingBlocksResolved,
|
|
||||||
validatorList,
|
|
||||||
setConfirmations,
|
|
||||||
blockProvider,
|
|
||||||
interval,
|
|
||||||
subscriptions
|
|
||||||
),
|
|
||||||
nextInterval
|
|
||||||
)
|
|
||||||
subscriptions.push(timeoutId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -56,6 +56,11 @@ const OLD_AMB_USER_REQUEST_FOR_SIGNATURE_ABI = [
|
|||||||
{
|
{
|
||||||
anonymous: false,
|
anonymous: false,
|
||||||
inputs: [
|
inputs: [
|
||||||
|
{
|
||||||
|
indexed: true,
|
||||||
|
name: 'messageId',
|
||||||
|
type: 'bytes32'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
indexed: false,
|
indexed: false,
|
||||||
name: 'encodedData',
|
name: 'encodedData',
|
||||||
@@ -71,6 +76,11 @@ const OLD_AMB_USER_REQUEST_FOR_AFFIRMATION_ABI = [
|
|||||||
{
|
{
|
||||||
anonymous: false,
|
anonymous: false,
|
||||||
inputs: [
|
inputs: [
|
||||||
|
{
|
||||||
|
indexed: true,
|
||||||
|
name: 'messageId',
|
||||||
|
type: 'bytes32'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
indexed: false,
|
indexed: false,
|
||||||
name: 'encodedData',
|
name: 'encodedData',
|
||||||
|
|||||||
@@ -28,3 +28,6 @@ MONITOR_HOME_TO_FOREIGN_BLOCK_LIST=
|
|||||||
|
|
||||||
# MONITOR_HOME_VALIDATORS_BALANCE_ENABLE=0x... 0x... 0x...
|
# MONITOR_HOME_VALIDATORS_BALANCE_ENABLE=0x... 0x... 0x...
|
||||||
# MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE=0x... 0x... 0x...
|
# MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE=0x... 0x... 0x...
|
||||||
|
|
||||||
|
# MONITOR_HOME_EXPLORER_API=
|
||||||
|
MONITOR_FOREIGN_EXPLORER_API=https://api.bscscan.com/api?apikey=YourApiKeyToken
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const logger = require('./logger')('alerts')
|
const logger = require('./logger')('alerts')
|
||||||
const eventsInfo = require('./utils/events')
|
|
||||||
const { processedMsgNotDelivered, eventWithoutReference } = require('./utils/message')
|
const { processedMsgNotDelivered, eventWithoutReference } = require('./utils/message')
|
||||||
const { BRIDGE_MODES } = require('../commons')
|
const { BRIDGE_MODES } = require('../commons')
|
||||||
const { web3Home, web3Foreign, getHomeBlockNumber, getForeignBlockNumber } = require('./utils/web3')
|
const { web3Home, web3Foreign } = require('./utils/web3')
|
||||||
|
|
||||||
async function main() {
|
async function main(eventsInfo) {
|
||||||
const {
|
const {
|
||||||
|
homeBlockNumber,
|
||||||
|
foreignBlockNumber,
|
||||||
homeToForeignRequests,
|
homeToForeignRequests,
|
||||||
homeToForeignConfirmations,
|
homeToForeignConfirmations,
|
||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations,
|
||||||
foreignToHomeRequests,
|
foreignToHomeRequests,
|
||||||
bridgeMode
|
bridgeMode
|
||||||
} = await eventsInfo()
|
} = eventsInfo
|
||||||
|
|
||||||
let xSignatures
|
let xSignatures
|
||||||
let xAffirmations
|
let xAffirmations
|
||||||
@@ -24,8 +25,6 @@ async function main() {
|
|||||||
xAffirmations = foreignToHomeConfirmations.filter(eventWithoutReference(foreignToHomeRequests))
|
xAffirmations = foreignToHomeConfirmations.filter(eventWithoutReference(foreignToHomeRequests))
|
||||||
}
|
}
|
||||||
logger.debug('building misbehavior blocks')
|
logger.debug('building misbehavior blocks')
|
||||||
const homeBlockNumber = await getHomeBlockNumber()
|
|
||||||
const foreignBlockNumber = await getForeignBlockNumber()
|
|
||||||
|
|
||||||
const baseRange = [false, false, false, false, false]
|
const baseRange = [false, false, false, false, false]
|
||||||
const xSignaturesMisbehavior = buildRangesObject(
|
const xSignaturesMisbehavior = buildRangesObject(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const logger = require('./logger')('checkWorker2')
|
const logger = require('./logger')('checkWorker2')
|
||||||
const eventsStats = require('./eventsStats')
|
const eventsStats = require('./eventsStats')
|
||||||
|
const getEventsInfo = require('./utils/events')
|
||||||
const alerts = require('./alerts')
|
const alerts = require('./alerts')
|
||||||
const { writeFile, createDir } = require('./utils/file')
|
const { writeFile, createDir } = require('./utils/file')
|
||||||
const { saveCache } = require('./utils/web3Cache')
|
const { saveCache } = require('./utils/web3Cache')
|
||||||
@@ -10,8 +11,10 @@ const { MONITOR_BRIDGE_NAME } = process.env
|
|||||||
async function checkWorker2() {
|
async function checkWorker2() {
|
||||||
try {
|
try {
|
||||||
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
||||||
|
logger.debug('calling getEventsInfo()')
|
||||||
|
const eventsInfo = await getEventsInfo()
|
||||||
logger.debug('calling eventsStats()')
|
logger.debug('calling eventsStats()')
|
||||||
const evStats = await eventsStats()
|
const evStats = await eventsStats(eventsInfo)
|
||||||
if (!evStats) throw new Error('evStats is empty: ' + JSON.stringify(evStats))
|
if (!evStats) throw new Error('evStats is empty: ' + JSON.stringify(evStats))
|
||||||
evStats.ok =
|
evStats.ok =
|
||||||
(evStats.onlyInHomeDeposits || evStats.home.deliveredMsgNotProcessedInForeign).length === 0 &&
|
(evStats.onlyInHomeDeposits || evStats.home.deliveredMsgNotProcessedInForeign).length === 0 &&
|
||||||
@@ -22,7 +25,7 @@ async function checkWorker2() {
|
|||||||
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/eventsStats.json`, evStats)
|
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/eventsStats.json`, evStats)
|
||||||
|
|
||||||
logger.debug('calling alerts()')
|
logger.debug('calling alerts()')
|
||||||
const _alerts = await alerts()
|
const _alerts = await alerts(eventsInfo)
|
||||||
if (!_alerts) throw new Error('alerts is empty: ' + JSON.stringify(_alerts))
|
if (!_alerts) throw new Error('alerts is empty: ' + JSON.stringify(_alerts))
|
||||||
_alerts.ok = !_alerts.executeAffirmations.mostRecentTxHash && !_alerts.executeSignatures.mostRecentTxHash
|
_alerts.ok = !_alerts.executeAffirmations.mostRecentTxHash && !_alerts.executeSignatures.mostRecentTxHash
|
||||||
_alerts.health = true
|
_alerts.health = true
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
require('dotenv').config()
|
require('dotenv').config()
|
||||||
const eventsInfo = require('./utils/events')
|
|
||||||
const {
|
const {
|
||||||
processedMsgNotDelivered,
|
processedMsgNotDelivered,
|
||||||
deliveredMsgNotProcessed,
|
deliveredMsgNotProcessed,
|
||||||
@@ -15,14 +14,14 @@ const {
|
|||||||
MONITOR_HOME_TO_FOREIGN_CHECK_SENDER
|
MONITOR_HOME_TO_FOREIGN_CHECK_SENDER
|
||||||
} = process.env
|
} = process.env
|
||||||
|
|
||||||
async function main() {
|
async function main(eventsInfo) {
|
||||||
const {
|
const {
|
||||||
homeToForeignRequests,
|
homeToForeignRequests,
|
||||||
homeToForeignConfirmations,
|
homeToForeignConfirmations,
|
||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations,
|
||||||
foreignToHomeRequests,
|
foreignToHomeRequests,
|
||||||
bridgeMode
|
bridgeMode
|
||||||
} = await eventsInfo()
|
} = eventsInfo
|
||||||
|
|
||||||
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -5,7 +5,12 @@ const logger = require('./logger')('getBalances')
|
|||||||
const { BRIDGE_MODES } = require('../commons')
|
const { BRIDGE_MODES } = require('../commons')
|
||||||
const { web3Home, web3Foreign, getHomeBlockNumber } = require('./utils/web3')
|
const { web3Home, web3Foreign, getHomeBlockNumber } = require('./utils/web3')
|
||||||
|
|
||||||
const { COMMON_HOME_BRIDGE_ADDRESS, COMMON_FOREIGN_BRIDGE_ADDRESS } = process.env
|
const {
|
||||||
|
MONITOR_HOME_START_BLOCK,
|
||||||
|
MONITOR_FOREIGN_START_BLOCK,
|
||||||
|
COMMON_HOME_BRIDGE_ADDRESS,
|
||||||
|
COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||||
|
} = process.env
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ERC20_ABI,
|
ERC20_ABI,
|
||||||
@@ -20,6 +25,8 @@ const {
|
|||||||
|
|
||||||
async function main(bridgeMode, eventsInfo) {
|
async function main(bridgeMode, eventsInfo) {
|
||||||
const {
|
const {
|
||||||
|
homeBlockNumber,
|
||||||
|
foreignBlockNumber,
|
||||||
homeToForeignConfirmations,
|
homeToForeignConfirmations,
|
||||||
foreignToHomeConfirmations,
|
foreignToHomeConfirmations,
|
||||||
homeDelayedBlockNumber,
|
homeDelayedBlockNumber,
|
||||||
@@ -46,6 +53,13 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
...foreignToHomeConfirmations.filter(e => e.blockNumber > homeDelayedBlockNumber).map(e => e.value)
|
...foreignToHomeConfirmations.filter(e => e.blockNumber > homeDelayedBlockNumber).map(e => e.value)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const blockRanges = {
|
||||||
|
startBlockHome: MONITOR_HOME_START_BLOCK,
|
||||||
|
endBlockHome: homeBlockNumber,
|
||||||
|
startBlockForeign: MONITOR_FOREIGN_START_BLOCK,
|
||||||
|
endBlockForeign: foreignBlockNumber
|
||||||
|
}
|
||||||
|
|
||||||
if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
|
if (bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
|
||||||
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_ERC_TO_ERC_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
const erc20Address = await foreignBridge.methods.erc20token().call()
|
const erc20Address = await foreignBridge.methods.erc20token().call()
|
||||||
@@ -72,6 +86,7 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
erc20Balance: Web3Utils.fromWei(foreignErc20Balance)
|
erc20Balance: Web3Utils.fromWei(foreignErc20Balance)
|
||||||
},
|
},
|
||||||
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
||||||
|
...blockRanges,
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
} else if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC || bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC_V1) {
|
} else if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC || bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC_V1) {
|
||||||
@@ -94,6 +109,7 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
totalSupply: Web3Utils.fromWei(totalSupply)
|
totalSupply: Web3Utils.fromWei(totalSupply)
|
||||||
},
|
},
|
||||||
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
||||||
|
...blockRanges,
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
} else if (bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
||||||
@@ -163,12 +179,14 @@ async function main(bridgeMode, eventsInfo) {
|
|||||||
},
|
},
|
||||||
foreign,
|
foreign,
|
||||||
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
balanceDiff: Number(Web3Utils.fromWei(diff)),
|
||||||
|
...blockRanges,
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
} else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
} else if (bridgeMode === BRIDGE_MODES.ARBITRARY_MESSAGE) {
|
||||||
return {
|
return {
|
||||||
home: {},
|
home: {},
|
||||||
foreign: {},
|
foreign: {},
|
||||||
|
...blockRanges,
|
||||||
lastChecked: Math.floor(Date.now() / 1000)
|
lastChecked: Math.floor(Date.now() / 1000)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ require('dotenv').config()
|
|||||||
const express = require('express')
|
const express = require('express')
|
||||||
const cors = require('cors')
|
const cors = require('cors')
|
||||||
const { readFile } = require('./utils/file')
|
const { readFile } = require('./utils/file')
|
||||||
const { getPrometheusMetrics } = require('./prometheusMetrics')
|
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
const bridgeRouter = express.Router({ mergeParams: true })
|
const bridgeRouter = express.Router({ mergeParams: true })
|
||||||
@@ -25,7 +24,8 @@ bridgeRouter.get('/:file(validators|eventsStats|alerts|mediators|stuckTransfers|
|
|||||||
|
|
||||||
bridgeRouter.get('/metrics', (req, res, next) => {
|
bridgeRouter.get('/metrics', (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const metrics = getPrometheusMetrics(req.params.bridgeName)
|
const { bridgeName } = req.params
|
||||||
|
const metrics = readFile(`./responses/${bridgeName}/metrics.txt`, false)
|
||||||
res.type('text').send(metrics)
|
res.type('text').send(metrics)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
next(e)
|
next(e)
|
||||||
|
|||||||
20
monitor/metricsWorker.js
Normal file
20
monitor/metricsWorker.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
require('dotenv').config()
|
||||||
|
const logger = require('./logger')('metricsWorker')
|
||||||
|
const { writeFile, createDir } = require('./utils/file')
|
||||||
|
const getPrometheusMetrics = require('./prometheusMetrics')
|
||||||
|
|
||||||
|
const { MONITOR_BRIDGE_NAME } = process.env
|
||||||
|
|
||||||
|
async function metricsWorker() {
|
||||||
|
try {
|
||||||
|
createDir(`/responses/${MONITOR_BRIDGE_NAME}`)
|
||||||
|
logger.debug('calling getPrometheusMetrics()')
|
||||||
|
const metrics = await getPrometheusMetrics(MONITOR_BRIDGE_NAME)
|
||||||
|
if (!metrics) throw new Error('metrics is empty: ' + JSON.stringify(metrics))
|
||||||
|
writeFile(`/responses/${MONITOR_BRIDGE_NAME}/metrics.txt`, metrics, { stringify: false })
|
||||||
|
logger.debug('Done')
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
metricsWorker()
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"check-all": "timeout -s 9 5m node checkWorker.js && timeout -s 9 5m node checkWorker2.js && timeout -s 9 5m node checkWorker3.js",
|
"check-all": "timeout -s 9 5m node checkWorker.js && timeout -s 9 5m node checkWorker2.js && timeout -s 9 5m node checkWorker3.js && timeout -s 9 10s node metricsWorker.js",
|
||||||
"start": "node index.js",
|
"start": "node index.js",
|
||||||
"check-and-start": "yarn check-all && yarn start",
|
"check-and-start": "yarn check-all && yarn start",
|
||||||
"lint": "eslint . --ignore-path ../.eslintignore",
|
"lint": "eslint . --ignore-path ../.eslintignore",
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
require('dotenv').config()
|
||||||
|
const logger = require('./logger')('getBalances')
|
||||||
const { readFile } = require('./utils/file')
|
const { readFile } = require('./utils/file')
|
||||||
|
|
||||||
const {
|
const {
|
||||||
MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST,
|
MONITOR_HOME_START_BLOCK,
|
||||||
MONITOR_HOME_TO_FOREIGN_BLOCK_LIST,
|
MONITOR_FOREIGN_START_BLOCK,
|
||||||
MONITOR_HOME_VALIDATORS_BALANCE_ENABLE,
|
MONITOR_HOME_VALIDATORS_BALANCE_ENABLE,
|
||||||
MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE
|
MONITOR_FOREIGN_VALIDATORS_BALANCE_ENABLE
|
||||||
} = process.env
|
} = process.env
|
||||||
@@ -23,7 +25,9 @@ function hasError(obj) {
|
|||||||
return 'error' in obj
|
return 'error' in obj
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPrometheusMetrics(bridgeName) {
|
// Try to collect all metrics from JSON responses and then
|
||||||
|
// discard all unsuccessfully retrieved ones
|
||||||
|
async function getPrometheusMetrics(bridgeName) {
|
||||||
const responsePath = jsonName => `./responses/${bridgeName}/${jsonName}.json`
|
const responsePath = jsonName => `./responses/${bridgeName}/${jsonName}.json`
|
||||||
|
|
||||||
const metrics = {}
|
const metrics = {}
|
||||||
@@ -32,22 +36,44 @@ function getPrometheusMetrics(bridgeName) {
|
|||||||
const balancesFile = readFile(responsePath('getBalances'))
|
const balancesFile = readFile(responsePath('getBalances'))
|
||||||
|
|
||||||
if (!hasError(balancesFile)) {
|
if (!hasError(balancesFile)) {
|
||||||
const { home: homeBalances, foreign: foreignBalances, ...commonBalances } = balancesFile
|
const { home, foreign, ...commonBalances } = balancesFile
|
||||||
metrics.balances_home_value = homeBalances.totalSupply
|
|
||||||
metrics.balances_home_txs_deposit = homeBalances.deposits
|
|
||||||
metrics.balances_home_txs_withdrawal = homeBalances.withdrawals
|
|
||||||
|
|
||||||
metrics.balances_foreign_value = foreignBalances.erc20Balance
|
const balanceMetrics = {
|
||||||
metrics.balances_foreign_txs_deposit = foreignBalances.deposits
|
// ERC_TO_ERC or ERC_TO_NATIVE mode
|
||||||
metrics.balances_foreign_txs_withdrawal = foreignBalances.withdrawals
|
balances_home_value: home.totalSupply,
|
||||||
|
balances_home_txs_deposit: home.deposits,
|
||||||
|
balances_home_txs_withdrawal: home.withdrawals,
|
||||||
|
balances_foreign_value: foreign.erc20Balance,
|
||||||
|
balances_foreign_txs_deposit: foreign.deposits,
|
||||||
|
balances_foreign_txs_withdrawal: foreign.withdrawals,
|
||||||
|
|
||||||
metrics.balances_diff_value = commonBalances.balanceDiff
|
// Not ARBITRARY_MESSAGE mode
|
||||||
metrics.balances_diff_deposit = commonBalances.depositsDiff
|
balances_diff_value: commonBalances.balanceDiff,
|
||||||
metrics.balances_diff_withdrawal = commonBalances.withdrawalDiff
|
balances_diff_deposit: commonBalances.depositsDiff,
|
||||||
if (MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST || MONITOR_HOME_TO_FOREIGN_BLOCK_LIST) {
|
balances_diff_withdrawal: commonBalances.withdrawalDiff,
|
||||||
metrics.balances_unclaimed_txs = commonBalances.unclaimedDiff
|
|
||||||
metrics.balances_unclaimed_value = commonBalances.unclaimedBalance
|
// MONITOR_HOME_TO_FOREIGN_ALLOWANCE_LIST or MONITOR_HOME_TO_FOREIGN_BLOCK_LIST is set
|
||||||
|
balances_unclaimed_txs: commonBalances.unclaimedDiff,
|
||||||
|
balances_unclaimed_value: commonBalances.unclaimedBalance,
|
||||||
|
|
||||||
|
// ARBITRARY_MESSAGE mode
|
||||||
|
txs_home_out: home.toForeign,
|
||||||
|
txs_home_in: home.fromForeign,
|
||||||
|
txs_foreign_out: foreign.toHome,
|
||||||
|
txs_foreign_in: foreign.fromHome,
|
||||||
|
txs_diff_home_out_oracles: commonBalances.fromHomeToForeignDiff,
|
||||||
|
txs_diff_home_out_users: commonBalances.fromHomeToForeignPBUDiff,
|
||||||
|
txs_diff_foreign_out: commonBalances.fromForeignToHomeDiff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const blockRanges = {
|
||||||
|
state_startblock_home: commonBalances.startBlockHome || MONITOR_HOME_START_BLOCK,
|
||||||
|
state_startblock_foreign: commonBalances.startBlockForeign || MONITOR_FOREIGN_START_BLOCK,
|
||||||
|
state_endblock_home: commonBalances.endBlockHome,
|
||||||
|
state_endblock_foreign: commonBalances.endBlockForeign
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(metrics, blockRanges, balanceMetrics)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validator metrics
|
// Validator metrics
|
||||||
@@ -62,7 +88,11 @@ function getPrometheusMetrics(bridgeName) {
|
|||||||
: Object.keys(allValidators)
|
: Object.keys(allValidators)
|
||||||
|
|
||||||
validatorAddressesWithBalanceCheck.forEach((addr, ind) => {
|
validatorAddressesWithBalanceCheck.forEach((addr, ind) => {
|
||||||
metrics[`validators_balances_${bridge.type}${ind}{address="${addr}"}`] = allValidators[addr].balance
|
if (addr in allValidators) {
|
||||||
|
metrics[`validators_balances_${bridge.type}${ind}{address="${addr}"}`] = allValidators[addr].balance
|
||||||
|
} else {
|
||||||
|
logger.debug(`Nonexistent validator address ${addr}`)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,9 +126,12 @@ function getPrometheusMetrics(bridgeName) {
|
|||||||
return Object.entries(metrics).reduceRight(
|
return Object.entries(metrics).reduceRight(
|
||||||
// Prometheus supports `Nan` and possibly signed `Infinity`
|
// Prometheus supports `Nan` and possibly signed `Infinity`
|
||||||
// in case cast to `Number` fails
|
// in case cast to `Number` fails
|
||||||
(acc, [key, val]) => `${key} ${val ? Number(val) : 0}\n${acc}`,
|
(acc, [key, val]) => {
|
||||||
|
if (typeof val === 'undefined') return acc
|
||||||
|
else return `${key} ${Number(val)}\n${acc}`
|
||||||
|
},
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { getPrometheusMetrics }
|
module.exports = getPrometheusMetrics
|
||||||
|
|||||||
@@ -236,13 +236,15 @@ async function main(mode) {
|
|||||||
foreignToHomeRequests,
|
foreignToHomeRequests,
|
||||||
isExternalErc20,
|
isExternalErc20,
|
||||||
bridgeMode,
|
bridgeMode,
|
||||||
|
homeBlockNumber,
|
||||||
|
foreignBlockNumber,
|
||||||
homeDelayedBlockNumber,
|
homeDelayedBlockNumber,
|
||||||
foreignDelayedBlockNumber
|
foreignDelayedBlockNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MONITOR_CACHE_EVENTS === 'true') {
|
if (MONITOR_CACHE_EVENTS === 'true') {
|
||||||
logger.debug('saving obtained events into cache file')
|
logger.debug('saving obtained events into cache file')
|
||||||
writeFile(cacheFilePath, result, false)
|
writeFile(cacheFilePath, result, { useCwd: false })
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,30 @@
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
function readFile(filePath) {
|
function readFile(filePath, parseJson = true) {
|
||||||
try {
|
try {
|
||||||
const content = fs.readFileSync(filePath)
|
const content = fs.readFileSync(filePath)
|
||||||
|
if (!parseJson) return content
|
||||||
const json = JSON.parse(content)
|
const json = JSON.parse(content)
|
||||||
const timeDiff = Math.floor(Date.now() / 1000) - json.lastChecked
|
const timeDiff = Math.floor(Date.now() / 1000) - json.lastChecked
|
||||||
return Object.assign({}, json, { timeDiff })
|
return Object.assign({}, json, { timeDiff })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error('readFlle', e)
|
||||||
return {
|
return {
|
||||||
error: 'the bridge statistics are not available'
|
error: 'the bridge statistics are not available'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeFile(filePath, object, useCwd = true) {
|
function writeFile(filePath, object, paramOptions = {}) {
|
||||||
|
const defaultOptions = {
|
||||||
|
useCwd: true,
|
||||||
|
stringify: true
|
||||||
|
}
|
||||||
|
const { useCwd, stringify } = Object.assign({}, defaultOptions, paramOptions)
|
||||||
|
|
||||||
const fullPath = useCwd ? path.join(process.cwd(), filePath) : filePath
|
const fullPath = useCwd ? path.join(process.cwd(), filePath) : filePath
|
||||||
fs.writeFileSync(fullPath, JSON.stringify(object, null, 4))
|
fs.writeFileSync(fullPath, stringify ? JSON.stringify(object, null, 4) : object)
|
||||||
}
|
}
|
||||||
|
|
||||||
function createDir(dirPath) {
|
function createDir(dirPath) {
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
|
const fetch = require('node-fetch')
|
||||||
const logger = require('../logger')('web3Cache')
|
const logger = require('../logger')('web3Cache')
|
||||||
const { readCacheFile, writeCacheFile } = require('./file')
|
const { readCacheFile, writeCacheFile } = require('./file')
|
||||||
const { web3Home, web3Foreign } = require('./web3')
|
const { web3Home, web3Foreign } = require('./web3')
|
||||||
const { getPastEvents: commonGetPastEvents } = require('../../commons')
|
const { getPastEvents: commonGetPastEvents } = require('../../commons')
|
||||||
|
|
||||||
const { MONITOR_BRIDGE_NAME, MONITOR_CACHE_EVENTS } = process.env
|
const {
|
||||||
|
MONITOR_BRIDGE_NAME,
|
||||||
|
MONITOR_CACHE_EVENTS,
|
||||||
|
MONITOR_FOREIGN_EXPLORER_API,
|
||||||
|
MONITOR_HOME_EXPLORER_API
|
||||||
|
} = process.env
|
||||||
|
|
||||||
let isDirty = false
|
let isDirty = false
|
||||||
|
|
||||||
@@ -52,6 +58,36 @@ async function isForeignContract(address) {
|
|||||||
return cachedForeignIsContract[address]
|
return cachedForeignIsContract[address]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPastEventsWithAPIFallback(contract, options) {
|
||||||
|
return commonGetPastEvents(contract, options).catch(async e => {
|
||||||
|
const [api, web3] =
|
||||||
|
options.chain === 'home' ? [MONITOR_HOME_EXPLORER_API, web3Home] : [MONITOR_FOREIGN_EXPLORER_API, web3Foreign]
|
||||||
|
if (api && e.message.includes('exceed maximum block range')) {
|
||||||
|
logger.debug('BLOCK RANGE EXCEED, using fallback to the explorer API')
|
||||||
|
|
||||||
|
const abi = contract.options.jsonInterface.find(abi => abi.type === 'event' && abi.name === options.event)
|
||||||
|
|
||||||
|
const url = new URL(api)
|
||||||
|
url.searchParams.append('module', 'logs')
|
||||||
|
url.searchParams.append('action', 'getLogs')
|
||||||
|
url.searchParams.append('address', contract.options.address)
|
||||||
|
url.searchParams.append('fromBlock', options.fromBlock)
|
||||||
|
url.searchParams.append('toBlock', options.toBlock || 'latest')
|
||||||
|
url.searchParams.append('topic0', web3.eth.abi.encodeEventSignature(abi))
|
||||||
|
|
||||||
|
const logs = await fetch(url).then(res => res.json())
|
||||||
|
|
||||||
|
return logs.result.map(log => ({
|
||||||
|
transactionHash: log.transactionHash,
|
||||||
|
blockNumber: parseInt(log.blockNumber.slice(2), 16),
|
||||||
|
returnValues: web3.eth.abi.decodeLog(abi.inputs, log.data, log.topics.slice(1))
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
throw new Error(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function getPastEvents(contract, options) {
|
async function getPastEvents(contract, options) {
|
||||||
if (MONITOR_CACHE_EVENTS !== 'true') {
|
if (MONITOR_CACHE_EVENTS !== 'true') {
|
||||||
return commonGetPastEvents(contract, options)
|
return commonGetPastEvents(contract, options)
|
||||||
@@ -94,14 +130,14 @@ async function getPastEvents(contract, options) {
|
|||||||
// requested: A...B
|
// requested: A...B
|
||||||
// cached: C...D
|
// cached: C...D
|
||||||
logger.debug(`Fetching events for blocks ${fromBlock}...${toBlock}`)
|
logger.debug(`Fetching events for blocks ${fromBlock}...${toBlock}`)
|
||||||
result = await commonGetPastEvents(contract, options)
|
result = await getPastEventsWithAPIFallback(contract, options)
|
||||||
} else if (fromBlock < cachedFromBlock && toBlock <= cachedToBlock) {
|
} else if (fromBlock < cachedFromBlock && toBlock <= cachedToBlock) {
|
||||||
// requested: A...B
|
// requested: A...B
|
||||||
// cached: C...D
|
// cached: C...D
|
||||||
logger.debug(`Cache hit for blocks ${cachedFromBlock}...${toBlock}`)
|
logger.debug(`Cache hit for blocks ${cachedFromBlock}...${toBlock}`)
|
||||||
logger.debug(`Fetching events for blocks ${fromBlock}...${cachedFromBlock - 1}`)
|
logger.debug(`Fetching events for blocks ${fromBlock}...${cachedFromBlock - 1}`)
|
||||||
result = [
|
result = [
|
||||||
...(await commonGetPastEvents(contract, { ...options, toBlock: cachedFromBlock - 1 })),
|
...(await getPastEventsWithAPIFallback(contract, { ...options, toBlock: cachedFromBlock - 1 })),
|
||||||
...cachedEvents.filter(e => e.blockNumber <= toBlock)
|
...cachedEvents.filter(e => e.blockNumber <= toBlock)
|
||||||
]
|
]
|
||||||
} else if (fromBlock < cachedFromBlock && cachedToBlock < toBlock) {
|
} else if (fromBlock < cachedFromBlock && cachedToBlock < toBlock) {
|
||||||
@@ -111,9 +147,9 @@ async function getPastEvents(contract, options) {
|
|||||||
logger.debug(`Fetching events for blocks ${fromBlock}...${cachedFromBlock - 1}`)
|
logger.debug(`Fetching events for blocks ${fromBlock}...${cachedFromBlock - 1}`)
|
||||||
logger.debug(`Fetching events for blocks ${cachedToBlock + 1}...${toBlock}`)
|
logger.debug(`Fetching events for blocks ${cachedToBlock + 1}...${toBlock}`)
|
||||||
result = [
|
result = [
|
||||||
...(await commonGetPastEvents(contract, { ...options, toBlock: cachedFromBlock - 1 })),
|
...(await getPastEventsWithAPIFallback(contract, { ...options, toBlock: cachedFromBlock - 1 })),
|
||||||
...cachedEvents,
|
...cachedEvents,
|
||||||
...(await commonGetPastEvents(contract, { ...options, fromBlock: cachedToBlock + 1 }))
|
...(await getPastEventsWithAPIFallback(contract, { ...options, fromBlock: cachedToBlock + 1 }))
|
||||||
]
|
]
|
||||||
} else if (cachedFromBlock <= fromBlock && toBlock <= cachedToBlock) {
|
} else if (cachedFromBlock <= fromBlock && toBlock <= cachedToBlock) {
|
||||||
// requested: A.B
|
// requested: A.B
|
||||||
@@ -127,7 +163,7 @@ async function getPastEvents(contract, options) {
|
|||||||
logger.debug(`Fetching events for blocks ${cachedToBlock + 1}...${toBlock}`)
|
logger.debug(`Fetching events for blocks ${cachedToBlock + 1}...${toBlock}`)
|
||||||
result = [
|
result = [
|
||||||
...cachedEvents.filter(e => e.blockNumber >= fromBlock),
|
...cachedEvents.filter(e => e.blockNumber >= fromBlock),
|
||||||
...(await commonGetPastEvents(contract, { ...options, fromBlock: cachedToBlock + 1 }))
|
...(await getPastEventsWithAPIFallback(contract, { ...options, fromBlock: cachedToBlock + 1 }))
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ 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
|
||||||
|
ORACLE_HOME_TX_RESEND_INTERVAL=300000
|
||||||
|
|
||||||
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
COMMON_FOREIGN_GAS_PRICE_SUPPLIER_URL=https://gasprice.poa.network/
|
||||||
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
COMMON_FOREIGN_GAS_PRICE_SPEED_TYPE=standard
|
||||||
COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
|
COMMON_FOREIGN_GAS_PRICE_FALLBACK=1000000000
|
||||||
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000
|
ORACLE_FOREIGN_GAS_PRICE_UPDATE_INTERVAL=600000
|
||||||
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
COMMON_FOREIGN_GAS_PRICE_FACTOR=1
|
||||||
|
ORACLE_FOREIGN_TX_RESEND_INTERVAL=1200000
|
||||||
|
|
||||||
ORACLE_QUEUE_URL=amqp://rabbit
|
ORACLE_QUEUE_URL=amqp://rabbit
|
||||||
ORACLE_REDIS_URL=redis://redis
|
ORACLE_REDIS_URL=redis://redis
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
const baseConfig = require('./base.config')
|
const baseConfig = require('./base.config')
|
||||||
|
|
||||||
|
const { DEFAULT_TRANSACTION_RESEND_INTERVAL } = require('../src/utils/constants')
|
||||||
const { web3Foreign, web3ForeignRedundant, web3ForeignFallback } = require('../src/services/web3')
|
const { web3Foreign, web3ForeignRedundant, web3ForeignFallback } = require('../src/services/web3')
|
||||||
|
|
||||||
|
const { ORACLE_FOREIGN_TX_RESEND_INTERVAL } = process.env
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
...baseConfig.bridgeConfig,
|
...baseConfig.bridgeConfig,
|
||||||
queue: 'foreign-prioritized',
|
queue: 'foreign-prioritized',
|
||||||
@@ -10,5 +13,6 @@ module.exports = {
|
|||||||
name: 'sender-foreign',
|
name: 'sender-foreign',
|
||||||
web3: web3Foreign,
|
web3: web3Foreign,
|
||||||
web3Redundant: web3ForeignRedundant,
|
web3Redundant: web3ForeignRedundant,
|
||||||
web3Fallback: web3ForeignFallback
|
web3Fallback: web3ForeignFallback,
|
||||||
|
resendInterval: parseInt(ORACLE_FOREIGN_TX_RESEND_INTERVAL, 10) || DEFAULT_TRANSACTION_RESEND_INTERVAL
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
const baseConfig = require('./base.config')
|
const baseConfig = require('./base.config')
|
||||||
|
|
||||||
|
const { DEFAULT_TRANSACTION_RESEND_INTERVAL } = require('../src/utils/constants')
|
||||||
const { web3Home, web3HomeRedundant, web3HomeFallback } = require('../src/services/web3')
|
const { web3Home, web3HomeRedundant, web3HomeFallback } = require('../src/services/web3')
|
||||||
|
|
||||||
|
const { ORACLE_HOME_TX_RESEND_INTERVAL } = process.env
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
...baseConfig.bridgeConfig,
|
...baseConfig.bridgeConfig,
|
||||||
queue: 'home-prioritized',
|
queue: 'home-prioritized',
|
||||||
@@ -10,5 +13,6 @@ module.exports = {
|
|||||||
name: 'sender-home',
|
name: 'sender-home',
|
||||||
web3: web3Home,
|
web3: web3Home,
|
||||||
web3Redundant: web3HomeRedundant,
|
web3Redundant: web3HomeRedundant,
|
||||||
web3Fallback: web3HomeFallback
|
web3Fallback: web3HomeFallback,
|
||||||
|
resendInterval: parseInt(ORACLE_HOME_TX_RESEND_INTERVAL, 10) || DEFAULT_TRANSACTION_RESEND_INTERVAL
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ async function initialize() {
|
|||||||
connectSenderToQueue({
|
connectSenderToQueue({
|
||||||
queueName: config.queue,
|
queueName: config.queue,
|
||||||
oldQueueName: config.oldQueue,
|
oldQueueName: config.oldQueue,
|
||||||
|
resendInterval: config.resendInterval,
|
||||||
cb: options => {
|
cb: options => {
|
||||||
if (config.maxProcessingTime) {
|
if (config.maxProcessingTime) {
|
||||||
return watchdog(() => main(options), config.maxProcessingTime, () => {
|
return watchdog(() => main(options), config.maxProcessingTime, () => {
|
||||||
@@ -207,7 +208,7 @@ async function main({ msg, ackMsg, nackMsg, channel, scheduleForRetry, scheduleT
|
|||||||
await scheduleForRetry(failedTx, msg.properties.headers['x-retries'])
|
await scheduleForRetry(failedTx, msg.properties.headers['x-retries'])
|
||||||
}
|
}
|
||||||
if (resendJobs.length) {
|
if (resendJobs.length) {
|
||||||
logger.info(`Sending ${resendJobs.length} Tx Delayed Resend Requests to Queue`)
|
logger.info({ delay: config.resendInterval }, `Sending ${resendJobs.length} Tx Delayed Resend Requests to Queue`)
|
||||||
await scheduleTransactionResend(resendJobs)
|
await scheduleTransactionResend(resendJobs)
|
||||||
}
|
}
|
||||||
ackMsg(msg)
|
ackMsg(msg)
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ const connection = require('amqp-connection-manager').connect(process.env.ORACLE
|
|||||||
const logger = require('./logger')
|
const logger = require('./logger')
|
||||||
const { getRetrySequence } = require('../utils/utils')
|
const { getRetrySequence } = require('../utils/utils')
|
||||||
const {
|
const {
|
||||||
TRANSACTION_RESEND_TIMEOUT,
|
|
||||||
SENDER_QUEUE_MAX_PRIORITY,
|
SENDER_QUEUE_MAX_PRIORITY,
|
||||||
SENDER_QUEUE_SEND_PRIORITY,
|
SENDER_QUEUE_SEND_PRIORITY,
|
||||||
SENDER_QUEUE_CHECK_STATUS_PRIORITY
|
SENDER_QUEUE_CHECK_STATUS_PRIORITY
|
||||||
@@ -48,7 +47,7 @@ function connectWatcherToQueue({ queueName, workerQueue, cb }) {
|
|||||||
cb({ sendToQueue, sendToWorker, channel: channelWrapper })
|
cb({ sendToQueue, sendToWorker, channel: channelWrapper })
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectSenderToQueue({ queueName, oldQueueName, cb }) {
|
function connectSenderToQueue({ queueName, oldQueueName, cb, resendInterval }) {
|
||||||
const deadLetterExchange = `${queueName}-retry`
|
const deadLetterExchange = `${queueName}-retry`
|
||||||
|
|
||||||
async function resendMessagesToNewQueue(channel) {
|
async function resendMessagesToNewQueue(channel) {
|
||||||
@@ -97,7 +96,8 @@ function connectSenderToQueue({ queueName, oldQueueName, cb }) {
|
|||||||
channelWrapper,
|
channelWrapper,
|
||||||
channel,
|
channel,
|
||||||
queueName,
|
queueName,
|
||||||
deadLetterExchange
|
deadLetterExchange,
|
||||||
|
delay: resendInterval
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -164,13 +164,13 @@ async function generateRetry({ data, msgRetries, channelWrapper, channel, queueN
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateTransactionResend({ data, channelWrapper, channel, queueName, deadLetterExchange }) {
|
async function generateTransactionResend({ data, channelWrapper, channel, queueName, deadLetterExchange, delay }) {
|
||||||
const retryQueue = `${queueName}-check-tx-status`
|
const retryQueue = `${queueName}-check-tx-status-${delay}`
|
||||||
await channel.assertQueue(retryQueue, {
|
await channel.assertQueue(retryQueue, {
|
||||||
durable: true,
|
durable: true,
|
||||||
deadLetterExchange,
|
deadLetterExchange,
|
||||||
messageTtl: TRANSACTION_RESEND_TIMEOUT,
|
messageTtl: delay,
|
||||||
expires: TRANSACTION_RESEND_TIMEOUT * 10,
|
expires: delay * 10,
|
||||||
maxPriority: SENDER_QUEUE_MAX_PRIORITY
|
maxPriority: SENDER_QUEUE_MAX_PRIORITY
|
||||||
})
|
})
|
||||||
await channelWrapper.sendToQueue(retryQueue, data, {
|
await channelWrapper.sendToQueue(retryQueue, data, {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ module.exports = {
|
|||||||
MIN: 1,
|
MIN: 1,
|
||||||
MAX: 1000
|
MAX: 1000
|
||||||
},
|
},
|
||||||
TRANSACTION_RESEND_TIMEOUT: 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,
|
||||||
SENDER_QUEUE_MAX_PRIORITY: 10,
|
SENDER_QUEUE_MAX_PRIORITY: 10,
|
||||||
SENDER_QUEUE_SEND_PRIORITY: 5,
|
SENDER_QUEUE_SEND_PRIORITY: 5,
|
||||||
|
|||||||
@@ -13953,6 +13953,11 @@ node-fetch@^2.1.2, node-fetch@^2.3.0, node-fetch@^2.5.0:
|
|||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||||
|
|
||||||
|
node-fetch@^2.6.1:
|
||||||
|
version "2.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||||
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
|
|
||||||
node-forge@0.7.5:
|
node-forge@0.7.5:
|
||||||
version "0.7.5"
|
version "0.7.5"
|
||||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df"
|
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df"
|
||||||
|
|||||||
Reference in New Issue
Block a user