Fetch signatures from RPC endpoint immediatly after enough signatures are collected (#499)

This commit is contained in:
Kirill Fedoseev 2020-12-20 01:13:49 +03:00 committed by GitHub
parent 04f66b243c
commit 6ce98ff3dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 67 additions and 51 deletions

@ -44,12 +44,13 @@ export interface ConfirmationsContainerParams {
export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }: ConfirmationsContainerParams) => {
const {
home: { name: homeName, confirmations },
home: { name: homeName },
foreign: { name: foreignName }
} = useStateProvider()
const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
const {
confirmations,
status,
executionData,
signatureCollected,
@ -115,7 +116,7 @@ export const ConfirmationsContainer = ({ message, receipt, fromHome, timestamp }
messageData={message.data}
executionData={executionData}
isHome={!fromHome}
requiredSignatures={requiredSignatures}
signatureCollected={signatureCollected}
setExecutionData={setExecutionData}
executionEventsFetched={executionEventsFetched}
setPendingExecution={setPendingExecution}

@ -18,7 +18,7 @@ export interface ExecutionConfirmationParams {
messageData: string
executionData: ExecutionData
setExecutionData: Function
requiredSignatures: number
signatureCollected: boolean | string[]
isHome: boolean
executionEventsFetched: boolean
setPendingExecution: Function
@ -28,7 +28,7 @@ export const ExecutionConfirmation = ({
messageData,
executionData,
setExecutionData,
requiredSignatures,
signatureCollected,
isHome,
executionEventsFetched,
setPendingExecution
@ -105,7 +105,7 @@ export const ExecutionConfirmation = ({
<ManualExecutionButton
messageData={messageData}
setExecutionData={setExecutionData}
requiredSignatures={requiredSignatures}
signatureCollected={signatureCollected as string[]}
setPendingExecution={setPendingExecution}
/>
</td>

@ -18,21 +18,19 @@ const StyledButton = styled.button`
interface ManualExecutionButtonParams {
messageData: string
setExecutionData: Function
requiredSignatures: number
signatureCollected: string[]
setPendingExecution: Function
}
export const ManualExecutionButton = ({
messageData,
setExecutionData,
requiredSignatures,
signatureCollected,
setPendingExecution
}: ManualExecutionButtonParams) => {
const { home, foreign, setError } = useStateProvider()
const { foreign, setError } = useStateProvider()
const { library, activate, account, active } = useWeb3React()
const [manualExecution, setManualExecution] = useState(false)
const disabled =
home.confirmations.filter(({ signature }) => signature && signature.startsWith('0x')).length < requiredSignatures
useEffect(
() => {
@ -60,12 +58,9 @@ export const ManualExecutionButton = ({
return
}
if (!library || !foreign.bridgeContract || !home.confirmations) return
if (!library || !foreign.bridgeContract) return
const collectedSignatures = home.confirmations
.map(confirmation => confirmation.signature!)
.filter(signature => signature && signature.startsWith('0x'))
const signatures = packSignatures(collectedSignatures.map(signatureToVRS))
const signatures = packSignatures(signatureCollected.map(signatureToVRS))
const data = foreign.bridgeContract.methods.executeSignatures(messageData, signatures).encodeABI()
setManualExecution(false)
@ -98,7 +93,7 @@ export const ManualExecutionButton = ({
foreign.bridgeContract,
setError,
messageData,
home.confirmations,
signatureCollected,
setExecutionData,
setPendingExecution
]
@ -106,7 +101,7 @@ export const ManualExecutionButton = ({
return (
<div className="is-center">
<StyledButton disabled={disabled} className="button outline" onClick={() => setManualExecution(true)}>
<StyledButton className="button outline" onClick={() => setManualExecution(true)}>
Execute
</StyledButton>
</div>

@ -63,7 +63,7 @@ export const useMessageConfirmations = ({
blockConfirmations
}: useMessageConfirmationsParams) => {
const { home, foreign } = useStateProvider()
const { confirmations, setConfirmations } = home
const [confirmations, setConfirmations] = useState([])
const [status, setStatus] = useState(CONFIRMATIONS_STATUS.UNDEFINED)
const [waitingBlocks, setWaitingBlocks] = useState(false)
const [waitingBlocksResolved, setWaitingBlocksResolved] = useState(false)
@ -94,7 +94,7 @@ export const useMessageConfirmations = ({
// Check if the validators are waiting for block confirmations to verify the message
useEffect(
() => {
if (!receipt || !blockConfirmations) return
if (!receipt || !blockConfirmations || waitingBlocksResolved) return
const subscriptions: Array<number> = []
@ -127,7 +127,16 @@ export const useMessageConfirmations = ({
blockProvider.stop()
}
},
[blockConfirmations, foreign.web3, fromHome, validatorList, home.web3, receipt, setConfirmations]
[
blockConfirmations,
foreign.web3,
fromHome,
validatorList,
home.web3,
receipt,
setConfirmations,
waitingBlocksResolved
]
)
// The collected signature event is only fetched once the signatures are collected on tx from home to foreign, to calculate if
@ -174,6 +183,7 @@ export const useMessageConfirmations = ({
useEffect(
() => {
if (!fromHome || !home.web3 || !receipt || !collectedSignaturesEvent || !blockConfirmations) return
if (waitingBlocksForExecutionResolved) return
const subscriptions: Array<number> = []
@ -202,7 +212,7 @@ export const useMessageConfirmations = ({
homeBlockNumberProvider.stop()
}
},
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, receipt]
[collectedSignaturesEvent, fromHome, blockConfirmations, home.web3, receipt, waitingBlocksForExecutionResolved]
)
// Checks if validators verified the message
@ -366,6 +376,7 @@ export const useMessageConfirmations = ({
)
return {
confirmations,
status,
signatureCollected,
executionData,

@ -12,7 +12,6 @@ import Web3 from 'web3'
import { useBridgeContracts } from '../hooks/useBridgeContracts'
import { Contract } from 'web3-eth-contract'
import { foreignSnapshotProvider, homeSnapshotProvider } from '../services/SnapshotProvider'
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
export interface BaseNetworkParams {
chainId: number
@ -22,13 +21,8 @@ export interface BaseNetworkParams {
bridgeContract: Maybe<Contract>
}
export interface HomeNetworkParams extends BaseNetworkParams {
confirmations: Array<ConfirmationParam>
setConfirmations: Function
}
export interface StateContext {
home: HomeNetworkParams
home: BaseNetworkParams
foreign: BaseNetworkParams
loading: boolean
error: string
@ -41,9 +35,7 @@ const initialState = {
name: '',
web3: null,
bridgeAddress: HOME_BRIDGE_ADDRESS,
bridgeContract: null,
confirmations: [],
setConfirmations: () => null
bridgeContract: null
},
foreign: {
chainId: 0,
@ -66,7 +58,6 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
homeWeb3: homeNetwork.web3,
foreignWeb3: foreignNetwork.web3
})
const [confirmations, setConfirmations] = useState([])
const [error, setError] = useState('')
const value = {
@ -74,8 +65,6 @@ export const StateProvider = ({ children }: { children: ReactNode }) => {
bridgeAddress: HOME_BRIDGE_ADDRESS,
name: HOME_NETWORK_NAME,
bridgeContract: homeBridge,
confirmations,
setConfirmations,
...homeNetwork
},
foreign: {

@ -24,7 +24,15 @@ const validator1 = '0x45b96809336A8b714BFbdAB3E4B5e0fe5d839908'
const validator2 = '0xAe8bFfc8BBc6AAa9E21ED1E4e4957fe798BEA25f'
const validator3 = '0x285A6eB779be4db94dA65e2F3518B1c5F0f71244'
const validatorList = [validator1, validator2, validator3]
const bridgeContract = {} as Contract
const signature =
'0x519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4519d704bceed17423daa79c20531cc34fc27a4be6e53fc5069a8023019188ca4'
const bridgeContract = {
methods: {
signature: () => ({
call: () => signature
})
}
} as Contract
const requiredSignatures = 2
const waitingBlocksResolved = true
let subscriptions: Array<number> = []
@ -103,7 +111,7 @@ describe('getConfirmationsForTx', () => {
expect(getValidatorConfirmation).toBeCalledTimes(1)
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
expect(setSignatureCollected).toBeCalledTimes(1)
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
expect(setSignatureCollected.mock.calls[0][0]).toEqual([signature, signature])
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
expect(setFailedConfirmations).toBeCalledTimes(1)
@ -247,7 +255,7 @@ describe('getConfirmationsForTx', () => {
expect(getValidatorConfirmation).toBeCalledTimes(1)
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
expect(setSignatureCollected).toBeCalledTimes(1)
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
expect(setSignatureCollected.mock.calls[0][0]).toEqual([signature, signature])
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
expect(setFailedConfirmations).toBeCalledTimes(1)
@ -335,7 +343,7 @@ describe('getConfirmationsForTx', () => {
expect(getValidatorConfirmation).toBeCalledTimes(1)
expect(getSuccessExecutionTransaction).toBeCalledTimes(1)
expect(setSignatureCollected).toBeCalledTimes(1)
expect(setSignatureCollected.mock.calls[0][0]).toEqual(true)
expect(setSignatureCollected.mock.calls[0][0]).toEqual([signature, signature])
expect(getValidatorFailedTransaction).toBeCalledTimes(1)
expect(setFailedConfirmations).toBeCalledTimes(1)
@ -674,7 +682,7 @@ describe('getConfirmationsForTx', () => {
expect(getSuccessExecutionTransaction).toBeCalledTimes(2)
expect(setSignatureCollected).toBeCalledTimes(2)
expect(setSignatureCollected.mock.calls[0][0]).toEqual(false)
expect(setSignatureCollected.mock.calls[1][0]).toEqual(true)
expect(setSignatureCollected.mock.calls[1][0]).toEqual([signature, signature])
expect(getValidatorFailedTransaction).toBeCalledTimes(2)
expect(setFailedConfirmations).toBeCalledTimes(2)

@ -15,13 +15,19 @@ export const checkWaitingBlocksForExecution = async (
const currentBlock = blockProvider.get()
if (currentBlock && currentBlock >= targetBlock) {
setExecutionData({
const undefinedExecutionState = {
status: VALIDATOR_CONFIRMATION_STATUS.UNDEFINED,
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
txHash: '',
timestamp: 0,
executionResult: false
})
}
setExecutionData(
(data: any) =>
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
? undefinedExecutionState
: data
)
setWaitingBlocksForExecutionResolved(true)
setWaitingBlocksForExecution(false)
blockProvider.stop()
@ -31,13 +37,20 @@ export const checkWaitingBlocksForExecution = async (
nextInterval = 500
} else {
setWaitingBlocksForExecution(true)
setExecutionData({
const waitingExecutionState = {
status: VALIDATOR_CONFIRMATION_STATUS.WAITING,
validator: collectedSignaturesEvent.returnValues.authorityResponsibleForRelay,
txHash: '',
timestamp: 0,
executionResult: false
})
}
setExecutionData(
(data: any) =>
data.status === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED ||
data.status === VALIDATOR_CONFIRMATION_STATUS.WAITING
? waitingExecutionState
: data
)
}
const timeoutId = setTimeout(
() =>

@ -113,7 +113,7 @@ export const getConfirmationsForTx = async (
shouldRetry = true
}
let signatureCollectedResult = false
let signatureCollectedResult: boolean | string[] = false
if (successConfirmations.length === requiredSignatures) {
// If signatures collected, it should set other signatures not found as not required
const notRequiredConfirmations = missingConfirmations.map(c => ({
@ -126,6 +126,12 @@ export const getConfirmationsForTx = async (
validatorConfirmations[index] = validatorData
})
signatureCollectedResult = true
if (fromHome) {
signatureCollectedResult = await Promise.all(
Array.from(Array(requiredSignatures).keys()).map(i => bridgeContract.methods.signature(hashMsg, i).call())
)
}
}
// get transactions from success signatures

@ -71,24 +71,18 @@ export const getSuccessExecutionTransaction = (
let txHashTimestamp = 0
let txHash = ''
let signature = ''
const status = VALIDATOR_CONFIRMATION_STATUS.SUCCESS
if (transactions.length > 0) {
const tx = transactions[0]
txHashTimestamp = parseInt(tx.timeStamp)
txHash = tx.hash
if (fromHome) {
const decoded = web3.eth.abi.decodeParameters(['bytes', 'bytes'], `0x${tx.input.substr(10)}`)
signature = decoded[0]
}
// cache the result
validatorsCache.setData(validatorCacheKey, {
validator,
status,
txHash,
signature,
timestamp: txHashTimestamp
})
}
@ -97,7 +91,6 @@ export const getSuccessExecutionTransaction = (
validator,
status,
txHash,
signature,
timestamp: txHashTimestamp
}
}