Merge the develop branch to the master branch, preparation to v3.6.0
This merge contains the following set of changes: * [Oracle, Fix] Add missing Ganache nonce error message (#651) * [ALM, Improvement] ALM: show manually added signatures (#653)
This commit is contained in:
commit
bcf16144c1
@ -1,9 +1,9 @@
|
|||||||
import React from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
import { TransactionReceipt } from 'web3-eth'
|
||||||
import { useMessageConfirmations } from '../hooks/useMessageConfirmations'
|
import { useMessageConfirmations } from '../hooks/useMessageConfirmations'
|
||||||
import { MessageObject } from '../utils/web3'
|
import { MessageObject } from '../utils/web3'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { CONFIRMATIONS_STATUS } from '../config/constants'
|
import { CONFIRMATIONS_STATUS, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||||
import { CONFIRMATIONS_STATUS_LABEL, CONFIRMATIONS_STATUS_LABEL_HOME } from '../config/descriptions'
|
import { CONFIRMATIONS_STATUS_LABEL, CONFIRMATIONS_STATUS_LABEL_HOME } from '../config/descriptions'
|
||||||
import { SimpleLoading } from './commons/Loading'
|
import { SimpleLoading } from './commons/Loading'
|
||||||
import { ValidatorsConfirmations } from './ValidatorsConfirmations'
|
import { ValidatorsConfirmations } from './ValidatorsConfirmations'
|
||||||
@ -54,7 +54,9 @@ export const ConfirmationsContainer = ({
|
|||||||
home: { name: homeName },
|
home: { name: homeName },
|
||||||
foreign: { name: foreignName }
|
foreign: { name: foreignName }
|
||||||
} = useStateProvider()
|
} = useStateProvider()
|
||||||
const { requiredSignatures, validatorList } = useValidatorContract(fromHome, receipt ? receipt.blockNumber : 0)
|
const src = useValidatorContract(fromHome, receipt ? receipt.blockNumber : 0)
|
||||||
|
const [executionBlockNumber, setExecutionBlockNumber] = useState(0)
|
||||||
|
const dst = useValidatorContract(!fromHome, executionBlockNumber || 'latest')
|
||||||
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
|
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
|
||||||
const {
|
const {
|
||||||
confirmations,
|
confirmations,
|
||||||
@ -71,11 +73,21 @@ export const ConfirmationsContainer = ({
|
|||||||
fromHome,
|
fromHome,
|
||||||
homeStartBlock,
|
homeStartBlock,
|
||||||
foreignStartBlock,
|
foreignStartBlock,
|
||||||
requiredSignatures,
|
requiredSignatures: src.requiredSignatures,
|
||||||
validatorList,
|
validatorList: src.validatorList,
|
||||||
|
targetValidatorList: dst.validatorList,
|
||||||
blockConfirmations
|
blockConfirmations
|
||||||
})
|
})
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() => {
|
||||||
|
if (executionBlockNumber || executionData.status !== VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS) return
|
||||||
|
|
||||||
|
setExecutionBlockNumber(executionData.blockNumber)
|
||||||
|
},
|
||||||
|
[executionData.status, executionBlockNumber, executionData.blockNumber]
|
||||||
|
)
|
||||||
|
|
||||||
const statusLabel = fromHome ? CONFIRMATIONS_STATUS_LABEL_HOME : CONFIRMATIONS_STATUS_LABEL
|
const statusLabel = fromHome ? CONFIRMATIONS_STATUS_LABEL_HOME : CONFIRMATIONS_STATUS_LABEL
|
||||||
|
|
||||||
const parseDescription = () => {
|
const parseDescription = () => {
|
||||||
@ -114,9 +126,9 @@ export const ConfirmationsContainer = ({
|
|||||||
</MultiLine>
|
</MultiLine>
|
||||||
</StatusDescription>
|
</StatusDescription>
|
||||||
<ValidatorsConfirmations
|
<ValidatorsConfirmations
|
||||||
confirmations={confirmations}
|
confirmations={fromHome ? confirmations.filter(c => dst.validatorList.includes(c.validator)) : confirmations}
|
||||||
requiredSignatures={requiredSignatures}
|
requiredSignatures={dst.requiredSignatures}
|
||||||
validatorList={validatorList}
|
validatorList={dst.validatorList}
|
||||||
waitingBlocksResolved={waitingBlocksResolved}
|
waitingBlocksResolved={waitingBlocksResolved}
|
||||||
/>
|
/>
|
||||||
{signatureCollected && (
|
{signatureCollected && (
|
||||||
@ -124,10 +136,12 @@ export const ConfirmationsContainer = ({
|
|||||||
message={message}
|
message={message}
|
||||||
executionData={executionData}
|
executionData={executionData}
|
||||||
isHome={!fromHome}
|
isHome={!fromHome}
|
||||||
signatureCollected={signatureCollected}
|
confirmations={confirmations}
|
||||||
setExecutionData={setExecutionData}
|
setExecutionData={setExecutionData}
|
||||||
executionEventsFetched={executionEventsFetched}
|
executionEventsFetched={executionEventsFetched}
|
||||||
setPendingExecution={setPendingExecution}
|
setPendingExecution={setPendingExecution}
|
||||||
|
dstRequiredSignatures={dst.requiredSignatures}
|
||||||
|
dstValidatorList={dst.validatorList}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</StyledConfirmationContainer>
|
</StyledConfirmationContainer>
|
||||||
|
@ -4,7 +4,7 @@ import { useWindowWidth } from '@react-hook/window-size'
|
|||||||
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS, ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from '../config/constants'
|
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS, ALM_HOME_TO_FOREIGN_MANUAL_EXECUTION } from '../config/constants'
|
||||||
import { SimpleLoading } from './commons/Loading'
|
import { SimpleLoading } from './commons/Loading'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
import { ConfirmationParam, ExecutionData } from '../hooks/useMessageConfirmations'
|
||||||
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
||||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||||
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
||||||
@ -22,20 +22,24 @@ export interface ExecutionConfirmationParams {
|
|||||||
message: MessageObject
|
message: MessageObject
|
||||||
executionData: ExecutionData
|
executionData: ExecutionData
|
||||||
setExecutionData: Function
|
setExecutionData: Function
|
||||||
signatureCollected: boolean | string[]
|
confirmations: ConfirmationParam[]
|
||||||
isHome: boolean
|
isHome: boolean
|
||||||
executionEventsFetched: boolean
|
executionEventsFetched: boolean
|
||||||
setPendingExecution: Function
|
setPendingExecution: Function
|
||||||
|
dstRequiredSignatures: number
|
||||||
|
dstValidatorList: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ExecutionConfirmation = ({
|
export const ExecutionConfirmation = ({
|
||||||
message,
|
message,
|
||||||
executionData,
|
executionData,
|
||||||
setExecutionData,
|
setExecutionData,
|
||||||
signatureCollected,
|
confirmations,
|
||||||
isHome,
|
isHome,
|
||||||
executionEventsFetched,
|
executionEventsFetched,
|
||||||
setPendingExecution
|
setPendingExecution,
|
||||||
|
dstRequiredSignatures,
|
||||||
|
dstValidatorList
|
||||||
}: ExecutionConfirmationParams) => {
|
}: ExecutionConfirmationParams) => {
|
||||||
const { foreign } = useStateProvider()
|
const { foreign } = useStateProvider()
|
||||||
const [safeExecutionAvailable, setSafeExecutionAvailable] = useState(false)
|
const [safeExecutionAvailable, setSafeExecutionAvailable] = useState(false)
|
||||||
@ -152,9 +156,11 @@ export const ExecutionConfirmation = ({
|
|||||||
safeExecutionAvailable={safeExecutionAvailable}
|
safeExecutionAvailable={safeExecutionAvailable}
|
||||||
messageData={message.data}
|
messageData={message.data}
|
||||||
setExecutionData={setExecutionData}
|
setExecutionData={setExecutionData}
|
||||||
signatureCollected={signatureCollected as string[]}
|
confirmations={confirmations}
|
||||||
setPendingExecution={setPendingExecution}
|
setPendingExecution={setPendingExecution}
|
||||||
setError={setError}
|
setError={setError}
|
||||||
|
requiredSignatures={dstRequiredSignatures}
|
||||||
|
validatorList={dstValidatorList}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
)}
|
)}
|
||||||
|
@ -14,7 +14,7 @@ import { useStateProvider } from '../state/StateProvider'
|
|||||||
import { signatureToVRS, packSignatures } from '../utils/signatures'
|
import { signatureToVRS, packSignatures } from '../utils/signatures'
|
||||||
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
|
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
import { TransactionReceipt } from 'web3-eth'
|
||||||
import { useValidatorContract } from '../hooks/useValidatorContract'
|
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||||
|
|
||||||
const ActionButton = styled.button`
|
const ActionButton = styled.button`
|
||||||
color: var(--button-color);
|
color: var(--button-color);
|
||||||
@ -31,18 +31,22 @@ interface ManualExecutionButtonParams {
|
|||||||
safeExecutionAvailable: boolean
|
safeExecutionAvailable: boolean
|
||||||
messageData: string
|
messageData: string
|
||||||
setExecutionData: Function
|
setExecutionData: Function
|
||||||
signatureCollected: string[]
|
confirmations: ConfirmationParam[]
|
||||||
setPendingExecution: Function
|
setPendingExecution: Function
|
||||||
setError: Function
|
setError: Function
|
||||||
|
requiredSignatures: number
|
||||||
|
validatorList: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ManualExecutionButton = ({
|
export const ManualExecutionButton = ({
|
||||||
safeExecutionAvailable,
|
safeExecutionAvailable,
|
||||||
messageData,
|
messageData,
|
||||||
setExecutionData,
|
setExecutionData,
|
||||||
signatureCollected,
|
confirmations,
|
||||||
setPendingExecution,
|
setPendingExecution,
|
||||||
setError
|
setError,
|
||||||
|
requiredSignatures,
|
||||||
|
validatorList
|
||||||
}: ManualExecutionButtonParams) => {
|
}: ManualExecutionButtonParams) => {
|
||||||
const { foreign } = useStateProvider()
|
const { foreign } = useStateProvider()
|
||||||
const { library, activate, account, active } = useWeb3React()
|
const { library, activate, account, active } = useWeb3React()
|
||||||
@ -52,15 +56,13 @@ export const ManualExecutionButton = ({
|
|||||||
const [title, setTitle] = useState('Loading')
|
const [title, setTitle] = useState('Loading')
|
||||||
const [validSignatures, setValidSignatures] = useState<string[]>([])
|
const [validSignatures, setValidSignatures] = useState<string[]>([])
|
||||||
|
|
||||||
const { requiredSignatures, validatorList } = useValidatorContract(false, 'latest')
|
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (
|
if (
|
||||||
!foreign.bridgeContract ||
|
!foreign.bridgeContract ||
|
||||||
!foreign.web3 ||
|
!foreign.web3 ||
|
||||||
!signatureCollected ||
|
!confirmations ||
|
||||||
!signatureCollected.length ||
|
!confirmations.length ||
|
||||||
!requiredSignatures ||
|
!requiredSignatures ||
|
||||||
!validatorList ||
|
!validatorList ||
|
||||||
!validatorList.length
|
!validatorList.length
|
||||||
@ -68,39 +70,20 @@ export const ManualExecutionButton = ({
|
|||||||
return
|
return
|
||||||
|
|
||||||
const signatures = []
|
const signatures = []
|
||||||
const remainingValidators = Object.fromEntries(validatorList.map(validator => [validator, true]))
|
for (let i = 0; i < confirmations.length && signatures.length < requiredSignatures; i++) {
|
||||||
for (let i = 0; i < signatureCollected.length && signatures.length < requiredSignatures; i++) {
|
const sig = confirmations[i].signature
|
||||||
const { v, r, s } = signatureToVRS(signatureCollected[i])
|
if (!sig) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const { v, r, s } = signatureToVRS(sig)
|
||||||
const signer = foreign.web3.eth.accounts.recover(messageData, `0x${v}`, `0x${r}`, `0x${s}`)
|
const signer = foreign.web3.eth.accounts.recover(messageData, `0x${v}`, `0x${r}`, `0x${s}`)
|
||||||
if (validatorList.includes(signer)) {
|
if (validatorList.includes(signer)) {
|
||||||
delete remainingValidators[signer]
|
signatures.push(sig)
|
||||||
signatures.push(signatureCollected[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signatures.length < requiredSignatures) {
|
|
||||||
console.log('On-chain collected signatures are not enough for message execution')
|
|
||||||
const manualValidators = Object.keys(remainingValidators)
|
|
||||||
const msgHash = foreign.web3.utils.sha3(messageData)!
|
|
||||||
for (let i = 0; i < manualValidators.length && signatures.length < requiredSignatures; i++) {
|
|
||||||
try {
|
|
||||||
const overrideSignatures: {
|
|
||||||
[key: string]: string
|
|
||||||
} = require(`../snapshots/signatures_${manualValidators[i]}.json`)
|
|
||||||
if (overrideSignatures[msgHash]) {
|
|
||||||
console.log(`Adding manual signature from ${manualValidators[i]}`)
|
|
||||||
signatures.push(overrideSignatures[msgHash])
|
|
||||||
} else {
|
|
||||||
console.log(`No manual signature from ${manualValidators[i]} was found`)
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.log(`Signatures overrides are not present for ${manualValidators[i]}`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signatures.length >= requiredSignatures) {
|
if (signatures.length >= requiredSignatures) {
|
||||||
setValidSignatures(signatures)
|
setValidSignatures(signatures.slice(0, requiredSignatures))
|
||||||
setTitle('Execute')
|
setTitle('Execute')
|
||||||
setReady(true)
|
setReady(true)
|
||||||
} else {
|
} else {
|
||||||
@ -110,11 +93,11 @@ export const ManualExecutionButton = ({
|
|||||||
[
|
[
|
||||||
foreign.bridgeContract,
|
foreign.bridgeContract,
|
||||||
foreign.web3,
|
foreign.web3,
|
||||||
signatureCollected,
|
|
||||||
validatorList,
|
validatorList,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
messageData,
|
messageData,
|
||||||
setValidSignatures
|
setValidSignatures,
|
||||||
|
confirmations
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
|
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
|
||||||
import { useWindowWidth } from '@react-hook/window-size'
|
import { useWindowWidth } from '@react-hook/window-size'
|
||||||
import { SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
import { RECENT_AGE, SEARCHING_TX, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||||
import { SimpleLoading } from './commons/Loading'
|
import { SimpleLoading } from './commons/Loading'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
|
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||||
@ -31,7 +31,9 @@ export const ValidatorsConfirmations = ({
|
|||||||
const getValidatorStatusElement = (validatorStatus = '') => {
|
const getValidatorStatusElement = (validatorStatus = '') => {
|
||||||
switch (validatorStatus) {
|
switch (validatorStatus) {
|
||||||
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
|
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
|
||||||
return <SuccessLabel>{validatorStatus}</SuccessLabel>
|
case VALIDATOR_CONFIRMATION_STATUS.MANUAL:
|
||||||
|
case VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID:
|
||||||
|
return <SuccessLabel>{VALIDATOR_CONFIRMATION_STATUS.SUCCESS}</SuccessLabel>
|
||||||
case VALIDATOR_CONFIRMATION_STATUS.FAILED:
|
case VALIDATOR_CONFIRMATION_STATUS.FAILED:
|
||||||
return <RedLabel>{validatorStatus}</RedLabel>
|
return <RedLabel>{validatorStatus}</RedLabel>
|
||||||
case VALIDATOR_CONFIRMATION_STATUS.PENDING:
|
case VALIDATOR_CONFIRMATION_STATUS.PENDING:
|
||||||
@ -58,26 +60,28 @@ export const ValidatorsConfirmations = ({
|
|||||||
</tr>
|
</tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{validatorList.map((validator, i) => {
|
{confirmations.map((confirmation, i) => {
|
||||||
const filteredConfirmation = confirmations.filter(c => c.validator === validator)
|
const displayedStatus = confirmation.status
|
||||||
const confirmation = filteredConfirmation.length > 0 ? filteredConfirmation[0] : null
|
const explorerLink = getExplorerTxUrl(confirmation.txHash, true)
|
||||||
const displayedStatus = confirmation && confirmation.status ? confirmation.status : ''
|
let elementIfNoTimestamp: any = <SimpleLoading />
|
||||||
const explorerLink = confirmation && confirmation.txHash ? getExplorerTxUrl(confirmation.txHash, true) : ''
|
switch (displayedStatus) {
|
||||||
const elementIfNoTimestamp =
|
case '':
|
||||||
displayedStatus !== VALIDATOR_CONFIRMATION_STATUS.WAITING &&
|
case VALIDATOR_CONFIRMATION_STATUS.UNDEFINED:
|
||||||
displayedStatus !== VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED ? (
|
if (waitingBlocksResolved) {
|
||||||
(displayedStatus === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || displayedStatus === '') &&
|
elementIfNoTimestamp = SEARCHING_TX
|
||||||
waitingBlocksResolved ? (
|
}
|
||||||
SEARCHING_TX
|
break
|
||||||
) : (
|
case VALIDATOR_CONFIRMATION_STATUS.WAITING:
|
||||||
<SimpleLoading />
|
case VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED:
|
||||||
)
|
elementIfNoTimestamp = ''
|
||||||
) : (
|
break
|
||||||
''
|
case VALIDATOR_CONFIRMATION_STATUS.MANUAL:
|
||||||
)
|
elementIfNoTimestamp = RECENT_AGE
|
||||||
|
break
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<tr key={i}>
|
<tr key={i}>
|
||||||
<td>{windowWidth < 850 ? formatTxHash(validator) : validator}</td>
|
<td>{windowWidth < 850 ? formatTxHash(confirmation.validator) : confirmation.validator}</td>
|
||||||
<StatusTd className="text-center">{getValidatorStatusElement(displayedStatus)}</StatusTd>
|
<StatusTd className="text-center">{getValidatorStatusElement(displayedStatus)}</StatusTd>
|
||||||
<AgeTd className="text-center">
|
<AgeTd className="text-center">
|
||||||
{confirmation && confirmation.timestamp > 0 ? (
|
{confirmation && confirmation.timestamp > 0 ? (
|
||||||
|
@ -55,14 +55,18 @@ export const CONFIRMATIONS_STATUS = {
|
|||||||
|
|
||||||
export const VALIDATOR_CONFIRMATION_STATUS = {
|
export const VALIDATOR_CONFIRMATION_STATUS = {
|
||||||
SUCCESS: 'Confirmed',
|
SUCCESS: 'Confirmed',
|
||||||
|
MANUAL: 'Manual',
|
||||||
EXECUTION_SUCCESS: 'Executed',
|
EXECUTION_SUCCESS: 'Executed',
|
||||||
FAILED: 'Failed',
|
FAILED: 'Failed',
|
||||||
|
FAILED_VALID: 'Failed valid',
|
||||||
PENDING: 'Pending',
|
PENDING: 'Pending',
|
||||||
WAITING: 'Waiting',
|
WAITING: 'Waiting',
|
||||||
NOT_REQUIRED: 'Not required',
|
NOT_REQUIRED: 'Not required',
|
||||||
UNDEFINED: 'UNDEFINED'
|
UNDEFINED: 'UNDEFINED'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const RECENT_AGE = 'Recent'
|
||||||
|
|
||||||
export const SEARCHING_TX = 'Searching Transaction...'
|
export const SEARCHING_TX = 'Searching Transaction...'
|
||||||
|
|
||||||
export const INCORRECT_CHAIN_ERROR = `Incorrect chain chosen. Switch to ${FOREIGN_NETWORK_NAME} in the wallet.`
|
export const INCORRECT_CHAIN_ERROR = `Incorrect chain chosen. Switch to ${FOREIGN_NETWORK_NAME} in the wallet.`
|
||||||
|
@ -29,17 +29,16 @@ export interface useMessageConfirmationsParams {
|
|||||||
foreignStartBlock: Maybe<number>
|
foreignStartBlock: Maybe<number>
|
||||||
requiredSignatures: number
|
requiredSignatures: number
|
||||||
validatorList: string[]
|
validatorList: string[]
|
||||||
|
targetValidatorList: string[]
|
||||||
blockConfirmations: number
|
blockConfirmations: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BasicConfirmationParam {
|
export interface ConfirmationParam {
|
||||||
validator: string
|
validator: string
|
||||||
status: string
|
status: string
|
||||||
}
|
|
||||||
|
|
||||||
export interface ConfirmationParam extends BasicConfirmationParam {
|
|
||||||
txHash: string
|
txHash: string
|
||||||
timestamp: number
|
timestamp: number
|
||||||
|
signature?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExecutionData {
|
export interface ExecutionData {
|
||||||
@ -48,6 +47,7 @@ export interface ExecutionData {
|
|||||||
txHash: string
|
txHash: string
|
||||||
timestamp: number
|
timestamp: number
|
||||||
executionResult: boolean
|
executionResult: boolean
|
||||||
|
blockNumber: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMessageConfirmations = ({
|
export const useMessageConfirmations = ({
|
||||||
@ -58,6 +58,7 @@ export const useMessageConfirmations = ({
|
|||||||
foreignStartBlock,
|
foreignStartBlock,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
validatorList,
|
validatorList,
|
||||||
|
targetValidatorList,
|
||||||
blockConfirmations
|
blockConfirmations
|
||||||
}: useMessageConfirmationsParams) => {
|
}: useMessageConfirmationsParams) => {
|
||||||
const { home, foreign } = useStateProvider()
|
const { home, foreign } = useStateProvider()
|
||||||
@ -65,7 +66,7 @@ export const useMessageConfirmations = ({
|
|||||||
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<boolean | string[]>(false)
|
const [signatureCollected, setSignatureCollected] = useState(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>({
|
||||||
@ -73,7 +74,8 @@ export const useMessageConfirmations = ({
|
|||||||
validator: '',
|
validator: '',
|
||||||
txHash: '',
|
txHash: '',
|
||||||
timestamp: 0,
|
timestamp: 0,
|
||||||
executionResult: false
|
executionResult: false,
|
||||||
|
blockNumber: 0
|
||||||
})
|
})
|
||||||
const [waitingBlocksForExecution, setWaitingBlocksForExecution] = useState(false)
|
const [waitingBlocksForExecution, setWaitingBlocksForExecution] = useState(false)
|
||||||
const [waitingBlocksForExecutionResolved, setWaitingBlocksForExecutionResolved] = useState(false)
|
const [waitingBlocksForExecutionResolved, setWaitingBlocksForExecutionResolved] = useState(false)
|
||||||
@ -140,10 +142,9 @@ export const useMessageConfirmations = ({
|
|||||||
// 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 || !home.bridgeContract || !hasCollectedSignatures) return
|
if (!fromHome || !receipt || !home.web3 || !home.bridgeContract || !signatureCollected) return
|
||||||
|
|
||||||
let timeoutId: number
|
let timeoutId: number
|
||||||
let isCancelled = false
|
let isCancelled = false
|
||||||
@ -179,7 +180,7 @@ export const useMessageConfirmations = ({
|
|||||||
isCancelled = true
|
isCancelled = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[fromHome, home.bridgeContract, home.web3, message.data, receipt, hasCollectedSignatures]
|
[fromHome, home.bridgeContract, home.web3, message.data, receipt, signatureCollected]
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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
|
||||||
@ -252,6 +253,35 @@ export const useMessageConfirmations = ({
|
|||||||
let timeoutId: number
|
let timeoutId: number
|
||||||
let isCancelled = false
|
let isCancelled = false
|
||||||
|
|
||||||
|
if (fromHome) {
|
||||||
|
if (!targetValidatorList || !targetValidatorList.length) return
|
||||||
|
const msgHash = home.web3.utils.sha3(message.data)!
|
||||||
|
const allValidators = [...validatorList, ...targetValidatorList].filter((v, i, s) => s.indexOf(v) === i)
|
||||||
|
const manualConfirmations = []
|
||||||
|
for (let i = 0; i < allValidators.length; i++) {
|
||||||
|
try {
|
||||||
|
const overrideSignatures: {
|
||||||
|
[key: string]: string
|
||||||
|
} = require(`../snapshots/signatures_${allValidators[i]}.json`)
|
||||||
|
if (overrideSignatures[msgHash]) {
|
||||||
|
console.log(`Adding manual signature from ${allValidators[i]}`)
|
||||||
|
manualConfirmations.push({
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.MANUAL,
|
||||||
|
validator: allValidators[i],
|
||||||
|
timestamp: 0,
|
||||||
|
txHash: '',
|
||||||
|
signature: overrideSignatures[msgHash]
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log(`No manual signature from ${allValidators[i]} was found`)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Signatures overrides are not present for ${allValidators[i]}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setConfirmations(manualConfirmations)
|
||||||
|
}
|
||||||
|
|
||||||
getConfirmationsForTx(
|
getConfirmationsForTx(
|
||||||
message.data,
|
message.data,
|
||||||
home.web3,
|
home.web3,
|
||||||
@ -284,7 +314,8 @@ export const useMessageConfirmations = ({
|
|||||||
home.bridgeContract,
|
home.bridgeContract,
|
||||||
requiredSignatures,
|
requiredSignatures,
|
||||||
waitingBlocksResolved,
|
waitingBlocksResolved,
|
||||||
homeStartBlock
|
homeStartBlock,
|
||||||
|
targetValidatorList
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,37 +14,40 @@ const messageData = '0x123456'
|
|||||||
const OTHER_HASH = 'aabbccdd'
|
const OTHER_HASH = 'aabbccdd'
|
||||||
const bridgeAddress = '0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560'
|
const bridgeAddress = '0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560'
|
||||||
const otherAddress = '0xD4075FB57fCf038bFc702c915Ef9592534bED5c1'
|
const otherAddress = '0xD4075FB57fCf038bFc702c915Ef9592534bED5c1'
|
||||||
|
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
||||||
|
const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
|
||||||
|
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
|
||||||
|
|
||||||
describe('getFailedTransactions', () => {
|
describe('getFailedTransactions', () => {
|
||||||
test('should only return failed transactions', async () => {
|
test('should only return failed transactions', async () => {
|
||||||
const to = otherAddress
|
const to = otherAddress
|
||||||
const transactions = [
|
const transactions = [
|
||||||
{ isError: '0', to },
|
{ isError: '0', to, from: validator1 },
|
||||||
{ isError: '1', to },
|
{ isError: '1', to, from: validator1 },
|
||||||
{ isError: '0', to },
|
{ isError: '0', to, from: validator2 },
|
||||||
{ isError: '1', to },
|
{ isError: '1', to, from: validator2 },
|
||||||
{ isError: '1', to }
|
{ isError: '1', to, from: validator3 }
|
||||||
]
|
]
|
||||||
|
|
||||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||||
const result = await getFailedTransactions('', to, 0, 1, '', fetchAccountTransactions)
|
const result = await getFailedTransactions(validator1, to, 0, 1, '', fetchAccountTransactions)
|
||||||
expect(result.length).toEqual(3)
|
expect(result.length).toEqual(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe('getSuccessTransactions', () => {
|
describe('getSuccessTransactions', () => {
|
||||||
test('should only return success transactions', async () => {
|
test('should only return success transactions', async () => {
|
||||||
const to = otherAddress
|
const to = otherAddress
|
||||||
const transactions = [
|
const transactions = [
|
||||||
{ isError: '0', to },
|
{ isError: '0', to, from: validator1 },
|
||||||
{ isError: '1', to },
|
{ isError: '1', to, from: validator1 },
|
||||||
{ isError: '0', to },
|
{ isError: '0', to, from: validator2 },
|
||||||
{ isError: '1', to },
|
{ isError: '1', to, from: validator2 },
|
||||||
{ isError: '1', to }
|
{ isError: '1', to, from: validator3 }
|
||||||
]
|
]
|
||||||
|
|
||||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||||
const result = await getSuccessTransactions('', to, 0, 1, '', fetchAccountTransactions)
|
const result = await getSuccessTransactions(validator1, to, 0, 1, '', fetchAccountTransactions)
|
||||||
expect(result.length).toEqual(2)
|
expect(result.length).toEqual(1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe('filterValidatorSignatureTransaction', () => {
|
describe('filterValidatorSignatureTransaction', () => {
|
||||||
|
@ -5,7 +5,7 @@ import Web3 from 'web3'
|
|||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { APIPendingTransaction, APITransaction } from '../explorer'
|
import { APIPendingTransaction, APITransaction } from '../explorer'
|
||||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
|
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
|
||||||
import { BasicConfirmationParam } from '../../hooks/useMessageConfirmations'
|
import { ConfirmationParam } from '../../hooks/useMessageConfirmations'
|
||||||
|
|
||||||
jest.mock('../validatorConfirmationHelpers')
|
jest.mock('../validatorConfirmationHelpers')
|
||||||
|
|
||||||
@ -18,6 +18,9 @@ const messageData = '0x111111111'
|
|||||||
const web3 = {
|
const web3 = {
|
||||||
utils: {
|
utils: {
|
||||||
soliditySha3Raw: (data: string) => `0xaaaa${data.replace('0x', '')}`
|
soliditySha3Raw: (data: string) => `0xaaaa${data.replace('0x', '')}`
|
||||||
|
},
|
||||||
|
eth: {
|
||||||
|
accounts: new Web3().eth.accounts
|
||||||
}
|
}
|
||||||
} as Web3
|
} as Web3
|
||||||
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
||||||
@ -25,7 +28,7 @@ const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
|
|||||||
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
|
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
|
||||||
const validatorList = [validator1, validator2, validator3]
|
const validatorList = [validator1, validator2, validator3]
|
||||||
const signature =
|
const signature =
|
||||||
'0x519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4'
|
'0x6f5b74905669999f1abdb52e1e215506907e1849aac7b31854da458b33a5954e15b165007c3703cfd16e61ca46a96a56727ed11fa47be359d3834515accd016e1b'
|
||||||
const bridgeContract = {
|
const bridgeContract = {
|
||||||
methods: {
|
methods: {
|
||||||
signature: () => ({
|
signature: () => ({
|
||||||
@ -61,19 +64,19 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
timestamp: 0
|
timestamp: 0
|
||||||
}))
|
}))
|
||||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
timestamp: 0
|
timestamp: 0
|
||||||
}))
|
}))
|
||||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
@ -110,9 +113,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setResult).toBeCalledTimes(2)
|
expect(setResult).toBeCalledTimes(2)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
||||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
|
|
||||||
|
|
||||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||||
@ -135,7 +137,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED, txHash: '', timestamp: 0 }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -144,19 +146,19 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator === validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator === validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
timestamp: 0
|
timestamp: 0
|
||||||
}))
|
}))
|
||||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
timestamp: 0
|
timestamp: 0
|
||||||
}))
|
}))
|
||||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
@ -208,19 +210,19 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: validatorData.validator !== validator3 ? '0x123' : '',
|
txHash: validatorData.validator !== validator3 ? '0x123' : '',
|
||||||
timestamp: validatorData.validator !== validator3 ? 123 : 0
|
timestamp: validatorData.validator !== validator3 ? 123 : 0
|
||||||
}))
|
}))
|
||||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
timestamp: 0
|
timestamp: 0
|
||||||
}))
|
}))
|
||||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
@ -257,9 +259,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setResult).toBeCalledTimes(3)
|
expect(setResult).toBeCalledTimes(3)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
||||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
|
|
||||||
|
|
||||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||||
@ -290,7 +291,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED, txHash: '', timestamp: 0 }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -304,22 +305,22 @@ describe('getConfirmationsForTx', () => {
|
|||||||
? VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
? VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
||||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? '0x123' : '',
|
txHash: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? '0x123' : '',
|
||||||
timestamp: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? 123 : 0
|
timestamp: validatorData.validator !== validator3 && validatorData.validator !== validator4 ? 123 : 0
|
||||||
}))
|
}))
|
||||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status:
|
status:
|
||||||
validatorData.validator === validator3
|
validatorData.validator === validator3
|
||||||
? VALIDATOR_CONFIRMATION_STATUS.FAILED
|
? VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID
|
||||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: validatorData.validator === validator3 ? '0x123' : '',
|
txHash: validatorData.validator === validator3 ? '0x123' : '',
|
||||||
timestamp: validatorData.validator === validator3 ? 123 : 0
|
timestamp: validatorData.validator === validator3 ? 123 : 0
|
||||||
}))
|
}))
|
||||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
@ -356,9 +357,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setResult).toBeCalledTimes(4)
|
expect(setResult).toBeCalledTimes(4)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(2)
|
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
|
||||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
|
|
||||||
|
|
||||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||||
@ -392,7 +392,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
@ -400,8 +400,8 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED, txHash: '', timestamp: 0 }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -414,22 +414,22 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
||||||
timestamp: validatorData.validator === validator1 ? 123 : 0
|
timestamp: validatorData.validator === validator1 ? 123 : 0
|
||||||
}))
|
}))
|
||||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status:
|
status:
|
||||||
validatorData.validator === validator2
|
validatorData.validator === validator2
|
||||||
? VALIDATOR_CONFIRMATION_STATUS.FAILED
|
? VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID
|
||||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: validatorData.validator === validator2 ? '0x123' : '',
|
txHash: validatorData.validator === validator2 ? '0x123' : '',
|
||||||
timestamp: validatorData.validator === validator2 ? 123 : 0
|
timestamp: validatorData.validator === validator2 ? 123 : 0
|
||||||
}))
|
}))
|
||||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status:
|
status:
|
||||||
validatorData.validator === validator3
|
validatorData.validator === validator3
|
||||||
@ -507,7 +507,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(res4).toEqual(
|
expect(res4).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID, txHash: '0x123', timestamp: 123 },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
@ -521,13 +521,13 @@ describe('getConfirmationsForTx', () => {
|
|||||||
validator,
|
validator,
|
||||||
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getSuccessExecutionTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
||||||
timestamp: validatorData.validator === validator1 ? 123 : 0
|
timestamp: validatorData.validator === validator1 ? 123 : 0
|
||||||
}))
|
}))
|
||||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status:
|
status:
|
||||||
validatorData.validator !== validator1
|
validatorData.validator !== validator1
|
||||||
@ -536,7 +536,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
txHash: validatorData.validator !== validator1 ? '0x123' : '',
|
txHash: validatorData.validator !== validator1 ? '0x123' : '',
|
||||||
timestamp: validatorData.validator !== validator1 ? 123 : 0
|
timestamp: validatorData.validator !== validator1 ? 123 : 0
|
||||||
}))
|
}))
|
||||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
@ -632,13 +632,13 @@ describe('getConfirmationsForTx', () => {
|
|||||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||||
}))
|
}))
|
||||||
getSuccessExecutionTransaction
|
getSuccessExecutionTransaction
|
||||||
.mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
|
.mockImplementationOnce(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash: validatorData.validator === validator1 ? '0x100' : '',
|
txHash: validatorData.validator === validator1 ? '0x100' : '',
|
||||||
timestamp: validatorData.validator === validator1 ? 100 : 0
|
timestamp: validatorData.validator === validator1 ? 100 : 0
|
||||||
}))
|
}))
|
||||||
.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
txHash:
|
txHash:
|
||||||
@ -646,7 +646,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
timestamp: validatorData.validator === validator1 ? 100 : validatorData.validator === validator3 ? 300 : ''
|
timestamp: validatorData.validator === validator1 ? 100 : validatorData.validator === validator3 ? 300 : ''
|
||||||
}))
|
}))
|
||||||
getValidatorFailedTransaction
|
getValidatorFailedTransaction
|
||||||
.mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
|
.mockImplementationOnce(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status:
|
status:
|
||||||
validatorData.validator === validator2
|
validatorData.validator === validator2
|
||||||
@ -655,18 +655,20 @@ describe('getConfirmationsForTx', () => {
|
|||||||
txHash: validatorData.validator === validator2 ? '0x200' : '',
|
txHash: validatorData.validator === validator2 ? '0x200' : '',
|
||||||
timestamp: validatorData.validator === validator2 ? 200 : 0
|
timestamp: validatorData.validator === validator2 ? 200 : 0
|
||||||
}))
|
}))
|
||||||
.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
.mockImplementation(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status:
|
status:
|
||||||
validatorData.validator === validator2 || validatorData.validator === validator4
|
validatorData.validator === validator2 || validatorData.validator === validator4
|
||||||
? VALIDATOR_CONFIRMATION_STATUS.FAILED
|
? validatorData.validator === validator2
|
||||||
|
? VALIDATOR_CONFIRMATION_STATUS.FAILED
|
||||||
|
: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID
|
||||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash:
|
txHash:
|
||||||
validatorData.validator === validator2 ? '0x200' : validatorData.validator === validator4 ? '0x400' : '',
|
validatorData.validator === validator2 ? '0x200' : validatorData.validator === validator4 ? '0x400' : '',
|
||||||
timestamp: validatorData.validator === validator2 ? 200 : validatorData.validator === validator4 ? 400 : ''
|
timestamp: validatorData.validator === validator2 ? 200 : validatorData.validator === validator4 ? 400 : ''
|
||||||
}))
|
}))
|
||||||
getValidatorPendingTransaction
|
getValidatorPendingTransaction
|
||||||
.mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
|
.mockImplementationOnce(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status:
|
status:
|
||||||
validatorData.validator === validator3
|
validatorData.validator === validator3
|
||||||
@ -675,7 +677,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
txHash: validatorData.validator === validator3 ? '0x300' : '',
|
txHash: validatorData.validator === validator3 ? '0x300' : '',
|
||||||
timestamp: validatorData.validator === validator3 ? 300 : 0
|
timestamp: validatorData.validator === validator3 ? 300 : 0
|
||||||
}))
|
}))
|
||||||
.mockImplementationOnce(() => async (validatorData: BasicConfirmationParam) => ({
|
.mockImplementationOnce(() => async (validatorData: ConfirmationParam) => ({
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
txHash: '',
|
txHash: '',
|
||||||
@ -716,7 +718,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
|
|
||||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||||
expect(setFailedConfirmations.mock.calls[0][0]).toEqual(false)
|
expect(setFailedConfirmations.mock.calls[0][0]).toEqual(true)
|
||||||
|
|
||||||
expect(getValidatorPendingTransaction).toBeCalledTimes(1)
|
expect(getValidatorPendingTransaction).toBeCalledTimes(1)
|
||||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||||
@ -783,14 +785,13 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect(setResult).toBeCalledTimes(7)
|
expect(setResult).toBeCalledTimes(7)
|
||||||
expect(getValidatorConfirmation).toBeCalledTimes(2)
|
expect(getValidatorConfirmation).toBeCalledTimes(2)
|
||||||
expect(getSuccessExecutionTransaction).toBeCalledTimes(2)
|
expect(getSuccessExecutionTransaction).toBeCalledTimes(2)
|
||||||
expect(setSignatureCollected).toBeCalledTimes(3)
|
expect(setSignatureCollected).toBeCalledTimes(2)
|
||||||
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
|
||||||
expect(setSignatureCollected.mock.calls[1][0]).toEqual(true)
|
expect(setSignatureCollected.mock.calls[1][0]).toEqual(true)
|
||||||
expect(setSignatureCollected.mock.calls[2][0]).toEqual([signature, signature])
|
|
||||||
|
|
||||||
expect(getValidatorFailedTransaction).toBeCalledTimes(2)
|
expect(getValidatorFailedTransaction).toBeCalledTimes(2)
|
||||||
expect(setFailedConfirmations).toBeCalledTimes(2)
|
expect(setFailedConfirmations).toBeCalledTimes(2)
|
||||||
expect(setFailedConfirmations.mock.calls[0][0]).toEqual(false)
|
expect(setFailedConfirmations.mock.calls[0][0]).toEqual(true)
|
||||||
expect(setFailedConfirmations.mock.calls[1][0]).toEqual(false)
|
expect(setFailedConfirmations.mock.calls[1][0]).toEqual(false)
|
||||||
|
|
||||||
expect(getValidatorPendingTransaction).toBeCalledTimes(1)
|
expect(getValidatorPendingTransaction).toBeCalledTimes(1)
|
||||||
@ -805,7 +806,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x200', timestamp: 200 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x200', timestamp: 200 },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x300', timestamp: 300 },
|
||||||
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
@ -822,7 +823,7 @@ describe('getConfirmationsForTx', () => {
|
|||||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 },
|
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x100', timestamp: 100 },
|
||||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x200', timestamp: 200 },
|
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x200', timestamp: 200 },
|
||||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x300', timestamp: 300 },
|
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x300', timestamp: 300 },
|
||||||
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x400', timestamp: 400 }
|
{ validator: validator4, status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID, txHash: '0x400', timestamp: 400 }
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -87,7 +87,8 @@ describe('getFinalizationEvent', () => {
|
|||||||
status: VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS,
|
status: VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS,
|
||||||
txHash,
|
txHash,
|
||||||
timestamp,
|
timestamp,
|
||||||
executionResult: true
|
executionResult: true,
|
||||||
|
blockNumber: 5523145
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(getFailedExecution).toBeCalledTimes(0)
|
expect(getFailedExecution).toBeCalledTimes(0)
|
||||||
@ -237,7 +238,8 @@ describe('getFinalizationEvent', () => {
|
|||||||
status: VALIDATOR_CONFIRMATION_STATUS.PENDING,
|
status: VALIDATOR_CONFIRMATION_STATUS.PENDING,
|
||||||
txHash,
|
txHash,
|
||||||
timestamp: expect.any(Number),
|
timestamp: expect.any(Number),
|
||||||
executionResult: false
|
executionResult: false,
|
||||||
|
blockNumber: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(getFailedExecution).toBeCalledTimes(0)
|
expect(getFailedExecution).toBeCalledTimes(0)
|
||||||
@ -294,7 +296,8 @@ describe('getFinalizationEvent', () => {
|
|||||||
status: VALIDATOR_CONFIRMATION_STATUS.FAILED,
|
status: VALIDATOR_CONFIRMATION_STATUS.FAILED,
|
||||||
txHash,
|
txHash,
|
||||||
timestamp: expect.any(Number),
|
timestamp: expect.any(Number),
|
||||||
executionResult: false
|
executionResult: false,
|
||||||
|
blockNumber: expect.any(Number)
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(getFailedExecution).toBeCalledTimes(1)
|
expect(getFailedExecution).toBeCalledTimes(1)
|
||||||
|
@ -12,6 +12,7 @@ import Web3 from 'web3'
|
|||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
|
|
||||||
export interface APITransaction {
|
export interface APITransaction {
|
||||||
|
from: string
|
||||||
timeStamp: string
|
timeStamp: string
|
||||||
isError: string
|
isError: string
|
||||||
input: string
|
input: string
|
||||||
@ -54,7 +55,7 @@ export const fetchAccountTransactions = async ({ account, startBlock, endBlock,
|
|||||||
url.searchParams.append('module', 'account')
|
url.searchParams.append('module', 'account')
|
||||||
url.searchParams.append('action', 'txlist')
|
url.searchParams.append('action', 'txlist')
|
||||||
url.searchParams.append('address', account)
|
url.searchParams.append('address', account)
|
||||||
url.searchParams.append('filterby', 'from')
|
url.searchParams.append('filterby', 'to')
|
||||||
url.searchParams.append('startblock', startBlock.toString())
|
url.searchParams.append('startblock', startBlock.toString())
|
||||||
url.searchParams.append('endblock', endBlock.toString())
|
url.searchParams.append('endblock', endBlock.toString())
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ export const fetchAccountTransactions = async ({ account, startBlock, endBlock,
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.result
|
return result.result || []
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchPendingTransactions = async ({
|
export const fetchPendingTransactions = async ({
|
||||||
@ -180,7 +181,9 @@ export const getLogs = async (
|
|||||||
if (topics[i] !== null) {
|
if (topics[i] !== null) {
|
||||||
url.searchParams.append(`topic${i}`, topics[i] as string)
|
url.searchParams.append(`topic${i}`, topics[i] as string)
|
||||||
for (let j = 0; j < i; j++) {
|
for (let j = 0; j < i; j++) {
|
||||||
url.searchParams.append(`topic${j}_${i}_opr`, 'and')
|
if (topics[j] !== null) {
|
||||||
|
url.searchParams.append(`topic${j}_${i}_opr`, 'and')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,7 +197,7 @@ export const getLogs = async (
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterReceiver = (to: string) => (tx: APITransaction) => tx.to.toLowerCase() === to.toLowerCase()
|
const filterSender = (from: string) => (tx: APITransaction) => tx.from.toLowerCase() === from.toLowerCase()
|
||||||
|
|
||||||
export const getFailedTransactions = async (
|
export const getFailedTransactions = async (
|
||||||
account: string,
|
account: string,
|
||||||
@ -204,9 +207,9 @@ export const getFailedTransactions = async (
|
|||||||
api: string,
|
api: string,
|
||||||
getAccountTransactionsMethod = getAccountTransactions
|
getAccountTransactionsMethod = getAccountTransactions
|
||||||
): Promise<APITransaction[]> => {
|
): Promise<APITransaction[]> => {
|
||||||
const transactions = await getAccountTransactionsMethod({ account, startBlock, endBlock, api })
|
const transactions = await getAccountTransactionsMethod({ account: to, startBlock, endBlock, api })
|
||||||
|
|
||||||
return transactions.filter(t => t.isError !== '0').filter(filterReceiver(to))
|
return transactions.filter(t => t.isError !== '0').filter(filterSender(account))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSuccessTransactions = async (
|
export const getSuccessTransactions = async (
|
||||||
@ -217,9 +220,9 @@ export const getSuccessTransactions = async (
|
|||||||
api: string,
|
api: string,
|
||||||
getAccountTransactionsMethod = getAccountTransactions
|
getAccountTransactionsMethod = getAccountTransactions
|
||||||
): Promise<APITransaction[]> => {
|
): Promise<APITransaction[]> => {
|
||||||
const transactions = await getAccountTransactionsMethod({ account, startBlock, endBlock, api })
|
const transactions = await getAccountTransactionsMethod({ account: to, startBlock, endBlock, api })
|
||||||
|
|
||||||
return transactions.filter(t => t.isError === '0').filter(filterReceiver(to))
|
return transactions.filter(t => t.isError === '0').filter(filterSender(account))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const filterValidatorSignatureTransaction = (
|
export const filterValidatorSignatureTransaction = (
|
||||||
|
@ -2,26 +2,37 @@ import Web3 from 'web3'
|
|||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { HOME_RPC_POLLING_INTERVAL, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
import { HOME_RPC_POLLING_INTERVAL, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||||
import { GetTransactionParams, APITransaction, APIPendingTransaction, GetPendingTransactionParams } from './explorer'
|
import { GetTransactionParams, APITransaction, APIPendingTransaction, GetPendingTransactionParams } from './explorer'
|
||||||
import { getAffirmationsSigned, getMessagesSigned } from './contract'
|
|
||||||
import {
|
import {
|
||||||
getValidatorConfirmation,
|
getValidatorConfirmation,
|
||||||
getValidatorFailedTransaction,
|
getValidatorFailedTransaction,
|
||||||
getValidatorPendingTransaction,
|
getValidatorPendingTransaction,
|
||||||
getSuccessExecutionTransaction
|
getSuccessExecutionTransaction
|
||||||
} from './validatorConfirmationHelpers'
|
} from './validatorConfirmationHelpers'
|
||||||
import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
|
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||||
|
import { signatureToVRS } from './signatures'
|
||||||
|
|
||||||
const mergeConfirmations = (oldConfirmations: BasicConfirmationParam[], newConfirmations: BasicConfirmationParam[]) => {
|
const mergeConfirmations = (oldConfirmations: ConfirmationParam[], newConfirmations: ConfirmationParam[]) => {
|
||||||
const confirmations = [...oldConfirmations]
|
const confirmations = [...oldConfirmations]
|
||||||
newConfirmations.forEach(validatorData => {
|
newConfirmations.forEach(validatorData => {
|
||||||
const index = confirmations.findIndex(e => e.validator === validatorData.validator)
|
const index = confirmations.findIndex(e => e.validator === validatorData.validator)
|
||||||
|
if (index === -1) {
|
||||||
|
confirmations.push(validatorData)
|
||||||
|
return
|
||||||
|
}
|
||||||
const currentStatus = confirmations[index].status
|
const currentStatus = confirmations[index].status
|
||||||
const newStatus = validatorData.status
|
const newStatus = validatorData.status
|
||||||
if (
|
if (
|
||||||
(validatorData as ConfirmationParam).txHash ||
|
validatorData.txHash ||
|
||||||
|
!!validatorData.signature ||
|
||||||
(newStatus !== currentStatus && newStatus !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED)
|
(newStatus !== currentStatus && newStatus !== VALIDATOR_CONFIRMATION_STATUS.UNDEFINED)
|
||||||
) {
|
) {
|
||||||
confirmations[index] = validatorData
|
confirmations[index] = {
|
||||||
|
status: validatorData.status,
|
||||||
|
validator: validatorData.validator,
|
||||||
|
timestamp: confirmations[index].timestamp || validatorData.timestamp,
|
||||||
|
txHash: confirmations[index].txHash || validatorData.txHash,
|
||||||
|
signature: confirmations[index].signature || validatorData.signature
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return confirmations
|
return confirmations
|
||||||
@ -45,19 +56,17 @@ export const getConfirmationsForTx = async (
|
|||||||
setPendingConfirmations: Function,
|
setPendingConfirmations: Function,
|
||||||
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
||||||
) => {
|
) => {
|
||||||
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
|
|
||||||
|
|
||||||
const hashMsg = web3.utils.soliditySha3Raw(messageData)
|
const hashMsg = web3.utils.soliditySha3Raw(messageData)
|
||||||
let validatorConfirmations = await Promise.all(
|
let validatorConfirmations = await Promise.all(
|
||||||
validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, confirmationContractMethod))
|
validatorList.map(getValidatorConfirmation(web3, hashMsg, bridgeContract, fromHome))
|
||||||
)
|
)
|
||||||
|
|
||||||
const updateConfirmations = (confirmations: BasicConfirmationParam[]) => {
|
const updateConfirmations = (confirmations: ConfirmationParam[]) => {
|
||||||
if (confirmations.length === 0) {
|
if (confirmations.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
validatorConfirmations = mergeConfirmations(validatorConfirmations, confirmations)
|
validatorConfirmations = mergeConfirmations(validatorConfirmations, confirmations)
|
||||||
setResult((currentConfirmations: BasicConfirmationParam[]) => {
|
setResult((currentConfirmations: ConfirmationParam[]) => {
|
||||||
if (currentConfirmations && currentConfirmations.length) {
|
if (currentConfirmations && currentConfirmations.length) {
|
||||||
return mergeConfirmations(currentConfirmations, confirmations)
|
return mergeConfirmations(currentConfirmations, confirmations)
|
||||||
}
|
}
|
||||||
@ -67,7 +76,7 @@ export const getConfirmationsForTx = async (
|
|||||||
|
|
||||||
const successConfirmations = validatorConfirmations.filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
|
const successConfirmations = validatorConfirmations.filter(c => c.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
|
||||||
const notSuccessConfirmations = validatorConfirmations.filter(c => c.status !== VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
|
const notSuccessConfirmations = validatorConfirmations.filter(c => c.status !== VALIDATOR_CONFIRMATION_STATUS.SUCCESS)
|
||||||
const hasEnoughSignatures = successConfirmations.length === requiredSignatures
|
const hasEnoughSignatures = successConfirmations.length >= requiredSignatures
|
||||||
|
|
||||||
updateConfirmations(validatorConfirmations)
|
updateConfirmations(validatorConfirmations)
|
||||||
setSignatureCollected(hasEnoughSignatures)
|
setSignatureCollected(hasEnoughSignatures)
|
||||||
@ -76,11 +85,15 @@ export const getConfirmationsForTx = async (
|
|||||||
setPendingConfirmations(false)
|
setPendingConfirmations(false)
|
||||||
if (fromHome) {
|
if (fromHome) {
|
||||||
// fetch collected signatures for possible manual processing
|
// fetch collected signatures for possible manual processing
|
||||||
setSignatureCollected(
|
const signatures = await Promise.all(
|
||||||
await Promise.all(
|
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
|
||||||
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
const confirmations = signatures.flatMap(sig => {
|
||||||
|
const { v, r, s } = signatureToVRS(sig)
|
||||||
|
const address = web3.eth.accounts.recover(messageData, `0x${v}`, `0x${r}`, `0x${s}`)
|
||||||
|
return successConfirmations.filter(c => c.validator === address).map(c => ({ ...c, signature: sig }))
|
||||||
|
})
|
||||||
|
updateConfirmations(confirmations)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,13 +128,13 @@ export const getConfirmationsForTx = async (
|
|||||||
// Check if confirmation failed
|
// Check if confirmation failed
|
||||||
const validatorFailedConfirmationsChecks = await Promise.all(
|
const validatorFailedConfirmationsChecks = await Promise.all(
|
||||||
undefinedConfirmations.map(
|
undefinedConfirmations.map(
|
||||||
getValidatorFailedTransaction(bridgeContract, messageData, startBlock, getFailedTransactions)
|
getValidatorFailedTransaction(web3, bridgeContract, messageData, startBlock, getFailedTransactions)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
let validatorFailedConfirmations = validatorFailedConfirmationsChecks.filter(
|
let validatorFailedConfirmations = validatorFailedConfirmationsChecks.filter(
|
||||||
c => c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED
|
c => c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED || c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID
|
||||||
)
|
)
|
||||||
if (hasEnoughSignatures) {
|
if (hasEnoughSignatures && !fromHome) {
|
||||||
const lastTS = Math.max(...successConfirmationWithTxFound.map(c => c.timestamp || 0))
|
const lastTS = Math.max(...successConfirmationWithTxFound.map(c => c.timestamp || 0))
|
||||||
validatorFailedConfirmations = validatorFailedConfirmations.map(
|
validatorFailedConfirmations = validatorFailedConfirmations.map(
|
||||||
c =>
|
c =>
|
||||||
@ -129,11 +142,13 @@ export const getConfirmationsForTx = async (
|
|||||||
? c
|
? c
|
||||||
: {
|
: {
|
||||||
...c,
|
...c,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
status: VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
setFailedConfirmations(validatorFailedConfirmations.length > validatorList.length - requiredSignatures)
|
setFailedConfirmations(
|
||||||
|
!hasEnoughSignatures && validatorFailedConfirmations.some(c => c.status === VALIDATOR_CONFIRMATION_STATUS.FAILED)
|
||||||
|
)
|
||||||
updateConfirmations(validatorFailedConfirmations)
|
updateConfirmations(validatorFailedConfirmations)
|
||||||
|
|
||||||
const missingConfirmations = validatorConfirmations.filter(
|
const missingConfirmations = validatorConfirmations.filter(
|
||||||
@ -144,7 +159,9 @@ export const getConfirmationsForTx = async (
|
|||||||
// If signatures collected, it should set other signatures not found as not required
|
// If signatures collected, it should set other signatures not found as not required
|
||||||
const notRequiredConfirmations = missingConfirmations.map(c => ({
|
const notRequiredConfirmations = missingConfirmations.map(c => ({
|
||||||
validator: c.validator,
|
validator: c.validator,
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED
|
status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED,
|
||||||
|
timestamp: 0,
|
||||||
|
txHash: ''
|
||||||
}))
|
}))
|
||||||
updateConfirmations(notRequiredConfirmations)
|
updateConfirmations(notRequiredConfirmations)
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,8 @@ export const getSuccessExecutionData = async (
|
|||||||
validator: validatorAddress,
|
validator: validatorAddress,
|
||||||
txHash: event.transactionHash,
|
txHash: event.transactionHash,
|
||||||
timestamp: blockTimestamp,
|
timestamp: blockTimestamp,
|
||||||
executionResult: event.returnValues.status
|
executionResult: event.returnValues.status,
|
||||||
|
blockNumber: event.blockNumber
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
@ -115,7 +116,8 @@ export const getFinalizationEvent = async (
|
|||||||
validator: validator,
|
validator: validator,
|
||||||
txHash: pendingTx.hash,
|
txHash: pendingTx.hash,
|
||||||
timestamp: nowTimestamp,
|
timestamp: nowTimestamp,
|
||||||
executionResult: false
|
executionResult: false,
|
||||||
|
blockNumber: 0
|
||||||
})
|
})
|
||||||
setPendingExecution(true)
|
setPendingExecution(true)
|
||||||
} else {
|
} else {
|
||||||
@ -144,7 +146,8 @@ export const getFinalizationEvent = async (
|
|||||||
validator: validator,
|
validator: validator,
|
||||||
txHash: failedTx.hash,
|
txHash: failedTx.hash,
|
||||||
timestamp,
|
timestamp,
|
||||||
executionResult: false
|
executionResult: false,
|
||||||
|
blockNumber: parseInt(failedTx.blockNumber)
|
||||||
})
|
})
|
||||||
setFailedExecution(true)
|
setFailedExecution(true)
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,45 @@
|
|||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
|
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||||
import validatorsCache from '../services/ValidatorsCache'
|
import validatorsCache from '../services/ValidatorsCache'
|
||||||
import { CACHE_KEY_FAILED, CACHE_KEY_SUCCESS, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
import { CACHE_KEY_FAILED, CACHE_KEY_SUCCESS, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||||
import { APIPendingTransaction, APITransaction, GetTransactionParams, GetPendingTransactionParams } from './explorer'
|
import { APIPendingTransaction, APITransaction, GetTransactionParams, GetPendingTransactionParams } from './explorer'
|
||||||
import { homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
import { homeBlockNumberProvider } from '../services/BlockNumberProvider'
|
||||||
|
import { getAffirmationsSigned, getMessagesSigned } from './contract'
|
||||||
|
|
||||||
export const getValidatorConfirmation = (
|
export const getValidatorConfirmation = (
|
||||||
web3: Web3,
|
web3: Web3,
|
||||||
hashMsg: string,
|
hashMsg: string,
|
||||||
bridgeContract: Contract,
|
bridgeContract: Contract,
|
||||||
confirmationContractMethod: Function
|
fromHome: boolean
|
||||||
) => async (validator: string): Promise<BasicConfirmationParam> => {
|
) => async (validator: string): Promise<ConfirmationParam> => {
|
||||||
const hashSenderMsg = web3.utils.soliditySha3Raw(validator, hashMsg)
|
const hashSenderMsg = web3.utils.soliditySha3Raw(validator, hashMsg)
|
||||||
|
|
||||||
const signatureFromCache = validatorsCache.get(hashSenderMsg)
|
const fromCache = validatorsCache.getData(hashSenderMsg)
|
||||||
if (signatureFromCache) {
|
if (fromCache) {
|
||||||
return {
|
return fromCache
|
||||||
validator,
|
|
||||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const confirmationContractMethod = fromHome ? getMessagesSigned : getAffirmationsSigned
|
||||||
const confirmed = await confirmationContractMethod(bridgeContract, hashSenderMsg)
|
const confirmed = await confirmationContractMethod(bridgeContract, hashSenderMsg)
|
||||||
const status = confirmed ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
|
||||||
|
|
||||||
// If validator confirmed signature, we cache the result to avoid doing future requests for a result that won't change
|
// If validator confirmed signature, we cache the result to avoid doing future requests for a result that won't change
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
validatorsCache.set(hashSenderMsg, confirmed)
|
const confirmation: ConfirmationParam = {
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||||
|
validator,
|
||||||
|
timestamp: 0,
|
||||||
|
txHash: ''
|
||||||
|
}
|
||||||
|
validatorsCache.setData(hashSenderMsg, confirmation)
|
||||||
|
return confirmation
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
validator,
|
validator,
|
||||||
status
|
timestamp: 0,
|
||||||
|
txHash: ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +50,7 @@ export const getSuccessExecutionTransaction = (
|
|||||||
messageData: string,
|
messageData: string,
|
||||||
startBlock: number,
|
startBlock: number,
|
||||||
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
getSuccessTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
||||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
) => async (validatorData: ConfirmationParam): Promise<ConfirmationParam> => {
|
||||||
const { validator } = validatorData
|
const { validator } = validatorData
|
||||||
const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}-${messageData}`
|
const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}-${messageData}`
|
||||||
const fromCache = validatorsCache.getData(validatorCacheKey)
|
const fromCache = validatorsCache.getData(validatorCacheKey)
|
||||||
@ -87,11 +94,12 @@ export const getSuccessExecutionTransaction = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getValidatorFailedTransaction = (
|
export const getValidatorFailedTransaction = (
|
||||||
|
web3: Web3,
|
||||||
bridgeContract: Contract,
|
bridgeContract: Contract,
|
||||||
messageData: string,
|
messageData: string,
|
||||||
startBlock: number,
|
startBlock: number,
|
||||||
getFailedTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
getFailedTransactions: (args: GetTransactionParams) => Promise<APITransaction[]>
|
||||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
) => async (validatorData: ConfirmationParam): Promise<ConfirmationParam> => {
|
||||||
const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}-${messageData}`
|
const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}-${messageData}`
|
||||||
const failedFromCache = validatorsCache.getData(validatorCacheKey)
|
const failedFromCache = validatorsCache.getData(validatorCacheKey)
|
||||||
|
|
||||||
@ -106,30 +114,33 @@ export const getValidatorFailedTransaction = (
|
|||||||
startBlock,
|
startBlock,
|
||||||
endBlock: homeBlockNumberProvider.get() || 0
|
endBlock: homeBlockNumberProvider.get() || 0
|
||||||
})
|
})
|
||||||
const newStatus =
|
|
||||||
failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.FAILED : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
|
||||||
|
|
||||||
let txHashTimestamp = 0
|
|
||||||
let txHash = ''
|
|
||||||
// If validator signature failed, we cache the result to avoid doing future requests for a result that won't change
|
// If validator signature failed, we cache the result to avoid doing future requests for a result that won't change
|
||||||
if (failedTransactions.length > 0) {
|
if (failedTransactions.length > 0) {
|
||||||
const failedTx = failedTransactions[0]
|
const failedTx = failedTransactions[0]
|
||||||
txHashTimestamp = parseInt(failedTx.timeStamp)
|
const confirmation: ConfirmationParam = {
|
||||||
txHash = failedTx.hash
|
status: VALIDATOR_CONFIRMATION_STATUS.FAILED,
|
||||||
|
|
||||||
validatorsCache.setData(validatorCacheKey, {
|
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: newStatus,
|
txHash: failedTx.hash,
|
||||||
txHash,
|
timestamp: parseInt(failedTx.timeStamp)
|
||||||
timestamp: txHashTimestamp
|
}
|
||||||
})
|
|
||||||
|
if (failedTx.input && failedTx.input.length > 10) {
|
||||||
|
try {
|
||||||
|
const res = web3.eth.abi.decodeParameters(['bytes', 'bytes'], `0x${failedTx.input.slice(10)}`)
|
||||||
|
confirmation.signature = res[0]
|
||||||
|
confirmation.status = VALIDATOR_CONFIRMATION_STATUS.FAILED_VALID
|
||||||
|
console.log(`Adding manual signature from failed message from ${validatorData.validator}`)
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
validatorsCache.setData(validatorCacheKey, confirmation)
|
||||||
|
return confirmation
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||||
validator: validatorData.validator,
|
validator: validatorData.validator,
|
||||||
status: newStatus,
|
txHash: '',
|
||||||
txHash,
|
timestamp: 0
|
||||||
timestamp: txHashTimestamp
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +148,7 @@ export const getValidatorPendingTransaction = (
|
|||||||
bridgeContract: Contract,
|
bridgeContract: Contract,
|
||||||
messageData: string,
|
messageData: string,
|
||||||
getPendingTransactions: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>
|
getPendingTransactions: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>
|
||||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
) => async (validatorData: ConfirmationParam): Promise<ConfirmationParam> => {
|
||||||
const failedTransactions = await getPendingTransactions({
|
const failedTransactions = await getPendingTransactions({
|
||||||
account: validatorData.validator,
|
account: validatorData.validator,
|
||||||
to: bridgeContract.options.address,
|
to: bridgeContract.options.address,
|
||||||
|
@ -169,7 +169,8 @@ function isNonceError(e) {
|
|||||||
message.includes('transaction nonce is too low') ||
|
message.includes('transaction nonce is too low') ||
|
||||||
message.includes('nonce too low') ||
|
message.includes('nonce too low') ||
|
||||||
message.includes('transaction with same nonce in the queue') ||
|
message.includes('transaction with same nonce in the queue') ||
|
||||||
message.includes('oldnonce')
|
message.includes('oldnonce') ||
|
||||||
|
message.includes(`the tx doesn't have the correct nonce`)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user