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 },
|
||||
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,
|
||||
|
@ -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);
|
||||
@ -45,7 +46,75 @@ export const ManualExecutionButton = ({
|
||||
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(
|
||||
() => {
|
||||
@ -73,9 +142,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 =
|
||||
@ -140,19 +209,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 && (
|
||||
|
@ -4,19 +4,13 @@ import Web3 from 'web3'
|
||||
import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '../utils/contract'
|
||||
import { BRIDGE_VALIDATORS_ABI } from '../abis'
|
||||
import { useStateProvider } from '../state/StateProvider'
|
||||
import { TransactionReceipt } from 'web3-eth'
|
||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||
import { FOREIGN_EXPLORER_API, HOME_EXPLORER_API } from '../config/constants'
|
||||
|
||||
export interface useValidatorContractParams {
|
||||
fromHome: boolean
|
||||
receipt: Maybe<TransactionReceipt>
|
||||
}
|
||||
|
||||
export const useValidatorContract = ({ receipt, fromHome }: useValidatorContractParams) => {
|
||||
export const useValidatorContract = (isHome: boolean, blockNumber: number | 'latest') => {
|
||||
const [validatorContract, setValidatorContract] = useState<Maybe<Contract>>(null)
|
||||
const [requiredSignatures, setRequiredSignatures] = useState(0)
|
||||
const [validatorList, setValidatorList] = useState([])
|
||||
const [validatorList, setValidatorList] = useState<string[]>([])
|
||||
|
||||
const { home, foreign } = useStateProvider()
|
||||
|
||||
@ -29,34 +23,34 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
||||
|
||||
const callRequiredSignatures = async (
|
||||
contract: Maybe<Contract>,
|
||||
receipt: TransactionReceipt,
|
||||
blockNumber: number | 'latest',
|
||||
setResult: Function,
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3,
|
||||
api: string
|
||||
) => {
|
||||
if (!contract) return
|
||||
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
||||
const result = await getRequiredSignatures(contract, blockNumber, snapshotProvider, web3, api)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
const callValidatorList = async (
|
||||
contract: Maybe<Contract>,
|
||||
receipt: TransactionReceipt,
|
||||
blockNumber: number | 'latest',
|
||||
setResult: Function,
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3,
|
||||
api: string
|
||||
) => {
|
||||
if (!contract) return
|
||||
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider, web3, api)
|
||||
const result = await getValidatorList(contract, blockNumber, snapshotProvider, web3, api)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
const web3 = fromHome ? home.web3 : foreign.web3
|
||||
const api = fromHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||
const web3 = isHome ? home.web3 : foreign.web3
|
||||
const api = isHome ? HOME_EXPLORER_API : FOREIGN_EXPLORER_API
|
||||
const bridgeContract = isHome ? home.bridgeContract : foreign.bridgeContract
|
||||
const snapshotProvider = isHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
@ -68,11 +62,11 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (!web3 || !receipt) return
|
||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider, web3, api)
|
||||
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider, web3, api)
|
||||
if (!web3 || !blockNumber) return
|
||||
callRequiredSignatures(validatorContract, blockNumber, setRequiredSignatures, snapshotProvider, web3, api)
|
||||
callValidatorList(validatorContract, blockNumber, setValidatorList, snapshotProvider, web3, api)
|
||||
},
|
||||
[validatorContract, receipt, web3, snapshotProvider, api]
|
||||
[validatorContract, blockNumber, web3, snapshotProvider, api]
|
||||
)
|
||||
|
||||
return {
|
||||
|
@ -52,11 +52,15 @@ export const getValidatorAddress = (contract: Contract) => contract.methods.vali
|
||||
|
||||
export const getRequiredSignatures = async (
|
||||
contract: Contract,
|
||||
blockNumber: number,
|
||||
blockNumber: number | 'latest',
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3 | null = null,
|
||||
api: string = ''
|
||||
) => {
|
||||
if (blockNumber === 'latest') {
|
||||
return contract.methods.requiredSignatures().call()
|
||||
}
|
||||
|
||||
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
|
||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||
|
||||
@ -78,11 +82,15 @@ export const getRequiredSignatures = async (
|
||||
|
||||
export const getValidatorList = async (
|
||||
contract: Contract,
|
||||
blockNumber: number,
|
||||
blockNumber: number | 'latest',
|
||||
snapshotProvider: SnapshotProvider,
|
||||
web3: Web3 | null = null,
|
||||
api: string = ''
|
||||
) => {
|
||||
if (blockNumber === 'latest') {
|
||||
return contract.methods.validatorList().call()
|
||||
}
|
||||
|
||||
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
||||
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
|
||||
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||
|
@ -19,6 +19,7 @@
|
||||
"confirm:information-request": "./scripts/start-worker.sh confirmRelay information-request-watcher",
|
||||
"manager:shutdown": "./scripts/start-worker.sh shutdownManager shutdown-manager",
|
||||
"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: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'",
|
||||
|
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