Skip to content

Commit

Permalink
ALM: show manually added signatures (#653)
Browse files Browse the repository at this point in the history
  • Loading branch information
k1rill-fedoseev authored Apr 29, 2022
1 parent 4af882b commit 16f3e9a
Show file tree
Hide file tree
Showing 13 changed files with 291 additions and 208 deletions.
32 changes: 23 additions & 9 deletions alm/src/components/ConfirmationsContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react'
import React, { useEffect, useState } from 'react'
import { TransactionReceipt } from 'web3-eth'
import { useMessageConfirmations } from '../hooks/useMessageConfirmations'
import { MessageObject } from '../utils/web3'
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 { SimpleLoading } from './commons/Loading'
import { ValidatorsConfirmations } from './ValidatorsConfirmations'
Expand Down Expand Up @@ -54,7 +54,9 @@ export const ConfirmationsContainer = ({
home: { name: homeName },
foreign: { name: foreignName }
} = 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 {
confirmations,
Expand All @@ -71,11 +73,21 @@ export const ConfirmationsContainer = ({
fromHome,
homeStartBlock,
foreignStartBlock,
requiredSignatures,
validatorList,
requiredSignatures: src.requiredSignatures,
validatorList: src.validatorList,
targetValidatorList: dst.validatorList,
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 parseDescription = () => {
Expand Down Expand Up @@ -114,20 +126,22 @@ export const ConfirmationsContainer = ({
</MultiLine>
</StatusDescription>
<ValidatorsConfirmations
confirmations={confirmations}
requiredSignatures={requiredSignatures}
validatorList={validatorList}
confirmations={fromHome ? confirmations.filter(c => dst.validatorList.includes(c.validator)) : confirmations}
requiredSignatures={dst.requiredSignatures}
validatorList={dst.validatorList}
waitingBlocksResolved={waitingBlocksResolved}
/>
{signatureCollected && (
<ExecutionConfirmation
message={message}
executionData={executionData}
isHome={!fromHome}
signatureCollected={signatureCollected}
confirmations={confirmations}
setExecutionData={setExecutionData}
executionEventsFetched={executionEventsFetched}
setPendingExecution={setPendingExecution}
dstRequiredSignatures={dst.requiredSignatures}
dstValidatorList={dst.validatorList}
/>
)}
</StyledConfirmationContainer>
Expand Down
16 changes: 11 additions & 5 deletions alm/src/components/ExecutionConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 { SimpleLoading } from './commons/Loading'
import styled from 'styled-components'
import { ExecutionData } from '../hooks/useMessageConfirmations'
import { ConfirmationParam, ExecutionData } from '../hooks/useMessageConfirmations'
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { Thead, AgeTd, StatusTd } from './commons/Table'
Expand All @@ -22,20 +22,24 @@ export interface ExecutionConfirmationParams {
message: MessageObject
executionData: ExecutionData
setExecutionData: Function
signatureCollected: boolean | string[]
confirmations: ConfirmationParam[]
isHome: boolean
executionEventsFetched: boolean
setPendingExecution: Function
dstRequiredSignatures: number
dstValidatorList: string[]
}

export const ExecutionConfirmation = ({
message,
executionData,
setExecutionData,
signatureCollected,
confirmations,
isHome,
executionEventsFetched,
setPendingExecution
setPendingExecution,
dstRequiredSignatures,
dstValidatorList
}: ExecutionConfirmationParams) => {
const { foreign } = useStateProvider()
const [safeExecutionAvailable, setSafeExecutionAvailable] = useState(false)
Expand Down Expand Up @@ -152,9 +156,11 @@ export const ExecutionConfirmation = ({
safeExecutionAvailable={safeExecutionAvailable}
messageData={message.data}
setExecutionData={setExecutionData}
signatureCollected={signatureCollected as string[]}
confirmations={confirmations}
setPendingExecution={setPendingExecution}
setError={setError}
requiredSignatures={dstRequiredSignatures}
validatorList={dstValidatorList}
/>
</td>
)}
Expand Down
57 changes: 20 additions & 37 deletions alm/src/components/ManualExecutionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useStateProvider } from '../state/StateProvider'
import { signatureToVRS, packSignatures } from '../utils/signatures'
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
import { TransactionReceipt } from 'web3-eth'
import { useValidatorContract } from '../hooks/useValidatorContract'
import { ConfirmationParam } from '../hooks/useMessageConfirmations'

const ActionButton = styled.button`
color: var(--button-color);
Expand All @@ -31,18 +31,22 @@ interface ManualExecutionButtonParams {
safeExecutionAvailable: boolean
messageData: string
setExecutionData: Function
signatureCollected: string[]
confirmations: ConfirmationParam[]
setPendingExecution: Function
setError: Function
requiredSignatures: number
validatorList: string[]
}

export const ManualExecutionButton = ({
safeExecutionAvailable,
messageData,
setExecutionData,
signatureCollected,
confirmations,
setPendingExecution,
setError
setError,
requiredSignatures,
validatorList
}: ManualExecutionButtonParams) => {
const { foreign } = useStateProvider()
const { library, activate, account, active } = useWeb3React()
Expand All @@ -52,55 +56,34 @@ export const ManualExecutionButton = ({
const [title, setTitle] = useState('Loading')
const [validSignatures, setValidSignatures] = useState<string[]>([])

const { requiredSignatures, validatorList } = useValidatorContract(false, 'latest')

useEffect(
() => {
if (
!foreign.bridgeContract ||
!foreign.web3 ||
!signatureCollected ||
!signatureCollected.length ||
!confirmations ||
!confirmations.length ||
!requiredSignatures ||
!validatorList ||
!validatorList.length
)
return

const signatures = []
const remainingValidators = Object.fromEntries(validatorList.map(validator => [validator, true]))
for (let i = 0; i < signatureCollected.length && signatures.length < requiredSignatures; i++) {
const { v, r, s } = signatureToVRS(signatureCollected[i])
for (let i = 0; i < confirmations.length && signatures.length < requiredSignatures; i++) {
const sig = confirmations[i].signature
if (!sig) {
continue
}
const { v, r, s } = signatureToVRS(sig)
const signer = foreign.web3.eth.accounts.recover(messageData, `0x${v}`, `0x${r}`, `0x${s}`)
if (validatorList.includes(signer)) {
delete remainingValidators[signer]
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]}`)
}
signatures.push(sig)
}
}

if (signatures.length >= requiredSignatures) {
setValidSignatures(signatures)
setValidSignatures(signatures.slice(0, requiredSignatures))
setTitle('Execute')
setReady(true)
} else {
Expand All @@ -110,11 +93,11 @@ export const ManualExecutionButton = ({
[
foreign.bridgeContract,
foreign.web3,
signatureCollected,
validatorList,
requiredSignatures,
messageData,
setValidSignatures
setValidSignatures,
confirmations
]
)

Expand Down
44 changes: 24 additions & 20 deletions alm/src/components/ValidatorsConfirmations.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { formatTimestamp, formatTxHash, getExplorerTxUrl } from '../utils/networks'
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 styled from 'styled-components'
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
Expand Down Expand Up @@ -31,7 +31,9 @@ export const ValidatorsConfirmations = ({
const getValidatorStatusElement = (validatorStatus = '') => {
switch (validatorStatus) {
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:
return <RedLabel>{validatorStatus}</RedLabel>
case VALIDATOR_CONFIRMATION_STATUS.PENDING:
Expand All @@ -58,26 +60,28 @@ export const ValidatorsConfirmations = ({
</tr>
</Thead>
<tbody>
{validatorList.map((validator, i) => {
const filteredConfirmation = confirmations.filter(c => c.validator === validator)
const confirmation = filteredConfirmation.length > 0 ? filteredConfirmation[0] : null
const displayedStatus = confirmation && confirmation.status ? confirmation.status : ''
const explorerLink = confirmation && confirmation.txHash ? getExplorerTxUrl(confirmation.txHash, true) : ''
const elementIfNoTimestamp =
displayedStatus !== VALIDATOR_CONFIRMATION_STATUS.WAITING &&
displayedStatus !== VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED ? (
(displayedStatus === VALIDATOR_CONFIRMATION_STATUS.UNDEFINED || displayedStatus === '') &&
waitingBlocksResolved ? (
SEARCHING_TX
) : (
<SimpleLoading />
)
) : (
''
)
{confirmations.map((confirmation, i) => {
const displayedStatus = confirmation.status
const explorerLink = getExplorerTxUrl(confirmation.txHash, true)
let elementIfNoTimestamp: any = <SimpleLoading />
switch (displayedStatus) {
case '':
case VALIDATOR_CONFIRMATION_STATUS.UNDEFINED:
if (waitingBlocksResolved) {
elementIfNoTimestamp = SEARCHING_TX
}
break
case VALIDATOR_CONFIRMATION_STATUS.WAITING:
case VALIDATOR_CONFIRMATION_STATUS.NOT_REQUIRED:
elementIfNoTimestamp = ''
break
case VALIDATOR_CONFIRMATION_STATUS.MANUAL:
elementIfNoTimestamp = RECENT_AGE
break
}
return (
<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>
<AgeTd className="text-center">
{confirmation && confirmation.timestamp > 0 ? (
Expand Down
4 changes: 4 additions & 0 deletions alm/src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,18 @@ export const CONFIRMATIONS_STATUS = {

export const VALIDATOR_CONFIRMATION_STATUS = {
SUCCESS: 'Confirmed',
MANUAL: 'Manual',
EXECUTION_SUCCESS: 'Executed',
FAILED: 'Failed',
FAILED_VALID: 'Failed valid',
PENDING: 'Pending',
WAITING: 'Waiting',
NOT_REQUIRED: 'Not required',
UNDEFINED: 'UNDEFINED'
}

export const RECENT_AGE = 'Recent'

export const SEARCHING_TX = 'Searching Transaction...'

export const INCORRECT_CHAIN_ERROR = `Incorrect chain chosen. Switch to ${FOREIGN_NETWORK_NAME} in the wallet.`
Expand Down
Loading

0 comments on commit 16f3e9a

Please sign in to comment.