Helpers for overriding AMB signatures (#640)
This commit is contained in:
parent
5bc562e810
commit
981231fb47
@ -54,7 +54,7 @@ export const ConfirmationsContainer = ({
|
|||||||
home: { name: homeName },
|
home: { name: homeName },
|
||||||
foreign: { name: foreignName }
|
foreign: { name: foreignName }
|
||||||
} = useStateProvider()
|
} = useStateProvider()
|
||||||
const { requiredSignatures, validatorList } = useValidatorContract({ fromHome, receipt })
|
const { requiredSignatures, validatorList } = useValidatorContract(fromHome, receipt ? receipt.blockNumber : 0)
|
||||||
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
|
const { blockConfirmations } = useBlockConfirmations({ fromHome, receipt })
|
||||||
const {
|
const {
|
||||||
confirmations,
|
confirmations,
|
||||||
|
@ -14,6 +14,7 @@ import { useStateProvider } from '../state/StateProvider'
|
|||||||
import { signatureToVRS, packSignatures } from '../utils/signatures'
|
import { signatureToVRS, packSignatures } from '../utils/signatures'
|
||||||
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
|
import { getSuccessExecutionData } from '../utils/getFinalizationEvent'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
import { TransactionReceipt } from 'web3-eth'
|
||||||
|
import { useValidatorContract } from '../hooks/useValidatorContract'
|
||||||
|
|
||||||
const ActionButton = styled.button`
|
const ActionButton = styled.button`
|
||||||
color: var(--button-color);
|
color: var(--button-color);
|
||||||
@ -45,7 +46,75 @@ export const ManualExecutionButton = ({
|
|||||||
const { library, activate, account, active } = useWeb3React()
|
const { library, activate, account, active } = useWeb3React()
|
||||||
const [manualExecution, setManualExecution] = useState(false)
|
const [manualExecution, setManualExecution] = useState(false)
|
||||||
const [allowFailures, setAllowFailures] = 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(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
@ -73,9 +142,9 @@ export const ManualExecutionButton = ({
|
|||||||
return
|
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 messageId = messageData.slice(0, 66)
|
||||||
const bridge = foreign.bridgeContract
|
const bridge = foreign.bridgeContract
|
||||||
const executeMethod =
|
const executeMethod =
|
||||||
@ -140,19 +209,20 @@ export const ManualExecutionButton = ({
|
|||||||
foreign.bridgeContract,
|
foreign.bridgeContract,
|
||||||
setError,
|
setError,
|
||||||
messageData,
|
messageData,
|
||||||
signatureCollected,
|
|
||||||
setExecutionData,
|
setExecutionData,
|
||||||
setPendingExecution,
|
setPendingExecution,
|
||||||
safeExecutionAvailable,
|
safeExecutionAvailable,
|
||||||
allowFailures
|
allowFailures,
|
||||||
|
foreign.web3,
|
||||||
|
validSignatures
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="is-center">
|
<div className="is-center">
|
||||||
<ActionButton disabled={notReady} className="button outline" onClick={() => setManualExecution(true)}>
|
<ActionButton disabled={!ready} className="button outline" onClick={() => setManualExecution(true)}>
|
||||||
Execute
|
{title}
|
||||||
</ActionButton>
|
</ActionButton>
|
||||||
</div>
|
</div>
|
||||||
{safeExecutionAvailable && (
|
{safeExecutionAvailable && (
|
||||||
|
@ -4,19 +4,13 @@ import Web3 from 'web3'
|
|||||||
import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '../utils/contract'
|
import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '../utils/contract'
|
||||||
import { BRIDGE_VALIDATORS_ABI } from '../abis'
|
import { BRIDGE_VALIDATORS_ABI } from '../abis'
|
||||||
import { useStateProvider } from '../state/StateProvider'
|
import { useStateProvider } from '../state/StateProvider'
|
||||||
import { TransactionReceipt } from 'web3-eth'
|
|
||||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
||||||
|
|
||||||
export interface useValidatorContractParams {
|
export const useValidatorContract = (isHome: boolean, blockNumber: number | 'latest') => {
|
||||||
fromHome: boolean
|
|
||||||
receipt: Maybe<TransactionReceipt>
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useValidatorContract = ({ receipt, fromHome }: useValidatorContractParams) => {
|
|
||||||
const [validatorContract, setValidatorContract] = useState<Maybe<Contract>>(null)
|
const [validatorContract, setValidatorContract] = useState<Maybe<Contract>>(null)
|
||||||
const [requiredSignatures, setRequiredSignatures] = useState(0)
|
const [requiredSignatures, setRequiredSignatures] = useState(0)
|
||||||
const [validatorList, setValidatorList] = useState([])
|
const [validatorList, setValidatorList] = useState<string[]>([])
|
||||||
|
|
||||||
const { home, foreign } = useStateProvider()
|
const { home, foreign } = useStateProvider()
|
||||||
|
|
||||||
@ -29,34 +23,34 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
|||||||
|
|
||||||
const callRequiredSignatures = async (
|
const callRequiredSignatures = async (
|
||||||
contract: Maybe<Contract>,
|
contract: Maybe<Contract>,
|
||||||
receipt: TransactionReceipt,
|
blockNumber: number | 'latest',
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
snapshotProvider: SnapshotProvider,
|
snapshotProvider: SnapshotProvider,
|
||||||
web3: Web3,
|
web3: Web3,
|
||||||
api: string
|
api: string
|
||||||
) => {
|
) => {
|
||||||
if (!contract) return
|
if (!contract) return
|
||||||
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
const result = await getRequiredSignatures(contract, blockNumber, snapshotProvider, web3, api)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
const callValidatorList = async (
|
const callValidatorList = async (
|
||||||
contract: Maybe<Contract>,
|
contract: Maybe<Contract>,
|
||||||
receipt: TransactionReceipt,
|
blockNumber: number | 'latest',
|
||||||
setResult: Function,
|
setResult: Function,
|
||||||
snapshotProvider: SnapshotProvider,
|
snapshotProvider: SnapshotProvider,
|
||||||
web3: Web3,
|
web3: Web3,
|
||||||
api: string
|
api: string
|
||||||
) => {
|
) => {
|
||||||
if (!contract) return
|
if (!contract) return
|
||||||
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
const result = await getValidatorList(contract, blockNumber, snapshotProvider, web3, api)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
const web3 = fromHome ? home.web3 : foreign.web3
|
const web3 = isHome ? home.web3 : foreign.web3
|
||||||
const api = fromHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
const api = isHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
||||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
const bridgeContract = isHome ? home.bridgeContract : foreign.bridgeContract
|
||||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
const snapshotProvider = isHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
@ -68,11 +62,11 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
|||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!web3 || !receipt) return
|
if (!web3 || !blockNumber) return
|
||||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider, web3, api)
|
callRequiredSignatures(validatorContract, blockNumber, setRequiredSignatures, snapshotProvider, web3, api)
|
||||||
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider, web3, api)
|
callValidatorList(validatorContract, blockNumber, setValidatorList, snapshotProvider, web3, api)
|
||||||
},
|
},
|
||||||
[validatorContract, receipt, web3, snapshotProvider, api]
|
[validatorContract, blockNumber, web3, snapshotProvider, api]
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -52,11 +52,15 @@ export const getValidatorAddress = (contract: Contract) => contract.methods.vali
|
|||||||
|
|
||||||
export const getRequiredSignatures = async (
|
export const getRequiredSignatures = async (
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
blockNumber: number,
|
blockNumber: number | 'latest',
|
||||||
snapshotProvider: SnapshotProvider,
|
snapshotProvider: SnapshotProvider,
|
||||||
web3: Web3 | null = null,
|
web3: Web3 | null = null,
|
||||||
api: string = ''
|
api: string = ''
|
||||||
) => {
|
) => {
|
||||||
|
if (blockNumber === 'latest') {
|
||||||
|
return contract.methods.requiredSignatures().call()
|
||||||
|
}
|
||||||
|
|
||||||
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
|
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
|
||||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
|
|
||||||
@ -78,11 +82,15 @@ export const getRequiredSignatures = async (
|
|||||||
|
|
||||||
export const getValidatorList = async (
|
export const getValidatorList = async (
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
blockNumber: number,
|
blockNumber: number | 'latest',
|
||||||
snapshotProvider: SnapshotProvider,
|
snapshotProvider: SnapshotProvider,
|
||||||
web3: Web3 | null = null,
|
web3: Web3 | null = null,
|
||||||
api: string = ''
|
api: string = ''
|
||||||
) => {
|
) => {
|
||||||
|
if (blockNumber === 'latest') {
|
||||||
|
return contract.methods.validatorList().call()
|
||||||
|
}
|
||||||
|
|
||||||
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
||||||
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
|
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
|
||||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"confirm:information-request": "./scripts/start-worker.sh confirmRelay information-request-watcher",
|
"confirm:information-request": "./scripts/start-worker.sh confirmRelay information-request-watcher",
|
||||||
"manager:shutdown": "./scripts/start-worker.sh shutdownManager shutdown-manager",
|
"manager:shutdown": "./scripts/start-worker.sh shutdownManager shutdown-manager",
|
||||||
"helper:interestFether": "node ./scripts/interestFetcher.js",
|
"helper:interestFether": "node ./scripts/interestFetcher.js",
|
||||||
|
"helper:signPendingMessages": "node ./scripts/signPendingMessages.js",
|
||||||
"mev:watcher:collected-signatures": "./scripts/start-worker.sh mevWatcher mev-collected-signatures-watcher",
|
"mev:watcher:collected-signatures": "./scripts/start-worker.sh mevWatcher mev-collected-signatures-watcher",
|
||||||
"mev:sender:foreign": "./scripts/start-worker.sh mevSender foreign-mev-sender",
|
"mev:sender:foreign": "./scripts/start-worker.sh mevSender foreign-mev-sender",
|
||||||
"dev": "concurrently -n 'watcher:signature-request,watcher:collected-signatures,watcher:affirmation-request,watcher:transfer, sender:home,sender:foreign' -c 'red,green,yellow,blue,magenta,cyan' 'yarn watcher:signature-request' 'yarn watcher:collected-signatures' 'yarn watcher:affirmation-request' 'yarn watcher:transfer' 'yarn sender:home' 'yarn sender:foreign'",
|
"dev": "concurrently -n 'watcher:signature-request,watcher:collected-signatures,watcher:affirmation-request,watcher:transfer, sender:home,sender:foreign' -c 'red,green,yellow,blue,magenta,cyan' 'yarn watcher:signature-request' 'yarn watcher:collected-signatures' 'yarn watcher:affirmation-request' 'yarn watcher:transfer' 'yarn sender:home' 'yarn sender:foreign'",
|
||||||
|
76
oracle/scripts/signPendingMessages.js
Normal file
76
oracle/scripts/signPendingMessages.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
require('dotenv').config()
|
||||||
|
|
||||||
|
const {
|
||||||
|
COMMON_HOME_BRIDGE_ADDRESS,
|
||||||
|
COMMON_FOREIGN_BRIDGE_ADDRESS,
|
||||||
|
ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY,
|
||||||
|
ORACLE_HOME_START_BLOCK,
|
||||||
|
ORACLE_HOME_END_BLOCK
|
||||||
|
} = process.env
|
||||||
|
|
||||||
|
const fs = require('fs')
|
||||||
|
const promiseLimit = require('promise-limit')
|
||||||
|
|
||||||
|
const { web3Home, web3Foreign } = require('../src/services/web3')
|
||||||
|
const { HOME_AMB_ABI, FOREIGN_AMB_ABI, getPastEvents, parseAMBMessage } = require('../../commons')
|
||||||
|
const { setLogger } = require('../src/services/injectedLogger')
|
||||||
|
|
||||||
|
const mockLogger = { debug: () => {}, info: () => {}, error: () => {}, child: () => mockLogger }
|
||||||
|
setLogger(mockLogger)
|
||||||
|
|
||||||
|
const limit = promiseLimit(50)
|
||||||
|
|
||||||
|
const output = process.argv[2]
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const wallet = web3Home.eth.accounts.wallet.add(ORACLE_VALIDATOR_ADDRESS_PRIVATE_KEY)
|
||||||
|
const homeBridge = new web3Home.eth.Contract(HOME_AMB_ABI, COMMON_HOME_BRIDGE_ADDRESS)
|
||||||
|
const foreignBridge = new web3Foreign.eth.Contract(FOREIGN_AMB_ABI, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
|
const fromBlock = parseInt(ORACLE_HOME_START_BLOCK, 10) || 0
|
||||||
|
let toBlock = parseInt(ORACLE_HOME_END_BLOCK, 10)
|
||||||
|
if (!toBlock) {
|
||||||
|
toBlock = await web3Home.eth.getBlockNumber()
|
||||||
|
}
|
||||||
|
console.log(`Getting CollectedSignatures events from block ${fromBlock} to block ${toBlock}`)
|
||||||
|
const events = await getPastEvents(homeBridge, { event: 'CollectedSignatures', fromBlock, toBlock })
|
||||||
|
console.log(`Found ${events.length} CollectedSignatures events`)
|
||||||
|
console.log('Getting messages')
|
||||||
|
let messages = await Promise.all(
|
||||||
|
events.map((event, i) => () => getMessage(homeBridge, foreignBridge, event, i)).map(limit)
|
||||||
|
)
|
||||||
|
messages = messages.filter(x => x)
|
||||||
|
console.log(`Filtered ${messages.length} pending messages`)
|
||||||
|
const result = {}
|
||||||
|
messages.forEach(msg => {
|
||||||
|
result[msg.msgHash] = wallet.sign(msg.message).signature
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('Writing results')
|
||||||
|
if (output === '-') {
|
||||||
|
console.log(JSON.stringify(result))
|
||||||
|
} else {
|
||||||
|
fs.writeFileSync(output, JSON.stringify(result))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMessage(homeBridge, foreignBridge, event, i) {
|
||||||
|
if (i % 50 === 0) {
|
||||||
|
console.log(`Processing event #${i}`)
|
||||||
|
}
|
||||||
|
const msgHash = event.returnValues.messageHash
|
||||||
|
const message = await homeBridge.methods.message(msgHash).call()
|
||||||
|
|
||||||
|
const { messageId } = parseAMBMessage(message)
|
||||||
|
const alreadyProcessed = await foreignBridge.methods.relayedMessages(messageId).call()
|
||||||
|
|
||||||
|
if (alreadyProcessed) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
msgHash,
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user