Skip to content

Commit

Permalink
Merge the develop branch to the master branch, preparation to v3.5.0
Browse files Browse the repository at this point in the history
This merge contains the following set of changes:
  * [Oracle, Improvement] Helpers for overriding AMB signatures (#640)
  * [Oracle, Improvement] Support manual signatures in erc to native mode (#646)
  * [ALM, Improvement] ALM: Do not show unneeded failed confirmations (#641)
  * [ALM, Improvement] ALM: warning for auto-relayed messages (#644)
  * [ALM, Fix] ALM: reorder warnings
  • Loading branch information
akolotov authored Mar 18, 2022
2 parents 5bc562e + 735aa75 commit dbaf7fe
Show file tree
Hide file tree
Showing 21 changed files with 445 additions and 138 deletions.
4 changes: 2 additions & 2 deletions alm/src/components/ConfirmationsContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const ConfirmationsContainer = ({
home: { name: homeName },
foreign: { name: foreignName }
} = useStateProvider()
const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
const { requiredSignatures, validatorList } = useValidatorContract(fromHome, receipt ? receipt.blockNumber : 0)
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
const {
confirmations,
Expand Down Expand Up @@ -121,7 +121,7 @@ export const ConfirmationsContainer = ({
/>
{signatureCollected && (
<ExecutionConfirmation
messageData={message.data}
message={message}
executionData={executionData}
isHome={!fromHome}
signatureCollected={signatureCollected}
Expand Down
34 changes: 30 additions & 4 deletions alm/src/components/ExecutionConfirmation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@ import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { Thead, AgeTd, StatusTd } from './commons/Table'
import { ManualExecutionButton } from './ManualExecutionButton'
import { useStateProvider } from '../state/StateProvider'
import { matchesRule, MessageObject, WarnRule } from '../utils/web3'
import { WarningAlert } from './commons/WarningAlert'
import { ErrorAlert } from './commons/ErrorAlert'

const StyledExecutionConfirmation = styled.div`
margin-top: 30px;
`

export interface ExecutionConfirmationParams {
messageData: string
message: MessageObject
executionData: ExecutionData
setExecutionData: Function
signatureCollected: boolean | string[]
Expand All @@ -26,7 +29,7 @@ export interface ExecutionConfirmationParams {
}

export const ExecutionConfirmation = ({
messageData,
message,
executionData,
setExecutionData,
signatureCollected,
Expand All @@ -36,6 +39,8 @@ export const ExecutionConfirmation = ({
}: ExecutionConfirmationParams) => {
const { foreign } = useStateProvider()
const [safeExecutionAvailable, setSafeExecutionAvailable] = useState(false)
const [error, setError] = useState('')
const [warning, setWarning] = useState('')
const availableManualExecution =
!isHome &&
(executionData.status === VALIDATOR_CONFIRMATION_STATUS.WAITING ||
Expand Down Expand Up @@ -67,9 +72,27 @@ export const ExecutionConfirmation = ({
[availableManualExecution, foreign.bridgeContract]
)

useEffect(
() => {
if (!message.data || !executionData || !availableManualExecution) return

try {
const fileName = 'warnRules'
const rules: WarnRule[] = require(`../snapshots/${fileName}.json`)
for (let rule of rules) {
if (matchesRule(rule, message)) {
setWarning(rule.message)
return
}
}
} catch (e) {}
},
[availableManualExecution, executionData, message, message.data, setWarning]
)

const getExecutionStatusElement = (validatorStatus = '') => {
switch (validatorStatus) {
case VALIDATOR_CONFIRMATION_STATUS.SUCCESS:
case VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS:
return <SuccessLabel>{validatorStatus}</SuccessLabel>
case VALIDATOR_CONFIRMATION_STATUS.FAILED:
return <RedLabel>{validatorStatus}</RedLabel>
Expand All @@ -87,6 +110,8 @@ export const ExecutionConfirmation = ({

return (
<StyledExecutionConfirmation>
{error && <ErrorAlert onClick={() => setError('')} error={error} />}
{warning && <WarningAlert onClick={() => setWarning('')} error={warning} />}
<table>
<Thead>
<tr>
Expand Down Expand Up @@ -125,10 +150,11 @@ export const ExecutionConfirmation = ({
<td>
<ManualExecutionButton
safeExecutionAvailable={safeExecutionAvailable}
messageData={messageData}
messageData={message.data}
setExecutionData={setExecutionData}
signatureCollected={signatureCollected as string[]}
setPendingExecution={setPendingExecution}
setError={setError}
/>
</td>
)}
Expand Down
4 changes: 1 addition & 3 deletions alm/src/components/MainPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { TransactionReceipt } from 'web3-eth'
import { InfoAlert } from './commons/InfoAlert'
import { ExplorerTxLink } from './commons/ExplorerTxLink'
import { FOREIGN_NETWORK_NAME, HOME_NETWORK_NAME } from '../config/constants'
import { ErrorAlert } from './commons/ErrorAlert'

const StyledMainPage = styled.div`
text-align: center;
Expand Down Expand Up @@ -52,7 +51,7 @@ export interface FormSubmitParams {

export const MainPage = () => {
const history = useHistory()
const { home, foreign, error, setError } = useStateProvider()
const { home, foreign } = useStateProvider()
const [networkName, setNetworkName] = useState('')
const [receipt, setReceipt] = useState<Maybe<TransactionReceipt>>(null)
const [showInfoAlert, setShowInfoAlert] = useState(false)
Expand Down Expand Up @@ -132,7 +131,6 @@ export const MainPage = () => {
</AlertP>
</InfoAlert>
)}
{error && <ErrorAlert onClick={() => setError('')} error={error} />}
<Route exact path={['/']} children={<Form onSubmit={onFormSubmit} />} />
<Route
path={['/:chainId/:txHash/:messageIdParam', '/:chainId/:txHash']}
Expand Down
90 changes: 81 additions & 9 deletions alm/src/components/ManualExecutionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +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'

const ActionButton = styled.button`
color: var(--button-color);
Expand All @@ -32,20 +33,90 @@ interface ManualExecutionButtonParams {
setExecutionData: Function
signatureCollected: string[]
setPendingExecution: Function
setError: Function
}

export const ManualExecutionButton = ({
safeExecutionAvailable,
messageData,
setExecutionData,
signatureCollected,
setPendingExecution
setPendingExecution,
setError
}: ManualExecutionButtonParams) => {
const { foreign, setError } = useStateProvider()
const { foreign } = useStateProvider()
const { library, activate, account, active } = useWeb3React()
const [manualExecution, setManualExecution] = useState(false)
const [allowFailures, setAllowFailures] = useState(false)
const notReady = !foreign.bridgeContract || !signatureCollected || !signatureCollected.length
const [ready, setReady] = useState(false)
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 ||
!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])
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]}`)
}
}
}

if (signatures.length >= requiredSignatures) {
setValidSignatures(signatures)
setTitle('Execute')
setReady(true)
} else {
setTitle('Unavailable')
}
},
[
foreign.bridgeContract,
foreign.web3,
signatureCollected,
validatorList,
requiredSignatures,
messageData,
setValidSignatures
]
)

useEffect(
() => {
Expand Down Expand Up @@ -73,9 +144,9 @@ export const ManualExecutionButton = ({
return
}

if (!library || !foreign.bridgeContract || !signatureCollected || !signatureCollected.length) return
if (!library || !foreign.bridgeContract || !foreign.web3 || !validSignatures || !validSignatures.length) return

const signatures = packSignatures(signatureCollected.map(signatureToVRS))
const signatures = packSignatures(validSignatures.map(signatureToVRS))
const messageId = messageData.slice(0, 66)
const bridge = foreign.bridgeContract
const executeMethod =
Expand Down Expand Up @@ -140,19 +211,20 @@ export const ManualExecutionButton = ({
foreign.bridgeContract,
setError,
messageData,
signatureCollected,
setExecutionData,
setPendingExecution,
safeExecutionAvailable,
allowFailures
allowFailures,
foreign.web3,
validSignatures
]
)

return (
<div>
<div className="is-center">
<ActionButton disabled={notReady} className="button outline" onClick={() => setManualExecution(true)}>
Execute
<ActionButton disabled={!ready} className="button outline" onClick={() => setManualExecution(true)}>
{title}
</ActionButton>
</div>
{safeExecutionAvailable && (
Expand Down
2 changes: 1 addition & 1 deletion alm/src/components/ValidatorsConfirmations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const ValidatorsConfirmations = ({
</tbody>
</table>
<RequiredConfirmations>
{requiredSignatures} of {validatorList.length} confirmations required
At least <strong>{requiredSignatures}</strong> of <strong>{validatorList.length}</strong> confirmations required
</RequiredConfirmations>
</div>
)
Expand Down
2 changes: 1 addition & 1 deletion alm/src/components/commons/ErrorAlert.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const ErrorAlert = ({ onClick, error }: { onClick: () => void; error: str
}
return (
<div className="row is-center">
<StyledErrorAlert className="col-10 is-vertical-align row">
<StyledErrorAlert className="col-12 is-vertical-align row">
<InfoIcon color="var(--failed-color)" />
<TextContainer className="col-10">
{text}
Expand Down
34 changes: 34 additions & 0 deletions alm/src/components/commons/WarningAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react'
import styled from 'styled-components'
import { InfoIcon } from './InfoIcon'
import { CloseIcon } from './CloseIcon'

const StyledErrorAlert = styled.div`
border: 1px solid var(--warning-color);
border-radius: 4px;
margin-bottom: 20px;
padding-top: 10px;
`

const CloseIconContainer = styled.div`
cursor: pointer;
`

const TextContainer = styled.div`
white-space: pre-wrap;
flex-direction: column;
`

export const WarningAlert = ({ onClick, error }: { onClick: () => void; error: string }) => {
return (
<div className="row is-center">
<StyledErrorAlert className="col-12 is-vertical-align row">
<InfoIcon color="var(--warning-color)" />
<TextContainer className="col-10">{error}</TextContainer>
<CloseIconContainer className="col-1 is-vertical-align is-center" onClick={onClick}>
<CloseIcon color="var(--warning-color)" />
</CloseIconContainer>
</StyledErrorAlert>
</div>
)
}
3 changes: 2 additions & 1 deletion alm/src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export const CONFIRMATIONS_STATUS = {
}

export const VALIDATOR_CONFIRMATION_STATUS = {
SUCCESS: 'Success',
SUCCESS: 'Confirmed',
EXECUTION_SUCCESS: 'Executed',
FAILED: 'Failed',
PENDING: 'Pending',
WAITING: 'Waiting',
Expand Down
5 changes: 4 additions & 1 deletion alm/src/hooks/useMessageConfirmations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,10 @@ export const useMessageConfirmations = ({
// Sets the message status based in the collected information
useEffect(
() => {
if (executionData.status === VALIDATOR_CONFIRMATION_STATUS.SUCCESS && existsConfirmation(confirmations)) {
if (
executionData.status === VALIDATOR_CONFIRMATION_STATUS.EXECUTION_SUCCESS &&
existsConfirmation(confirmations)
) {
const newStatus = executionData.executionResult
? CONFIRMATIONS_STATUS.SUCCESS
: CONFIRMATIONS_STATUS.SUCCESS_MESSAGE_FAILED
Expand Down
Loading

0 comments on commit dbaf7fe

Please sign in to comment.