Add Alm unit tests (#388)
This commit is contained in:
parent
2edd8f2783
commit
4c44aa5fcd
@ -1,5 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
test('renders learn react link', () => {
|
||||
// Removed basic test from setup. Keeping this so CI passes until we add unit tests.
|
||||
})
|
469
alm/src/utils/__tests__/contracts.test.ts
Normal file
469
alm/src/utils/__tests__/contracts.test.ts
Normal file
@ -0,0 +1,469 @@
|
||||
import 'jest'
|
||||
import { getRequiredBlockConfirmations, getRequiredSignatures, getValidatorList } from '../contract'
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
import { SnapshotProvider } from '../../services/SnapshotProvider'
|
||||
|
||||
describe('getRequiredBlockConfirmations', () => {
|
||||
const methodsBuilder = (value: string) => ({
|
||||
requiredBlockConfirmations: () => {
|
||||
return {
|
||||
call: () => {
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('Should call requiredBlockConfirmations method if no events present', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
return []
|
||||
},
|
||||
methods: methodsBuilder('1')
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
requiredBlockConfirmationEvents: () => {
|
||||
return []
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 10
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const result = await getRequiredBlockConfirmations(contract, 10, snapshotProvider)
|
||||
|
||||
expect(result).toEqual(1)
|
||||
})
|
||||
test('Should not call to get events if block number was included in the snapshot', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||
methods: methodsBuilder('3')
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
requiredBlockConfirmationEvents: () => {
|
||||
return [
|
||||
{
|
||||
blockNumber: 8,
|
||||
returnValues: {
|
||||
requiredBlockConfirmations: '1'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 15
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const result = await getRequiredBlockConfirmations(contract, 10, snapshotProvider)
|
||||
|
||||
expect(result).toEqual(1)
|
||||
expect(contract.getPastEvents).toBeCalledTimes(0)
|
||||
})
|
||||
test('Should call to get events if block number was not included in the snapshot', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [
|
||||
{
|
||||
blockNumber: 9,
|
||||
returnValues: {
|
||||
requiredBlockConfirmations: '2'
|
||||
}
|
||||
}
|
||||
]),
|
||||
methods: methodsBuilder('3')
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
requiredBlockConfirmationEvents: () => {
|
||||
return [
|
||||
{
|
||||
blockNumber: 8,
|
||||
returnValues: {
|
||||
requiredBlockConfirmations: '1'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 8
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const result = await getRequiredBlockConfirmations(contract, 10, snapshotProvider)
|
||||
|
||||
expect(result).toEqual(2)
|
||||
expect(contract.getPastEvents).toBeCalledTimes(1)
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('RequiredBlockConfirmationChanged', {
|
||||
fromBlock: 9,
|
||||
toBlock: 10
|
||||
})
|
||||
})
|
||||
test('Should use the most updated event', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [
|
||||
{
|
||||
blockNumber: 9,
|
||||
returnValues: {
|
||||
requiredBlockConfirmations: '2'
|
||||
}
|
||||
},
|
||||
{
|
||||
blockNumber: 11,
|
||||
returnValues: {
|
||||
requiredBlockConfirmations: '3'
|
||||
}
|
||||
}
|
||||
]),
|
||||
methods: methodsBuilder('3')
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
requiredBlockConfirmationEvents: () => {
|
||||
return []
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 11
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const result = await getRequiredBlockConfirmations(contract, 15, snapshotProvider)
|
||||
|
||||
expect(result).toEqual(3)
|
||||
expect(contract.getPastEvents).toBeCalledTimes(1)
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('RequiredBlockConfirmationChanged', {
|
||||
fromBlock: 12,
|
||||
toBlock: 15
|
||||
})
|
||||
})
|
||||
})
|
||||
describe('getRequiredSignatures', () => {
|
||||
test('Should not call to get events if block number was included in the snapshot', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [])
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
requiredSignaturesEvents: () => {
|
||||
return [
|
||||
{
|
||||
blockNumber: 7,
|
||||
returnValues: {
|
||||
requiredSignatures: '1'
|
||||
}
|
||||
},
|
||||
{
|
||||
blockNumber: 8,
|
||||
returnValues: {
|
||||
requiredSignatures: '2'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 10
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const result = await getRequiredSignatures(contract, 10, snapshotProvider)
|
||||
|
||||
expect(result).toEqual(2)
|
||||
expect(contract.getPastEvents).toBeCalledTimes(0)
|
||||
})
|
||||
test('Should call to get events if block number is higher than the snapshot block number', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [
|
||||
{
|
||||
blockNumber: 15,
|
||||
returnValues: {
|
||||
requiredSignatures: '3'
|
||||
}
|
||||
}
|
||||
])
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
requiredSignaturesEvents: () => {
|
||||
return [
|
||||
{
|
||||
blockNumber: 7,
|
||||
returnValues: {
|
||||
requiredSignatures: '1'
|
||||
}
|
||||
},
|
||||
{
|
||||
blockNumber: 8,
|
||||
returnValues: {
|
||||
requiredSignatures: '2'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 10
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const result = await getRequiredSignatures(contract, 20, snapshotProvider)
|
||||
|
||||
expect(result).toEqual(3)
|
||||
expect(contract.getPastEvents).toBeCalledTimes(1)
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('RequiredSignaturesChanged', {
|
||||
fromBlock: 11,
|
||||
toBlock: 20
|
||||
})
|
||||
})
|
||||
test('Should use the most updated event before the block number', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => [
|
||||
{
|
||||
blockNumber: 15,
|
||||
returnValues: {
|
||||
requiredSignatures: '4'
|
||||
}
|
||||
}
|
||||
])
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
requiredSignaturesEvents: () => {
|
||||
return [
|
||||
{
|
||||
blockNumber: 5,
|
||||
returnValues: {
|
||||
requiredSignatures: '1'
|
||||
}
|
||||
},
|
||||
{
|
||||
blockNumber: 6,
|
||||
returnValues: {
|
||||
requiredSignatures: '2'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 10
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const result = await getRequiredSignatures(contract, 7, snapshotProvider)
|
||||
|
||||
expect(result).toEqual(2)
|
||||
expect(contract.getPastEvents).toBeCalledTimes(0)
|
||||
})
|
||||
})
|
||||
describe('getValidatorList', () => {
|
||||
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
||||
const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
|
||||
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
|
||||
const methodsBuilder = (value: string[]) => ({
|
||||
validatorList: () => {
|
||||
return {
|
||||
call: () => {
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
test('Should return the current validator list if no events found', async () => {
|
||||
const currentValidators = [validator1, validator2, validator3]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||
methods: methodsBuilder(currentValidators)
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
validatorAddedEvents: () => {
|
||||
return []
|
||||
},
|
||||
validatorRemovedEvents: () => {
|
||||
return []
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 10
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const list = await getValidatorList(contract, 20, snapshotProvider)
|
||||
|
||||
expect(list.length).toEqual(3)
|
||||
expect(list).toEqual(expect.arrayContaining(currentValidators))
|
||||
expect(contract.getPastEvents).toBeCalledTimes(2)
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorAdded', {
|
||||
fromBlock: 20
|
||||
})
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorRemoved', {
|
||||
fromBlock: 20
|
||||
})
|
||||
})
|
||||
test('If validator was added later from snapshot it should not include it', async () => {
|
||||
const currentValidators = [validator1, validator2, validator3]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||
methods: methodsBuilder(currentValidators)
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
validatorAddedEvents: () => {
|
||||
return [
|
||||
{
|
||||
blockNumber: 9,
|
||||
returnValues: {
|
||||
validator: validator3
|
||||
},
|
||||
event: 'ValidatorAdded'
|
||||
}
|
||||
]
|
||||
},
|
||||
validatorRemovedEvents: () => {
|
||||
return []
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 10
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const list = await getValidatorList(contract, 5, snapshotProvider)
|
||||
|
||||
expect(list.length).toEqual(2)
|
||||
expect(list).toEqual(expect.arrayContaining([validator1, validator2]))
|
||||
expect(contract.getPastEvents).toBeCalledTimes(2)
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorAdded', {
|
||||
fromBlock: 11
|
||||
})
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorRemoved', {
|
||||
fromBlock: 11
|
||||
})
|
||||
})
|
||||
test('If validator was added later from chain it should not include it', async () => {
|
||||
const currentValidators = [validator1, validator2, validator3]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(event => {
|
||||
if (event === 'ValidatorAdded') {
|
||||
return [
|
||||
{
|
||||
blockNumber: 9,
|
||||
returnValues: {
|
||||
validator: validator3
|
||||
},
|
||||
event: 'ValidatorAdded'
|
||||
}
|
||||
]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}),
|
||||
methods: methodsBuilder(currentValidators)
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
validatorAddedEvents: () => {
|
||||
return []
|
||||
},
|
||||
validatorRemovedEvents: () => {
|
||||
return []
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 10
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const list = await getValidatorList(contract, 15, snapshotProvider)
|
||||
|
||||
expect(list.length).toEqual(2)
|
||||
expect(list).toEqual(expect.arrayContaining([validator1, validator2]))
|
||||
expect(contract.getPastEvents).toBeCalledTimes(2)
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorAdded', {
|
||||
fromBlock: 15
|
||||
})
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorRemoved', {
|
||||
fromBlock: 15
|
||||
})
|
||||
})
|
||||
test('If validator was removed later from snapshot it should include it', async () => {
|
||||
const currentValidators = [validator1, validator2]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(() => []),
|
||||
methods: methodsBuilder(currentValidators)
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
validatorAddedEvents: () => {
|
||||
return []
|
||||
},
|
||||
validatorRemovedEvents: () => {
|
||||
return [
|
||||
{
|
||||
blockNumber: 9,
|
||||
returnValues: {
|
||||
validator: validator3
|
||||
},
|
||||
event: 'ValidatorRemoved'
|
||||
}
|
||||
]
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 10
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const list = await getValidatorList(contract, 5, snapshotProvider)
|
||||
|
||||
expect(list.length).toEqual(3)
|
||||
expect(list).toEqual(expect.arrayContaining([validator1, validator2, validator3]))
|
||||
expect(contract.getPastEvents).toBeCalledTimes(2)
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorAdded', {
|
||||
fromBlock: 11
|
||||
})
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorRemoved', {
|
||||
fromBlock: 11
|
||||
})
|
||||
})
|
||||
test('If validator was removed later from chain it should include it', async () => {
|
||||
const currentValidators = [validator1, validator2]
|
||||
const contract = ({
|
||||
getPastEvents: jest.fn().mockImplementation(event => {
|
||||
if (event === 'ValidatorRemoved') {
|
||||
return [
|
||||
{
|
||||
blockNumber: 9,
|
||||
returnValues: {
|
||||
validator: validator3
|
||||
},
|
||||
event: 'ValidatorRemoved'
|
||||
}
|
||||
]
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}),
|
||||
methods: methodsBuilder(currentValidators)
|
||||
} as unknown) as Contract
|
||||
|
||||
const snapshotProvider = ({
|
||||
validatorAddedEvents: () => {
|
||||
return []
|
||||
},
|
||||
validatorRemovedEvents: () => {
|
||||
return []
|
||||
},
|
||||
snapshotBlockNumber: () => {
|
||||
return 10
|
||||
}
|
||||
} as unknown) as SnapshotProvider
|
||||
|
||||
const list = await getValidatorList(contract, 15, snapshotProvider)
|
||||
|
||||
expect(list.length).toEqual(3)
|
||||
expect(list).toEqual(expect.arrayContaining([validator1, validator2, validator3]))
|
||||
expect(contract.getPastEvents).toBeCalledTimes(2)
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorAdded', {
|
||||
fromBlock: 15
|
||||
})
|
||||
expect(contract.getPastEvents).toHaveBeenCalledWith('ValidatorRemoved', {
|
||||
fromBlock: 15
|
||||
})
|
||||
})
|
||||
})
|
155
alm/src/utils/__tests__/explorer.test.ts
Normal file
155
alm/src/utils/__tests__/explorer.test.ts
Normal file
@ -0,0 +1,155 @@
|
||||
import 'jest'
|
||||
import {
|
||||
getFailedTransactions,
|
||||
getSuccessTransactions,
|
||||
filterValidatorSignatureTransaction,
|
||||
getExecutionFailedTransactionForMessage,
|
||||
APITransaction,
|
||||
getValidatorPendingTransactionsForMessage,
|
||||
getExecutionPendingTransactionsForMessage
|
||||
} from '../explorer'
|
||||
import { EXECUTE_AFFIRMATION_HASH, EXECUTE_SIGNATURES_HASH, SUBMIT_SIGNATURE_HASH } from '../../config/constants'
|
||||
|
||||
const messageData = '0x123456'
|
||||
const OTHER_HASH = 'aabbccdd'
|
||||
const bridgeAddress = '0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560'
|
||||
const otherAddress = '0xD4075FB57fCf038bFc702c915Ef9592534bED5c1'
|
||||
|
||||
describe('getFailedTransactions', () => {
|
||||
test('should only return failed transactions', async () => {
|
||||
const transactions = [{ isError: '0' }, { isError: '1' }, { isError: '0' }, { isError: '1' }, { isError: '1' }]
|
||||
|
||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||
const result = await getFailedTransactions('', '', 0, 1, '', fetchAccountTransactions)
|
||||
expect(result.length).toEqual(3)
|
||||
})
|
||||
})
|
||||
describe('getSuccessTransactions', () => {
|
||||
test('should only return success transactions', async () => {
|
||||
const transactions = [{ isError: '0' }, { isError: '1' }, { isError: '0' }, { isError: '1' }, { isError: '1' }]
|
||||
|
||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||
const result = await getSuccessTransactions('', '', 0, 1, '', fetchAccountTransactions)
|
||||
expect(result.length).toEqual(2)
|
||||
})
|
||||
})
|
||||
describe('filterValidatorSignatureTransaction', () => {
|
||||
test('should return submit signatures related transaction', () => {
|
||||
const transactions = [
|
||||
{ input: `0x${SUBMIT_SIGNATURE_HASH}112233` },
|
||||
{ input: `0x${SUBMIT_SIGNATURE_HASH}123456` },
|
||||
{ input: `0x${OTHER_HASH}123456` },
|
||||
{ input: `0x${OTHER_HASH}112233` }
|
||||
] as APITransaction[]
|
||||
|
||||
const result = filterValidatorSignatureTransaction(transactions, messageData)
|
||||
expect(result.length).toEqual(1)
|
||||
expect(result[0]).toEqual({ input: `0x${SUBMIT_SIGNATURE_HASH}123456` })
|
||||
})
|
||||
test('should return execute affirmation related transaction', () => {
|
||||
const transactions = [
|
||||
{ input: `0x${EXECUTE_AFFIRMATION_HASH}112233` },
|
||||
{ input: `0x${EXECUTE_AFFIRMATION_HASH}123456` },
|
||||
{ input: `0x${OTHER_HASH}123456` },
|
||||
{ input: `0x${OTHER_HASH}112233` }
|
||||
] as APITransaction[]
|
||||
|
||||
const result = filterValidatorSignatureTransaction(transactions, messageData)
|
||||
expect(result.length).toEqual(1)
|
||||
expect(result[0]).toEqual({ input: `0x${EXECUTE_AFFIRMATION_HASH}123456` })
|
||||
})
|
||||
})
|
||||
describe('getExecutionFailedTransactionForMessage', () => {
|
||||
test('should return failed transaction related to signatures execution', async () => {
|
||||
const transactions = [
|
||||
{ input: `0x${EXECUTE_SIGNATURES_HASH}112233` },
|
||||
{ input: `0x${EXECUTE_SIGNATURES_HASH}123456` },
|
||||
{ input: `0x${OTHER_HASH}123456` },
|
||||
{ input: `0x${OTHER_HASH}112233` }
|
||||
] as APITransaction[]
|
||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||
|
||||
const result = await getExecutionFailedTransactionForMessage(
|
||||
{
|
||||
account: '',
|
||||
to: '',
|
||||
messageData,
|
||||
startTimestamp: 0,
|
||||
endTimestamp: 1
|
||||
},
|
||||
fetchAccountTransactions
|
||||
)
|
||||
expect(result.length).toEqual(1)
|
||||
expect(result[0]).toEqual({ input: `0x${EXECUTE_SIGNATURES_HASH}123456` })
|
||||
})
|
||||
})
|
||||
describe('getValidatorPendingTransactionsForMessage', () => {
|
||||
test('should return pending transaction for submit signature transaction', async () => {
|
||||
const transactions = [
|
||||
{ input: `0x${SUBMIT_SIGNATURE_HASH}112233`, to: bridgeAddress },
|
||||
{ input: `0x${SUBMIT_SIGNATURE_HASH}123456`, to: bridgeAddress },
|
||||
{ input: `0x${SUBMIT_SIGNATURE_HASH}123456`, to: otherAddress },
|
||||
{ input: `0x${OTHER_HASH}123456`, to: bridgeAddress },
|
||||
{ input: `0x${OTHER_HASH}112233`, to: bridgeAddress }
|
||||
] as APITransaction[]
|
||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||
|
||||
const result = await getValidatorPendingTransactionsForMessage(
|
||||
{
|
||||
account: '',
|
||||
to: bridgeAddress,
|
||||
messageData
|
||||
},
|
||||
fetchAccountTransactions
|
||||
)
|
||||
|
||||
expect(result.length).toEqual(1)
|
||||
expect(result[0]).toEqual({ input: `0x${SUBMIT_SIGNATURE_HASH}123456`, to: bridgeAddress })
|
||||
})
|
||||
test('should return pending transaction for execute affirmation transaction', async () => {
|
||||
const transactions = [
|
||||
{ input: `0x${EXECUTE_AFFIRMATION_HASH}112233`, to: bridgeAddress },
|
||||
{ input: `0x${EXECUTE_AFFIRMATION_HASH}123456`, to: bridgeAddress },
|
||||
{ input: `0x${EXECUTE_AFFIRMATION_HASH}123456`, to: otherAddress },
|
||||
{ input: `0x${OTHER_HASH}123456`, to: bridgeAddress },
|
||||
{ input: `0x${OTHER_HASH}112233`, to: bridgeAddress }
|
||||
] as APITransaction[]
|
||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||
|
||||
const result = await getValidatorPendingTransactionsForMessage(
|
||||
{
|
||||
account: '',
|
||||
to: bridgeAddress,
|
||||
messageData
|
||||
},
|
||||
fetchAccountTransactions
|
||||
)
|
||||
|
||||
expect(result.length).toEqual(1)
|
||||
expect(result[0]).toEqual({ input: `0x${EXECUTE_AFFIRMATION_HASH}123456`, to: bridgeAddress })
|
||||
})
|
||||
})
|
||||
describe('getExecutionPendingTransactionsForMessage', () => {
|
||||
test('should return pending transaction for signatures execution transaction', async () => {
|
||||
const transactions = [
|
||||
{ input: `0x${EXECUTE_SIGNATURES_HASH}112233`, to: bridgeAddress },
|
||||
{ input: `0x${EXECUTE_SIGNATURES_HASH}123456`, to: bridgeAddress },
|
||||
{ input: `0x${EXECUTE_SIGNATURES_HASH}123456`, to: otherAddress },
|
||||
{ input: `0x${OTHER_HASH}123456`, to: bridgeAddress },
|
||||
{ input: `0x${OTHER_HASH}112233`, to: bridgeAddress }
|
||||
] as APITransaction[]
|
||||
const fetchAccountTransactions = jest.fn().mockImplementation(() => transactions)
|
||||
|
||||
const result = await getExecutionPendingTransactionsForMessage(
|
||||
{
|
||||
account: '',
|
||||
to: bridgeAddress,
|
||||
messageData
|
||||
},
|
||||
fetchAccountTransactions
|
||||
)
|
||||
|
||||
expect(result.length).toEqual(1)
|
||||
expect(result[0]).toEqual({ input: `0x${EXECUTE_SIGNATURES_HASH}123456`, to: bridgeAddress })
|
||||
})
|
||||
})
|
437
alm/src/utils/__tests__/getConfirmationsForTx.test.ts
Normal file
437
alm/src/utils/__tests__/getConfirmationsForTx.test.ts
Normal file
@ -0,0 +1,437 @@
|
||||
import 'jest'
|
||||
import { getConfirmationsForTx } from '../getConfirmationsForTx'
|
||||
import * as helpers from '../validatorConfirmationHelpers'
|
||||
import Web3 from 'web3'
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
import { APIPendingTransaction, APITransaction } from '../explorer'
|
||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
|
||||
import { BasicConfirmationParam } from '../../hooks/useMessageConfirmations'
|
||||
|
||||
jest.mock('../validatorConfirmationHelpers')
|
||||
|
||||
const getValidatorSuccessTransaction = helpers.getValidatorSuccessTransaction as jest.Mock<any>
|
||||
const getValidatorConfirmation = helpers.getValidatorConfirmation as jest.Mock<any>
|
||||
const getValidatorFailedTransaction = helpers.getValidatorFailedTransaction as jest.Mock<any>
|
||||
const getValidatorPendingTransaction = helpers.getValidatorPendingTransaction as jest.Mock<any>
|
||||
|
||||
const messageData = '0x111111111'
|
||||
const web3 = {
|
||||
utils: {
|
||||
soliditySha3Raw: (data: string) => `0xaaaa${data.replace('0x', '')}`
|
||||
}
|
||||
} as Web3
|
||||
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
||||
const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
|
||||
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
|
||||
const validatorList = [validator1, validator2, validator3]
|
||||
const bridgeContract = {} as Contract
|
||||
const confirmationContractMethod = () => {}
|
||||
const requiredSignatures = 2
|
||||
const waitingBlocksResolved = true
|
||||
let subscriptions: Array<number> = []
|
||||
const timestamp = 1594045859
|
||||
const getFailedTransactions = (): Promise<APITransaction[]> => Promise.resolve([])
|
||||
const getPendingTransactions = (): Promise<APIPendingTransaction[]> => Promise.resolve([])
|
||||
const getSuccessTransactions = (): Promise<APITransaction[]> => Promise.resolve([])
|
||||
|
||||
const unsubscribe = () => {
|
||||
subscriptions.forEach(s => {
|
||||
clearTimeout(s)
|
||||
})
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
// Clear all instances and calls to constructor and all methods:
|
||||
getValidatorSuccessTransaction.mockClear()
|
||||
getValidatorConfirmation.mockClear()
|
||||
getValidatorFailedTransaction.mockClear()
|
||||
getValidatorPendingTransaction.mockClear()
|
||||
subscriptions = []
|
||||
})
|
||||
describe('getConfirmationsForTx', () => {
|
||||
test('should set validator confirmations status when signatures collected even if validator transactions not found yet and set remaining validator as not required', async () => {
|
||||
getValidatorConfirmation.mockImplementation(() => async (validator: string) => ({
|
||||
validator,
|
||||
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
|
||||
const setResult = jest.fn()
|
||||
const setSignatureCollected = jest.fn()
|
||||
const setFailedConfirmations = jest.fn()
|
||||
const setPendingConfirmations = jest.fn()
|
||||
|
||||
await getConfirmationsForTx(
|
||||
messageData,
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
getPendingTransactions,
|
||||
setPendingConfirmations,
|
||||
getSuccessTransactions
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(1)
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(0)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(0)
|
||||
|
||||
expect(getValidatorPendingTransaction).toBeCalledTimes(0)
|
||||
expect(setPendingConfirmations).toBeCalledTimes(0)
|
||||
|
||||
expect(setResult.mock.calls[0][0]).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
||||
])
|
||||
)
|
||||
})
|
||||
test('should set validator confirmations status when signatures not collected even if validator transactions not found yet', async () => {
|
||||
getValidatorConfirmation.mockImplementation(() => async (validator: string) => ({
|
||||
validator,
|
||||
status: validator === validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
|
||||
const setResult = jest.fn()
|
||||
const setSignatureCollected = jest.fn()
|
||||
const setFailedConfirmations = jest.fn()
|
||||
const setPendingConfirmations = jest.fn()
|
||||
|
||||
await getConfirmationsForTx(
|
||||
messageData,
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
getPendingTransactions,
|
||||
setPendingConfirmations,
|
||||
getSuccessTransactions
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(0)
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(0)
|
||||
|
||||
expect(getValidatorPendingTransaction).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations).toBeCalledTimes(0)
|
||||
})
|
||||
test('should set validator confirmations status, validator transactions and not retry', async () => {
|
||||
getValidatorConfirmation.mockImplementation(() => async (validator: string) => ({
|
||||
validator,
|
||||
status: validator !== validator3 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: validatorData.validator !== validator3 ? '0x123' : '',
|
||||
timestamp: validatorData.validator !== validator3 ? 123 : 0
|
||||
}))
|
||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
|
||||
const setResult = jest.fn()
|
||||
const setSignatureCollected = jest.fn()
|
||||
const setFailedConfirmations = jest.fn()
|
||||
const setPendingConfirmations = jest.fn()
|
||||
|
||||
await getConfirmationsForTx(
|
||||
messageData,
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
getPendingTransactions,
|
||||
setPendingConfirmations,
|
||||
getSuccessTransactions
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(0)
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(1)
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(0)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(0)
|
||||
|
||||
expect(getValidatorPendingTransaction).toBeCalledTimes(0)
|
||||
expect(setPendingConfirmations).toBeCalledTimes(0)
|
||||
|
||||
expect(setResult.mock.calls[0][0]).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, 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 }
|
||||
])
|
||||
)
|
||||
})
|
||||
test('should look for failed and pending transactions for not confirmed validators', async () => {
|
||||
// Validator1 success
|
||||
// Validator2 failed
|
||||
// Validator3 Pending
|
||||
|
||||
getValidatorConfirmation.mockImplementation(() => async (validator: string) => ({
|
||||
validator,
|
||||
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
||||
timestamp: validatorData.validator === validator1 ? 123 : 0
|
||||
}))
|
||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status:
|
||||
validatorData.validator === validator2
|
||||
? VALIDATOR_CONFIRMATION_STATUS.FAILED
|
||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: validatorData.validator === validator2 ? '0x123' : '',
|
||||
timestamp: validatorData.validator === validator2 ? 123 : 0
|
||||
}))
|
||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status:
|
||||
validatorData.validator === validator3
|
||||
? VALIDATOR_CONFIRMATION_STATUS.PENDING
|
||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: validatorData.validator === validator3 ? '0x123' : '',
|
||||
timestamp: validatorData.validator === validator3 ? 123 : 0
|
||||
}))
|
||||
|
||||
const setResult = jest.fn()
|
||||
const setSignatureCollected = jest.fn()
|
||||
const setFailedConfirmations = jest.fn()
|
||||
const setPendingConfirmations = jest.fn()
|
||||
|
||||
await getConfirmationsForTx(
|
||||
messageData,
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
getPendingTransactions,
|
||||
setPendingConfirmations,
|
||||
getSuccessTransactions
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(0)
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(0)
|
||||
|
||||
expect(getValidatorPendingTransaction).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations).toBeCalledTimes(1)
|
||||
|
||||
expect(setResult.mock.calls[0][0]).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.PENDING, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
})
|
||||
test('should set as failed if enough signatures failed', async () => {
|
||||
// Validator1 success
|
||||
// Validator2 failed
|
||||
// Validator3 failed
|
||||
|
||||
getValidatorConfirmation.mockImplementation(() => async (validator: string) => ({
|
||||
validator,
|
||||
status: validator === validator1 ? VALIDATOR_CONFIRMATION_STATUS.SUCCESS : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
}))
|
||||
getValidatorSuccessTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash: validatorData.validator === validator1 ? '0x123' : '',
|
||||
timestamp: validatorData.validator === validator1 ? 123 : 0
|
||||
}))
|
||||
getValidatorFailedTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status:
|
||||
validatorData.validator !== validator1
|
||||
? VALIDATOR_CONFIRMATION_STATUS.FAILED
|
||||
: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: validatorData.validator !== validator1 ? '0x123' : '',
|
||||
timestamp: validatorData.validator !== validator1 ? 123 : 0
|
||||
}))
|
||||
getValidatorPendingTransaction.mockImplementation(() => async (validatorData: BasicConfirmationParam) => ({
|
||||
validator: validatorData.validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
|
||||
txHash: '',
|
||||
timestamp: 0
|
||||
}))
|
||||
|
||||
const setResult = jest.fn()
|
||||
const setSignatureCollected = jest.fn()
|
||||
const setFailedConfirmations = jest.fn()
|
||||
const setPendingConfirmations = jest.fn()
|
||||
|
||||
await getConfirmationsForTx(
|
||||
messageData,
|
||||
web3,
|
||||
validatorList,
|
||||
bridgeContract,
|
||||
confirmationContractMethod,
|
||||
setResult,
|
||||
requiredSignatures,
|
||||
setSignatureCollected,
|
||||
waitingBlocksResolved,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
getFailedTransactions,
|
||||
setFailedConfirmations,
|
||||
getPendingTransactions,
|
||||
setPendingConfirmations,
|
||||
getSuccessTransactions
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(0)
|
||||
expect(setResult).toBeCalledTimes(2)
|
||||
expect(getValidatorConfirmation).toBeCalledTimes(1)
|
||||
expect(getValidatorSuccessTransaction).toBeCalledTimes(1)
|
||||
expect(setSignatureCollected).toBeCalledTimes(0)
|
||||
|
||||
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
|
||||
expect(setFailedConfirmations).toBeCalledTimes(1)
|
||||
|
||||
expect(getValidatorPendingTransaction).toBeCalledTimes(1)
|
||||
expect(setPendingConfirmations).toBeCalledTimes(0)
|
||||
|
||||
expect(setResult.mock.calls[0][0]).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
expect(setResult.mock.calls[1][0]).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ validator: validator1, status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator2, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 },
|
||||
{ validator: validator3, status: VALIDATOR_CONFIRMATION_STATUS.FAILED, txHash: '0x123', timestamp: 123 }
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
303
alm/src/utils/__tests__/getFinalizationEvent.test.ts
Normal file
303
alm/src/utils/__tests__/getFinalizationEvent.test.ts
Normal file
@ -0,0 +1,303 @@
|
||||
import 'jest'
|
||||
import { Contract, EventData } from 'web3-eth-contract'
|
||||
import Web3 from 'web3'
|
||||
import { getFinalizationEvent } from '../getFinalizationEvent'
|
||||
import { VALIDATOR_CONFIRMATION_STATUS } from '../../config/constants'
|
||||
|
||||
const eventName = 'RelayedMessage'
|
||||
const timestamp = 1594045859
|
||||
const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
|
||||
const txHash = '0xdab36c9210e7e45fb82af10ffe4960461e41661dce0c9cd36b2843adaa1df156'
|
||||
|
||||
const web3 = ({
|
||||
eth: {
|
||||
getTransactionReceipt: () => ({
|
||||
from: validator1
|
||||
}),
|
||||
getBlock: () => ({ timestamp })
|
||||
},
|
||||
utils: {
|
||||
toChecksumAddress: (a: string) => a
|
||||
}
|
||||
} as unknown) as Web3
|
||||
const waitingBlocksResolved = true
|
||||
const message = {
|
||||
id: '0x123',
|
||||
data: '0x123456789'
|
||||
}
|
||||
const interval = 10000
|
||||
let subscriptions: Array<number> = []
|
||||
|
||||
const event = {
|
||||
transactionHash: txHash,
|
||||
blockNumber: 5523145,
|
||||
returnValues: {
|
||||
status: true
|
||||
}
|
||||
}
|
||||
|
||||
const bridgeAddress = '0xFe446bEF1DbF7AFE24E81e05BC8B271C1BA9a560'
|
||||
|
||||
const unsubscribe = () => {
|
||||
subscriptions.forEach(s => {
|
||||
clearTimeout(s)
|
||||
})
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
subscriptions = []
|
||||
})
|
||||
describe('getFinalizationEvent', () => {
|
||||
test('should get finalization event and not try to get failed or pending transactions', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
return [event]
|
||||
}
|
||||
} as unknown) as Contract
|
||||
|
||||
const collectedSignaturesEvent = null
|
||||
const setResult = jest.fn()
|
||||
const getFailedExecution = jest.fn()
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn()
|
||||
const setPendingExecution = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(0)
|
||||
expect(setResult).toBeCalledTimes(1)
|
||||
expect(setResult.mock.calls[0][0]).toEqual({
|
||||
validator: validator1,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS,
|
||||
txHash,
|
||||
timestamp,
|
||||
executionResult: true
|
||||
})
|
||||
|
||||
expect(getFailedExecution).toBeCalledTimes(0)
|
||||
expect(setFailedExecution).toBeCalledTimes(0)
|
||||
|
||||
expect(getPendingExecution).toBeCalledTimes(0)
|
||||
expect(setPendingExecution).toBeCalledTimes(0)
|
||||
})
|
||||
test('should retry to get finalization event and not try to get failed or pending transactions if foreign to home transaction', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
return []
|
||||
}
|
||||
} as unknown) as Contract
|
||||
|
||||
const collectedSignaturesEvent = null
|
||||
const setResult = jest.fn()
|
||||
const getFailedExecution = jest.fn()
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn()
|
||||
const setPendingExecution = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(1)
|
||||
expect(setResult).toBeCalledTimes(0)
|
||||
|
||||
expect(getFailedExecution).toBeCalledTimes(0)
|
||||
expect(setFailedExecution).toBeCalledTimes(0)
|
||||
|
||||
expect(getPendingExecution).toBeCalledTimes(0)
|
||||
expect(setPendingExecution).toBeCalledTimes(0)
|
||||
})
|
||||
test('should retry to get finalization event and try to get failed and pending transactions if home to foreign transaction', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
return []
|
||||
},
|
||||
options: {
|
||||
address: bridgeAddress
|
||||
}
|
||||
} as unknown) as Contract
|
||||
|
||||
const collectedSignaturesEvent = ({
|
||||
returnValues: {
|
||||
authorityResponsibleForRelay: validator1
|
||||
}
|
||||
} as unknown) as EventData
|
||||
const setResult = jest.fn()
|
||||
const getFailedExecution = jest.fn().mockResolvedValue([])
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn().mockResolvedValue([])
|
||||
const setPendingExecution = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(1)
|
||||
expect(setResult).toBeCalledTimes(0)
|
||||
|
||||
expect(getFailedExecution).toBeCalledTimes(1)
|
||||
expect(setFailedExecution).toBeCalledTimes(0)
|
||||
|
||||
expect(getPendingExecution).toBeCalledTimes(1)
|
||||
expect(setPendingExecution).toBeCalledTimes(0)
|
||||
})
|
||||
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 = ({
|
||||
getPastEvents: () => {
|
||||
return []
|
||||
},
|
||||
options: {
|
||||
address: bridgeAddress
|
||||
}
|
||||
} as unknown) as Contract
|
||||
|
||||
const collectedSignaturesEvent = ({
|
||||
returnValues: {
|
||||
authorityResponsibleForRelay: validator1
|
||||
}
|
||||
} as unknown) as EventData
|
||||
const setResult = jest.fn()
|
||||
const getFailedExecution = jest.fn().mockResolvedValue([])
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn().mockResolvedValue([{ hash: txHash }])
|
||||
const setPendingExecution = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(1)
|
||||
expect(setResult).toBeCalledTimes(1)
|
||||
expect(setResult.mock.calls[0][0]).toEqual({
|
||||
validator: validator1,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.PENDING,
|
||||
txHash,
|
||||
timestamp: expect.any(Number),
|
||||
executionResult: false
|
||||
})
|
||||
|
||||
expect(getFailedExecution).toBeCalledTimes(0)
|
||||
expect(setFailedExecution).toBeCalledTimes(0)
|
||||
|
||||
expect(getPendingExecution).toBeCalledTimes(1)
|
||||
expect(setPendingExecution).toBeCalledTimes(1)
|
||||
})
|
||||
test('should retry to get finalization event even if failed transaction found if home to foreign transaction', async () => {
|
||||
const contract = ({
|
||||
getPastEvents: () => {
|
||||
return []
|
||||
},
|
||||
options: {
|
||||
address: bridgeAddress
|
||||
}
|
||||
} as unknown) as Contract
|
||||
|
||||
const collectedSignaturesEvent = ({
|
||||
returnValues: {
|
||||
authorityResponsibleForRelay: validator1
|
||||
}
|
||||
} as unknown) as EventData
|
||||
const setResult = jest.fn()
|
||||
const getFailedExecution = jest.fn().mockResolvedValue([{ timeStamp: timestamp, hash: txHash }])
|
||||
const setFailedExecution = jest.fn()
|
||||
const getPendingExecution = jest.fn().mockResolvedValue([])
|
||||
const setPendingExecution = jest.fn()
|
||||
|
||||
await getFinalizationEvent(
|
||||
contract,
|
||||
eventName,
|
||||
web3,
|
||||
setResult,
|
||||
waitingBlocksResolved,
|
||||
message,
|
||||
interval,
|
||||
subscriptions,
|
||||
timestamp,
|
||||
collectedSignaturesEvent,
|
||||
getFailedExecution,
|
||||
setFailedExecution,
|
||||
getPendingExecution,
|
||||
setPendingExecution
|
||||
)
|
||||
|
||||
unsubscribe()
|
||||
|
||||
expect(subscriptions.length).toEqual(1)
|
||||
expect(setResult).toBeCalledTimes(1)
|
||||
expect(setResult.mock.calls[0][0]).toEqual({
|
||||
validator: validator1,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.FAILED,
|
||||
txHash,
|
||||
timestamp: expect.any(Number),
|
||||
executionResult: false
|
||||
})
|
||||
|
||||
expect(getFailedExecution).toBeCalledTimes(1)
|
||||
expect(setFailedExecution).toBeCalledTimes(1)
|
||||
|
||||
expect(getPendingExecution).toBeCalledTimes(1)
|
||||
expect(setPendingExecution).toBeCalledTimes(0)
|
||||
})
|
||||
})
|
@ -217,14 +217,11 @@ export const getValidatorSuccessTransactionsForMessage = async ({
|
||||
return filterValidatorSignatureTransaction(transactions, messageData)
|
||||
}
|
||||
|
||||
export const getExecutionFailedTransactionForMessage = async ({
|
||||
account,
|
||||
to,
|
||||
messageData,
|
||||
startTimestamp,
|
||||
endTimestamp
|
||||
}: GetFailedTransactionParams): Promise<APITransaction[]> => {
|
||||
const failedTransactions = await getFailedTransactions(
|
||||
export const getExecutionFailedTransactionForMessage = async (
|
||||
{ account, to, messageData, startTimestamp, endTimestamp }: GetFailedTransactionParams,
|
||||
getFailedTransactionsMethod = getFailedTransactions
|
||||
): Promise<APITransaction[]> => {
|
||||
const failedTransactions = await getFailedTransactionsMethod(
|
||||
account,
|
||||
to,
|
||||
startTimestamp,
|
||||
@ -237,12 +234,11 @@ export const getExecutionFailedTransactionForMessage = async ({
|
||||
return failedTransactions.filter(t => t.input.includes(EXECUTE_SIGNATURES_HASH) && t.input.includes(messageDataValue))
|
||||
}
|
||||
|
||||
export const getValidatorPendingTransactionsForMessage = async ({
|
||||
account,
|
||||
to,
|
||||
messageData
|
||||
}: GetPendingTransactionParams): Promise<APIPendingTransaction[]> => {
|
||||
const pendingTransactions = await fetchPendingTransactions({
|
||||
export const getValidatorPendingTransactionsForMessage = async (
|
||||
{ account, to, messageData }: GetPendingTransactionParams,
|
||||
fetchPendingTransactionsMethod = fetchPendingTransactions
|
||||
): Promise<APIPendingTransaction[]> => {
|
||||
const pendingTransactions = await fetchPendingTransactionsMethod({
|
||||
account,
|
||||
api: HOME_EXPLORER_API
|
||||
})
|
||||
@ -258,12 +254,11 @@ export const getValidatorPendingTransactionsForMessage = async ({
|
||||
)
|
||||
}
|
||||
|
||||
export const getExecutionPendingTransactionsForMessage = async ({
|
||||
account,
|
||||
to,
|
||||
messageData
|
||||
}: GetPendingTransactionParams): Promise<APIPendingTransaction[]> => {
|
||||
const pendingTransactions = await fetchPendingTransactions({
|
||||
export const getExecutionPendingTransactionsForMessage = async (
|
||||
{ account, to, messageData }: GetPendingTransactionParams,
|
||||
fetchPendingTransactionsMethod = fetchPendingTransactions
|
||||
): Promise<APIPendingTransaction[]> => {
|
||||
const pendingTransactions = await fetchPendingTransactionsMethod({
|
||||
account,
|
||||
api: FOREIGN_EXPLORER_API
|
||||
})
|
||||
|
@ -1,176 +1,18 @@
|
||||
import Web3 from 'web3'
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
import validatorsCache from '../services/ValidatorsCache'
|
||||
import {
|
||||
CACHE_KEY_FAILED,
|
||||
CACHE_KEY_SUCCESS,
|
||||
HOME_RPC_POLLING_INTERVAL,
|
||||
ONE_DAY_TIMESTAMP,
|
||||
VALIDATOR_CONFIRMATION_STATUS
|
||||
} from '../config/constants'
|
||||
import { HOME_RPC_POLLING_INTERVAL, VALIDATOR_CONFIRMATION_STATUS } from '../config/constants'
|
||||
import {
|
||||
GetFailedTransactionParams,
|
||||
APITransaction,
|
||||
APIPendingTransaction,
|
||||
GetPendingTransactionParams
|
||||
} from './explorer'
|
||||
import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||
|
||||
export const getValidatorConfirmation = (
|
||||
web3: Web3,
|
||||
hashMsg: string,
|
||||
bridgeContract: Contract,
|
||||
confirmationContractMethod: Function
|
||||
) => async (validator: string): Promise<BasicConfirmationParam> => {
|
||||
const hashSenderMsg = web3.utils.soliditySha3Raw(validator, hashMsg)
|
||||
|
||||
const signatureFromCache = validatorsCache.get(hashSenderMsg)
|
||||
if (signatureFromCache) {
|
||||
return {
|
||||
validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
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 (confirmed) {
|
||||
validatorsCache.set(hashSenderMsg, confirmed)
|
||||
}
|
||||
|
||||
return {
|
||||
validator,
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
export const getValidatorSuccessTransaction = (
|
||||
bridgeContract: Contract,
|
||||
messageData: string,
|
||||
timestamp: number,
|
||||
getSuccessTransactions: (args: GetFailedTransactionParams) => Promise<APITransaction[]>
|
||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
||||
const { validator } = validatorData
|
||||
const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}-${messageData}`
|
||||
const fromCache = validatorsCache.getData(validatorCacheKey)
|
||||
|
||||
if (fromCache && fromCache.txHash) {
|
||||
return fromCache
|
||||
}
|
||||
|
||||
const transactions = await getSuccessTransactions({
|
||||
account: validatorData.validator,
|
||||
to: bridgeContract.options.address,
|
||||
messageData,
|
||||
startTimestamp: timestamp,
|
||||
endTimestamp: timestamp + ONE_DAY_TIMESTAMP
|
||||
})
|
||||
|
||||
let txHashTimestamp = 0
|
||||
let txHash = ''
|
||||
const status = VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
||||
|
||||
if (transactions.length > 0) {
|
||||
const tx = transactions[0]
|
||||
txHashTimestamp = parseInt(tx.timeStamp)
|
||||
txHash = tx.hash
|
||||
|
||||
// cache the result
|
||||
validatorsCache.setData(validatorCacheKey, {
|
||||
validator,
|
||||
status,
|
||||
txHash,
|
||||
timestamp: txHashTimestamp
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
validator,
|
||||
status,
|
||||
txHash,
|
||||
timestamp: txHashTimestamp
|
||||
}
|
||||
}
|
||||
|
||||
export const getValidatorFailedTransaction = (
|
||||
bridgeContract: Contract,
|
||||
messageData: string,
|
||||
timestamp: number,
|
||||
getFailedTransactions: (args: GetFailedTransactionParams) => Promise<APITransaction[]>
|
||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
||||
const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}-${messageData}`
|
||||
const failedFromCache = validatorsCache.getData(validatorCacheKey)
|
||||
|
||||
if (failedFromCache && failedFromCache.txHash) {
|
||||
return failedFromCache
|
||||
}
|
||||
|
||||
const failedTransactions = await getFailedTransactions({
|
||||
account: validatorData.validator,
|
||||
to: bridgeContract.options.address,
|
||||
messageData,
|
||||
startTimestamp: timestamp,
|
||||
endTimestamp: timestamp + ONE_DAY_TIMESTAMP
|
||||
})
|
||||
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 (failedTransactions.length > 0) {
|
||||
const failedTx = failedTransactions[0]
|
||||
txHashTimestamp = parseInt(failedTx.timeStamp)
|
||||
txHash = failedTx.hash
|
||||
|
||||
validatorsCache.setData(validatorCacheKey, {
|
||||
validator: validatorData.validator,
|
||||
status: newStatus,
|
||||
txHash,
|
||||
timestamp: txHashTimestamp
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
validator: validatorData.validator,
|
||||
status: newStatus,
|
||||
txHash,
|
||||
timestamp: txHashTimestamp
|
||||
}
|
||||
}
|
||||
|
||||
export const getValidatorPendingTransaction = (
|
||||
bridgeContract: Contract,
|
||||
messageData: string,
|
||||
getPendingTransactions: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>
|
||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
||||
const failedTransactions = await getPendingTransactions({
|
||||
account: validatorData.validator,
|
||||
to: bridgeContract.options.address,
|
||||
messageData
|
||||
})
|
||||
|
||||
const newStatus =
|
||||
failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.PENDING : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
|
||||
let timestamp = 0
|
||||
let txHash = ''
|
||||
|
||||
if (failedTransactions.length > 0) {
|
||||
const failedTx = failedTransactions[0]
|
||||
timestamp = Math.floor(new Date().getTime() / 1000.0)
|
||||
txHash = failedTx.hash
|
||||
}
|
||||
|
||||
return {
|
||||
validator: validatorData.validator,
|
||||
status: newStatus,
|
||||
txHash,
|
||||
timestamp
|
||||
}
|
||||
}
|
||||
import {
|
||||
getValidatorConfirmation,
|
||||
getValidatorFailedTransaction,
|
||||
getValidatorPendingTransaction,
|
||||
getValidatorSuccessTransaction
|
||||
} from './validatorConfirmationHelpers'
|
||||
|
||||
export const getConfirmationsForTx = async (
|
||||
messageData: string,
|
||||
|
172
alm/src/utils/validatorConfirmationHelpers.ts
Normal file
172
alm/src/utils/validatorConfirmationHelpers.ts
Normal file
@ -0,0 +1,172 @@
|
||||
import Web3 from 'web3'
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
import { BasicConfirmationParam, ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||
import validatorsCache from '../services/ValidatorsCache'
|
||||
import {
|
||||
CACHE_KEY_FAILED,
|
||||
CACHE_KEY_SUCCESS,
|
||||
ONE_DAY_TIMESTAMP,
|
||||
VALIDATOR_CONFIRMATION_STATUS
|
||||
} from '../config/constants'
|
||||
import {
|
||||
APIPendingTransaction,
|
||||
APITransaction,
|
||||
GetFailedTransactionParams,
|
||||
GetPendingTransactionParams
|
||||
} from './explorer'
|
||||
|
||||
export const getValidatorConfirmation = (
|
||||
web3: Web3,
|
||||
hashMsg: string,
|
||||
bridgeContract: Contract,
|
||||
confirmationContractMethod: Function
|
||||
) => async (validator: string): Promise<BasicConfirmationParam> => {
|
||||
const hashSenderMsg = web3.utils.soliditySha3Raw(validator, hashMsg)
|
||||
|
||||
const signatureFromCache = validatorsCache.get(hashSenderMsg)
|
||||
if (signatureFromCache) {
|
||||
return {
|
||||
validator,
|
||||
status: VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
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 (confirmed) {
|
||||
validatorsCache.set(hashSenderMsg, confirmed)
|
||||
}
|
||||
|
||||
return {
|
||||
validator,
|
||||
status
|
||||
}
|
||||
}
|
||||
|
||||
export const getValidatorSuccessTransaction = (
|
||||
bridgeContract: Contract,
|
||||
messageData: string,
|
||||
timestamp: number,
|
||||
getSuccessTransactions: (args: GetFailedTransactionParams) => Promise<APITransaction[]>
|
||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
||||
const { validator } = validatorData
|
||||
const validatorCacheKey = `${CACHE_KEY_SUCCESS}${validatorData.validator}-${messageData}`
|
||||
const fromCache = validatorsCache.getData(validatorCacheKey)
|
||||
|
||||
if (fromCache && fromCache.txHash) {
|
||||
return fromCache
|
||||
}
|
||||
|
||||
const transactions = await getSuccessTransactions({
|
||||
account: validatorData.validator,
|
||||
to: bridgeContract.options.address,
|
||||
messageData,
|
||||
startTimestamp: timestamp,
|
||||
endTimestamp: timestamp + ONE_DAY_TIMESTAMP
|
||||
})
|
||||
|
||||
let txHashTimestamp = 0
|
||||
let txHash = ''
|
||||
const status = VALIDATOR_CONFIRMATION_STATUS.SUCCESS
|
||||
|
||||
if (transactions.length > 0) {
|
||||
const tx = transactions[0]
|
||||
txHashTimestamp = parseInt(tx.timeStamp)
|
||||
txHash = tx.hash
|
||||
|
||||
// cache the result
|
||||
validatorsCache.setData(validatorCacheKey, {
|
||||
validator,
|
||||
status,
|
||||
txHash,
|
||||
timestamp: txHashTimestamp
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
validator,
|
||||
status,
|
||||
txHash,
|
||||
timestamp: txHashTimestamp
|
||||
}
|
||||
}
|
||||
|
||||
export const getValidatorFailedTransaction = (
|
||||
bridgeContract: Contract,
|
||||
messageData: string,
|
||||
timestamp: number,
|
||||
getFailedTransactions: (args: GetFailedTransactionParams) => Promise<APITransaction[]>
|
||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
||||
const validatorCacheKey = `${CACHE_KEY_FAILED}${validatorData.validator}-${messageData}`
|
||||
const failedFromCache = validatorsCache.getData(validatorCacheKey)
|
||||
|
||||
if (failedFromCache && failedFromCache.txHash) {
|
||||
return failedFromCache
|
||||
}
|
||||
|
||||
const failedTransactions = await getFailedTransactions({
|
||||
account: validatorData.validator,
|
||||
to: bridgeContract.options.address,
|
||||
messageData,
|
||||
startTimestamp: timestamp,
|
||||
endTimestamp: timestamp + ONE_DAY_TIMESTAMP
|
||||
})
|
||||
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 (failedTransactions.length > 0) {
|
||||
const failedTx = failedTransactions[0]
|
||||
txHashTimestamp = parseInt(failedTx.timeStamp)
|
||||
txHash = failedTx.hash
|
||||
|
||||
validatorsCache.setData(validatorCacheKey, {
|
||||
validator: validatorData.validator,
|
||||
status: newStatus,
|
||||
txHash,
|
||||
timestamp: txHashTimestamp
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
validator: validatorData.validator,
|
||||
status: newStatus,
|
||||
txHash,
|
||||
timestamp: txHashTimestamp
|
||||
}
|
||||
}
|
||||
|
||||
export const getValidatorPendingTransaction = (
|
||||
bridgeContract: Contract,
|
||||
messageData: string,
|
||||
getPendingTransactions: (args: GetPendingTransactionParams) => Promise<APIPendingTransaction[]>
|
||||
) => async (validatorData: BasicConfirmationParam): Promise<ConfirmationParam> => {
|
||||
const failedTransactions = await getPendingTransactions({
|
||||
account: validatorData.validator,
|
||||
to: bridgeContract.options.address,
|
||||
messageData
|
||||
})
|
||||
|
||||
const newStatus =
|
||||
failedTransactions.length > 0 ? VALIDATOR_CONFIRMATION_STATUS.PENDING : VALIDATOR_CONFIRMATION_STATUS.UNDEFINED
|
||||
|
||||
let timestamp = 0
|
||||
let txHash = ''
|
||||
|
||||
if (failedTransactions.length > 0) {
|
||||
const failedTx = failedTransactions[0]
|
||||
timestamp = Math.floor(new Date().getTime() / 1000.0)
|
||||
txHash = failedTx.hash
|
||||
}
|
||||
|
||||
return {
|
||||
validator: validatorData.validator,
|
||||
status: newStatus,
|
||||
txHash,
|
||||
timestamp
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user