Add ALM snapshots (#382)
This commit is contained in:
parent
caf2e2b4d3
commit
8c268d6f06
2
alm/.gitignore
vendored
2
alm/.gitignore
vendored
@ -1,5 +1,7 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
src/snapshots/*.json
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
/node_modules
|
/node_modules
|
||||||
/.pnp
|
/.pnp
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"@use-it/interval": "^0.1.3",
|
"@use-it/interval": "^0.1.3",
|
||||||
"customize-cra": "^1.0.0",
|
"customize-cra": "^1.0.0",
|
||||||
"date-fns": "^2.14.0",
|
"date-fns": "^2.14.0",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
"fast-memoize": "^2.5.2",
|
"fast-memoize": "^2.5.2",
|
||||||
"promise-retry": "^2.0.1",
|
"promise-retry": "^2.0.1",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
@ -30,11 +31,12 @@
|
|||||||
"web3-eth-contract": "1.2.7"
|
"web3-eth-contract": "1.2.7"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "./load-env.sh react-app-rewired start",
|
"start": "yarn createSnapshots && ./load-env.sh react-app-rewired start",
|
||||||
"build": "./load-env.sh react-app-rewired build",
|
"build": "yarn createSnapshots && ./load-env.sh react-app-rewired build",
|
||||||
"test": "react-app-rewired test",
|
"test": "react-app-rewired test",
|
||||||
"eject": "react-app-rewired eject",
|
"eject": "react-app-rewired eject",
|
||||||
"lint": "eslint '*/**/*.{js,ts,tsx}' --ignore-path ../.eslintignore"
|
"lint": "eslint '*/**/*.{js,ts,tsx}' --ignore-path ../.eslintignore",
|
||||||
|
"createSnapshots": "node scripts/createSnapshots.js"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": "react-app"
|
"extends": "react-app"
|
||||||
|
118
alm/scripts/createSnapshots.js
Normal file
118
alm/scripts/createSnapshots.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
const { BRIDGE_VALIDATORS_ABI, HOME_AMB_ABI } = require('commons')
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
require('dotenv').config()
|
||||||
|
const Web3 = require('web3')
|
||||||
|
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
const {
|
||||||
|
COMMON_HOME_RPC_URL,
|
||||||
|
COMMON_HOME_BRIDGE_ADDRESS,
|
||||||
|
COMMON_FOREIGN_RPC_URL,
|
||||||
|
COMMON_FOREIGN_BRIDGE_ADDRESS
|
||||||
|
} = process.env
|
||||||
|
|
||||||
|
const generateSnapshot = async (side, url, bridgeAddress) => {
|
||||||
|
const snapshotPath = `../src/snapshots/${side}.json`
|
||||||
|
const snapshotFullPath = path.join(__dirname, snapshotPath)
|
||||||
|
const snapshot = {}
|
||||||
|
|
||||||
|
const web3 = new Web3(new Web3.providers.HttpProvider(url))
|
||||||
|
|
||||||
|
const currentBlockNumber = await web3.eth.getBlockNumber()
|
||||||
|
snapshot.snapshotBlockNumber = currentBlockNumber
|
||||||
|
|
||||||
|
// Save chainId
|
||||||
|
snapshot.chainId = await web3.eth.getChainId()
|
||||||
|
|
||||||
|
const bridgeContract = new web3.eth.Contract(HOME_AMB_ABI, bridgeAddress)
|
||||||
|
|
||||||
|
// Save RequiredBlockConfirmationChanged events
|
||||||
|
let requiredBlockConfirmationChangedEvents = await bridgeContract.getPastEvents('RequiredBlockConfirmationChanged', {
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: currentBlockNumber
|
||||||
|
})
|
||||||
|
|
||||||
|
// In case RequiredBlockConfirmationChanged was not emitted during initialization in early versions of AMB
|
||||||
|
// manually generate an event for this. Example Sokol - Kovan bridge
|
||||||
|
if (requiredBlockConfirmationChangedEvents.length === 0) {
|
||||||
|
const deployedAtBlock = await bridgeContract.methods.deployedAtBlock().call()
|
||||||
|
const blockConfirmations = await bridgeContract.methods.requiredBlockConfirmations().call()
|
||||||
|
|
||||||
|
requiredBlockConfirmationChangedEvents.push({
|
||||||
|
blockNumber: parseInt(deployedAtBlock),
|
||||||
|
returnValues: {
|
||||||
|
requiredBlockConfirmations: blockConfirmations
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshot.RequiredBlockConfirmationChanged = requiredBlockConfirmationChangedEvents.map(e => ({
|
||||||
|
blockNumber: e.blockNumber,
|
||||||
|
returnValues: {
|
||||||
|
requiredBlockConfirmations: e.returnValues.requiredBlockConfirmations
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
const validatorAddress = await bridgeContract.methods.validatorContract().call()
|
||||||
|
const validatorContract = new web3.eth.Contract(BRIDGE_VALIDATORS_ABI, validatorAddress)
|
||||||
|
|
||||||
|
// Save RequiredSignaturesChanged events
|
||||||
|
const RequiredSignaturesChangedEvents = await validatorContract.getPastEvents('RequiredSignaturesChanged', {
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: currentBlockNumber
|
||||||
|
})
|
||||||
|
snapshot.RequiredSignaturesChanged = RequiredSignaturesChangedEvents.map(e => ({
|
||||||
|
blockNumber: e.blockNumber,
|
||||||
|
returnValues: {
|
||||||
|
requiredSignatures: e.returnValues.requiredSignatures
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Save ValidatorAdded events
|
||||||
|
const validatorAddedEvents = await validatorContract.getPastEvents('ValidatorAdded', {
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: currentBlockNumber
|
||||||
|
})
|
||||||
|
|
||||||
|
snapshot.ValidatorAdded = validatorAddedEvents.map(e => ({
|
||||||
|
blockNumber: e.blockNumber,
|
||||||
|
returnValues: {
|
||||||
|
validator: e.returnValues.validator
|
||||||
|
},
|
||||||
|
event: 'ValidatorAdded'
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Save ValidatorRemoved events
|
||||||
|
const validatorRemovedEvents = await validatorContract.getPastEvents('ValidatorRemoved', {
|
||||||
|
fromBlock: 0,
|
||||||
|
toBlock: currentBlockNumber
|
||||||
|
})
|
||||||
|
|
||||||
|
snapshot.ValidatorRemoved = validatorRemovedEvents.map(e => ({
|
||||||
|
blockNumber: e.blockNumber,
|
||||||
|
returnValues: {
|
||||||
|
validator: e.returnValues.validator
|
||||||
|
},
|
||||||
|
event: 'ValidatorRemoved'
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Write snapshot
|
||||||
|
fs.writeFileSync(snapshotFullPath, JSON.stringify(snapshot, null, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
const main = async () => {
|
||||||
|
await Promise.all([
|
||||||
|
generateSnapshot('home', COMMON_HOME_RPC_URL, COMMON_HOME_BRIDGE_ADDRESS),
|
||||||
|
generateSnapshot('foreign', COMMON_FOREIGN_RPC_URL, COMMON_FOREIGN_BRIDGE_ADDRESS)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.then(() => process.exit(0))
|
||||||
|
.catch(error => {
|
||||||
|
console.log('Error while creating snapshots')
|
||||||
|
console.error(error)
|
||||||
|
process.exit(0)
|
||||||
|
})
|
@ -7,10 +7,7 @@ import styled from 'styled-components'
|
|||||||
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
import { ExecutionData } from '../hooks/useMessageConfirmations'
|
||||||
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
||||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||||
|
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
||||||
const Thead = styled.thead`
|
|
||||||
border-bottom: 2px solid #9e9e9e;
|
|
||||||
`
|
|
||||||
|
|
||||||
const StyledExecutionConfirmation = styled.div`
|
const StyledExecutionConfirmation = styled.div`
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
@ -55,12 +52,12 @@ export const ExecutionConfirmation = ({ executionData, isHome }: ExecutionConfir
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{formattedValidator ? formattedValidator : <SimpleLoading />}</td>
|
<td>{formattedValidator ? formattedValidator : <SimpleLoading />}</td>
|
||||||
<td className="text-center">{getExecutionStatusElement(executionData.status)}</td>
|
<StatusTd className="text-center">{getExecutionStatusElement(executionData.status)}</StatusTd>
|
||||||
<td className="text-center">
|
<AgeTd className="text-center">
|
||||||
<ExplorerTxLink href={txExplorerLink} target="_blank">
|
<ExplorerTxLink href={txExplorerLink} target="_blank">
|
||||||
{executionData.timestamp > 0 ? formatTimestamp(executionData.timestamp) : ''}
|
{executionData.timestamp > 0 ? formatTimestamp(executionData.timestamp) : ''}
|
||||||
</ExplorerTxLink>
|
</ExplorerTxLink>
|
||||||
</td>
|
</AgeTd>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -7,10 +7,7 @@ import styled from 'styled-components'
|
|||||||
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
|
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||||
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
||||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||||
|
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
||||||
const Thead = styled.thead`
|
|
||||||
border-bottom: 2px solid #9e9e9e;
|
|
||||||
`
|
|
||||||
|
|
||||||
const RequiredConfirmations = styled.label`
|
const RequiredConfirmations = styled.label`
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
@ -70,14 +67,14 @@ export const ValidatorsConfirmations = ({
|
|||||||
return (
|
return (
|
||||||
<tr key={i}>
|
<tr key={i}>
|
||||||
<td>{windowWidth < 850 ? formatTxHash(validator) : validator}</td>
|
<td>{windowWidth < 850 ? formatTxHash(validator) : validator}</td>
|
||||||
<td className="text-center">{getValidatorStatusElement(displayedStatus)}</td>
|
<StatusTd className="text-center">{getValidatorStatusElement(displayedStatus)}</StatusTd>
|
||||||
<td className="text-center">
|
<AgeTd className="text-center">
|
||||||
<ExplorerTxLink href={explorerLink} target="_blank">
|
<ExplorerTxLink href={explorerLink} target="_blank">
|
||||||
{confirmation && confirmation.timestamp > 0
|
{confirmation && confirmation.timestamp > 0
|
||||||
? formatTimestamp(confirmation.timestamp)
|
? formatTimestamp(confirmation.timestamp)
|
||||||
: elementIfNoTimestamp}
|
: elementIfNoTimestamp}
|
||||||
</ExplorerTxLink>
|
</ExplorerTxLink>
|
||||||
</td>
|
</AgeTd>
|
||||||
</tr>
|
</tr>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
13
alm/src/components/commons/Table.tsx
Normal file
13
alm/src/components/commons/Table.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import styled from 'styled-components'
|
||||||
|
|
||||||
|
export const Thead = styled.thead`
|
||||||
|
border-bottom: 2px solid #9e9e9e;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const StatusTd = styled.td`
|
||||||
|
width: 150px;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const AgeTd = styled.td`
|
||||||
|
width: 180px;
|
||||||
|
`
|
@ -3,6 +3,7 @@ import { TransactionReceipt } from 'web3-eth'
|
|||||||
import { useStateProvider } from '../state/StateProvider'
|
import { useStateProvider } from '../state/StateProvider'
|
||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
import { getRequiredBlockConfirmations } from '../utils/contract'
|
import { getRequiredBlockConfirmations } from '../utils/contract'
|
||||||
|
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
|
|
||||||
export interface UseBlockConfirmationsParams {
|
export interface UseBlockConfirmationsParams {
|
||||||
fromHome: boolean
|
fromHome: boolean
|
||||||
@ -17,17 +18,19 @@ export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmatio
|
|||||||
const callRequireBlockConfirmations = async (
|
const callRequireBlockConfirmations = async (
|
||||||
contract: Contract,
|
contract: Contract,
|
||||||
receipt: TransactionReceipt,
|
receipt: TransactionReceipt,
|
||||||
setResult: Function
|
setResult: Function,
|
||||||
|
snapshotProvider: SnapshotProvider
|
||||||
) => {
|
) => {
|
||||||
const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber)
|
const result = await getRequiredBlockConfirmations(contract, receipt.blockNumber, snapshotProvider)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||||
|
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||||
if (!bridgeContract || !receipt) return
|
if (!bridgeContract || !receipt) return
|
||||||
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations)
|
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations, snapshotProvider)
|
||||||
},
|
},
|
||||||
[home.bridgeContract, foreign.bridgeContract, receipt, fromHome]
|
[home.bridgeContract, foreign.bridgeContract, receipt, fromHome]
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { getWeb3 } from '../utils/web3'
|
import { getChainId, getWeb3 } from '../utils/web3'
|
||||||
|
import { SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
|
|
||||||
export const useNetwork = (url: string) => {
|
export const useNetwork = (url: string, snapshotProvider: SnapshotProvider) => {
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [chainId, setChainId] = useState(0)
|
const [chainId, setChainId] = useState(0)
|
||||||
const web3 = getWeb3(url)
|
const web3 = getWeb3(url)
|
||||||
@ -9,14 +10,14 @@ export const useNetwork = (url: string) => {
|
|||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
const getChainId = async () => {
|
const getWeb3ChainId = async () => {
|
||||||
const id = await web3.eth.getChainId()
|
const id = await getChainId(web3, snapshotProvider)
|
||||||
setChainId(id)
|
setChainId(id)
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
}
|
}
|
||||||
getChainId()
|
getWeb3ChainId()
|
||||||
},
|
},
|
||||||
[web3.eth]
|
[web3, snapshotProvider]
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -5,6 +5,7 @@ import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '..
|
|||||||
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 { TransactionReceipt } from 'web3-eth'
|
||||||
|
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
|
|
||||||
export interface useValidatorContractParams {
|
export interface useValidatorContractParams {
|
||||||
fromHome: boolean
|
fromHome: boolean
|
||||||
@ -28,16 +29,22 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
|||||||
const callRequiredSignatures = async (
|
const callRequiredSignatures = async (
|
||||||
contract: Maybe<Contract>,
|
contract: Maybe<Contract>,
|
||||||
receipt: TransactionReceipt,
|
receipt: TransactionReceipt,
|
||||||
setResult: Function
|
setResult: Function,
|
||||||
|
snapshotProvider: SnapshotProvider
|
||||||
) => {
|
) => {
|
||||||
if (!contract) return
|
if (!contract) return
|
||||||
const result = await getRequiredSignatures(contract, receipt.blockNumber)
|
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
const callValidatorList = async (contract: Maybe<Contract>, receipt: TransactionReceipt, setResult: Function) => {
|
const callValidatorList = async (
|
||||||
|
contract: Maybe<Contract>,
|
||||||
|
receipt: TransactionReceipt,
|
||||||
|
setResult: Function,
|
||||||
|
snapshotProvider: SnapshotProvider
|
||||||
|
) => {
|
||||||
if (!contract) return
|
if (!contract) return
|
||||||
const result = await getValidatorList(contract, receipt.blockNumber)
|
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider)
|
||||||
setResult(result)
|
setResult(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,10 +62,11 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
|||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
if (!receipt) return
|
if (!receipt) return
|
||||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures)
|
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||||
callValidatorList(validatorContract, receipt, setValidatorList)
|
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider)
|
||||||
|
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider)
|
||||||
},
|
},
|
||||||
[validatorContract, receipt]
|
[validatorContract, receipt, fromHome]
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
69
alm/src/services/SnapshotProvider.ts
Normal file
69
alm/src/services/SnapshotProvider.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
const initialValue = {
|
||||||
|
chainId: 0,
|
||||||
|
RequiredBlockConfirmationChanged: [],
|
||||||
|
RequiredSignaturesChanged: [],
|
||||||
|
ValidatorAdded: [],
|
||||||
|
ValidatorRemoved: [],
|
||||||
|
snapshotBlockNumber: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SnapshotEvent {
|
||||||
|
blockNumber: number
|
||||||
|
returnValues: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SnapshotValidatorEvent {
|
||||||
|
blockNumber: number
|
||||||
|
returnValues: any
|
||||||
|
event: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Snapshot {
|
||||||
|
chainId: number
|
||||||
|
RequiredBlockConfirmationChanged: SnapshotEvent[]
|
||||||
|
RequiredSignaturesChanged: SnapshotEvent[]
|
||||||
|
ValidatorAdded: SnapshotValidatorEvent[]
|
||||||
|
ValidatorRemoved: SnapshotValidatorEvent[]
|
||||||
|
snapshotBlockNumber: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SnapshotProvider {
|
||||||
|
private data: Snapshot
|
||||||
|
|
||||||
|
constructor(side: string) {
|
||||||
|
let data = initialValue
|
||||||
|
try {
|
||||||
|
data = require(`../snapshots/${side}.json`)
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Snapshot not found')
|
||||||
|
}
|
||||||
|
this.data = data
|
||||||
|
}
|
||||||
|
|
||||||
|
chainId() {
|
||||||
|
return this.data.chainId
|
||||||
|
}
|
||||||
|
|
||||||
|
snapshotBlockNumber() {
|
||||||
|
return this.data.snapshotBlockNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
requiredBlockConfirmationEvents(toBlock: number) {
|
||||||
|
return this.data.RequiredBlockConfirmationChanged.filter(e => e.blockNumber <= toBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
requiredSignaturesEvents(toBlock: number) {
|
||||||
|
return this.data.RequiredSignaturesChanged.filter(e => e.blockNumber <= toBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
validatorAddedEvents(fromBlock: number) {
|
||||||
|
return this.data.ValidatorAdded.filter(e => e.blockNumber >= fromBlock)
|
||||||
|
}
|
||||||
|
|
||||||
|
validatorRemovedEvents(fromBlock: number) {
|
||||||
|
return this.data.ValidatorRemoved.filter(e => e.blockNumber >= fromBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const homeSnapshotProvider = new SnapshotProvider('home')
|
||||||
|
export const foreignSnapshotProvider = new SnapshotProvider('foreign')
|
0
alm/src/snapshots/.gitkeep
Normal file
0
alm/src/snapshots/.gitkeep
Normal file
@ -11,6 +11,7 @@ import {
|
|||||||
import Web3 from 'web3'
|
import Web3 from 'web3'
|
||||||
import { useBridgeContracts } from '../hooks/useBridgeContracts'
|
import { useBridgeContracts } from '../hooks/useBridgeContracts'
|
||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
|
import { foreignSnapshotProvider, homeSnapshotProvider } from '../services/SnapshotProvider'
|
||||||
|
|
||||||
export interface BaseNetworkParams {
|
export interface BaseNetworkParams {
|
||||||
chainId: number
|
chainId: number
|
||||||
@ -47,8 +48,8 @@ const initialState = {
|
|||||||
const StateContext = createContext<StateContext>(initialState)
|
const StateContext = createContext<StateContext>(initialState)
|
||||||
|
|
||||||
export const StateProvider = ({ children }: { children: ReactNode }) => {
|
export const StateProvider = ({ children }: { children: ReactNode }) => {
|
||||||
const homeNetwork = useNetwork(HOME_RPC_URL)
|
const homeNetwork = useNetwork(HOME_RPC_URL, homeSnapshotProvider)
|
||||||
const foreignNetwork = useNetwork(FOREIGN_RPC_URL)
|
const foreignNetwork = useNetwork(FOREIGN_RPC_URL, foreignSnapshotProvider)
|
||||||
const { homeBridge, foreignBridge } = useBridgeContracts({
|
const { homeBridge, foreignBridge } = useBridgeContracts({
|
||||||
homeWeb3: homeNetwork.web3,
|
homeWeb3: homeNetwork.web3,
|
||||||
foreignWeb3: foreignNetwork.web3
|
foreignWeb3: foreignNetwork.web3
|
||||||
|
@ -1,10 +1,24 @@
|
|||||||
import { Contract } from 'web3-eth-contract'
|
import { Contract } from 'web3-eth-contract'
|
||||||
|
import { EventData } from 'web3-eth-contract'
|
||||||
|
import { SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
|
|
||||||
export const getRequiredBlockConfirmations = async (contract: Contract, blockNumber: number) => {
|
export const getRequiredBlockConfirmations = async (
|
||||||
const events = await contract.getPastEvents('RequiredBlockConfirmationChanged', {
|
contract: Contract,
|
||||||
fromBlock: 0,
|
blockNumber: number,
|
||||||
|
snapshotProvider: SnapshotProvider
|
||||||
|
) => {
|
||||||
|
const eventsFromSnapshot = snapshotProvider.requiredBlockConfirmationEvents(blockNumber)
|
||||||
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
|
|
||||||
|
let contractEvents: EventData[] = []
|
||||||
|
if (blockNumber > snapshotBlockNumber) {
|
||||||
|
contractEvents = await contract.getPastEvents('RequiredBlockConfirmationChanged', {
|
||||||
|
fromBlock: snapshotBlockNumber + 1,
|
||||||
toBlock: blockNumber
|
toBlock: blockNumber
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const events = [...eventsFromSnapshot, ...contractEvents]
|
||||||
|
|
||||||
let blockConfirmations
|
let blockConfirmations
|
||||||
if (events.length > 0) {
|
if (events.length > 0) {
|
||||||
@ -21,11 +35,23 @@ export const getRequiredBlockConfirmations = async (contract: Contract, blockNum
|
|||||||
|
|
||||||
export const getValidatorAddress = (contract: Contract) => contract.methods.validatorContract().call()
|
export const getValidatorAddress = (contract: Contract) => contract.methods.validatorContract().call()
|
||||||
|
|
||||||
export const getRequiredSignatures = async (contract: Contract, blockNumber: number) => {
|
export const getRequiredSignatures = async (
|
||||||
const events = await contract.getPastEvents('RequiredSignaturesChanged', {
|
contract: Contract,
|
||||||
fromBlock: 0,
|
blockNumber: number,
|
||||||
|
snapshotProvider: SnapshotProvider
|
||||||
|
) => {
|
||||||
|
const eventsFromSnapshot = snapshotProvider.requiredSignaturesEvents(blockNumber)
|
||||||
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
|
|
||||||
|
let contractEvents: EventData[] = []
|
||||||
|
if (blockNumber > snapshotBlockNumber) {
|
||||||
|
contractEvents = await contract.getPastEvents('RequiredSignaturesChanged', {
|
||||||
|
fromBlock: snapshotBlockNumber + 1,
|
||||||
toBlock: blockNumber
|
toBlock: blockNumber
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const events = [...eventsFromSnapshot, ...contractEvents]
|
||||||
|
|
||||||
// Use the value form last event before the transaction
|
// Use the value form last event before the transaction
|
||||||
const event = events[events.length - 1]
|
const event = events[events.length - 1]
|
||||||
@ -33,19 +59,26 @@ export const getRequiredSignatures = async (contract: Contract, blockNumber: num
|
|||||||
return parseInt(requiredSignatures)
|
return parseInt(requiredSignatures)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getValidatorList = async (contract: Contract, blockNumber: number) => {
|
export const getValidatorList = async (contract: Contract, blockNumber: number, snapshotProvider: SnapshotProvider) => {
|
||||||
let currentList: string[] = await contract.methods.validatorList().call()
|
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
||||||
const [added, removed] = await Promise.all([
|
const removedEventsFromSnapshot = snapshotProvider.validatorRemovedEvents(blockNumber)
|
||||||
|
const snapshotBlockNumber = snapshotProvider.snapshotBlockNumber()
|
||||||
|
|
||||||
|
const fromBlock = snapshotBlockNumber > blockNumber ? snapshotBlockNumber + 1 : blockNumber
|
||||||
|
const [currentList, added, removed] = await Promise.all([
|
||||||
|
contract.methods.validatorList().call(),
|
||||||
contract.getPastEvents('ValidatorAdded', {
|
contract.getPastEvents('ValidatorAdded', {
|
||||||
fromBlock: blockNumber
|
fromBlock
|
||||||
}),
|
}),
|
||||||
contract.getPastEvents('ValidatorRemoved', {
|
contract.getPastEvents('ValidatorRemoved', {
|
||||||
fromBlock: blockNumber
|
fromBlock
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|
||||||
// Ordered desc
|
// Ordered desc
|
||||||
const orderedEvents = [...added, ...removed].sort(({ blockNumber: prev }, { blockNumber: next }) => next - prev)
|
const orderedEvents = [...addedEventsFromSnapshot, ...added, ...removedEventsFromSnapshot, ...removed].sort(
|
||||||
|
({ blockNumber: prev }, { blockNumber: next }) => next - prev
|
||||||
|
)
|
||||||
|
|
||||||
// Stored as a Set to avoid duplicates
|
// Stored as a Set to avoid duplicates
|
||||||
const validatorList = new Set(currentList)
|
const validatorList = new Set(currentList)
|
||||||
|
@ -5,6 +5,7 @@ import { AbiItem } from 'web3-utils'
|
|||||||
import memoize from 'fast-memoize'
|
import memoize from 'fast-memoize'
|
||||||
import promiseRetry from 'promise-retry'
|
import promiseRetry from 'promise-retry'
|
||||||
import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../abis'
|
import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../abis'
|
||||||
|
import { SnapshotProvider } from '../services/SnapshotProvider'
|
||||||
|
|
||||||
export interface MessageObject {
|
export interface MessageObject {
|
||||||
id: string
|
id: string
|
||||||
@ -61,3 +62,11 @@ export const getBlock = async (web3: Web3, blockNumber: number): Promise<BlockTr
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const getChainId = async (web3: Web3, snapshotProvider: SnapshotProvider) => {
|
||||||
|
let id = snapshotProvider.chainId()
|
||||||
|
if (id === 0) {
|
||||||
|
id = await web3.eth.getChainId()
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
@ -7550,6 +7550,11 @@ dotenv@^7.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c"
|
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c"
|
||||||
integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==
|
integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==
|
||||||
|
|
||||||
|
dotenv@^8.2.0:
|
||||||
|
version "8.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
|
||||||
|
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
|
||||||
|
|
||||||
dotignore@~0.1.2:
|
dotignore@~0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905"
|
resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905"
|
||||||
|
Loading…
Reference in New Issue
Block a user