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.
|
||||
|
||||
src/snapshots/*.json
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
|
@ -17,6 +17,7 @@
|
||||
"@use-it/interval": "^0.1.3",
|
||||
"customize-cra": "^1.0.0",
|
||||
"date-fns": "^2.14.0",
|
||||
"dotenv": "^8.2.0",
|
||||
"fast-memoize": "^2.5.2",
|
||||
"promise-retry": "^2.0.1",
|
||||
"react": "^16.13.1",
|
||||
@ -30,11 +31,12 @@
|
||||
"web3-eth-contract": "1.2.7"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "./load-env.sh react-app-rewired start",
|
||||
"build": "./load-env.sh react-app-rewired build",
|
||||
"start": "yarn createSnapshots && ./load-env.sh react-app-rewired start",
|
||||
"build": "yarn createSnapshots && ./load-env.sh react-app-rewired build",
|
||||
"test": "react-app-rewired test",
|
||||
"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": {
|
||||
"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 { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||
|
||||
const Thead = styled.thead`
|
||||
border-bottom: 2px solid #9e9e9e;
|
||||
`
|
||||
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
||||
|
||||
const StyledExecutionConfirmation = styled.div`
|
||||
margin-top: 30px;
|
||||
@ -55,12 +52,12 @@ export const ExecutionConfirmation = ({ executionData, isHome }: ExecutionConfir
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{formattedValidator ? formattedValidator : <SimpleLoading />}</td>
|
||||
<td className="text-center">{getExecutionStatusElement(executionData.status)}</td>
|
||||
<td className="text-center">
|
||||
<StatusTd className="text-center">{getExecutionStatusElement(executionData.status)}</StatusTd>
|
||||
<AgeTd className="text-center">
|
||||
<ExplorerTxLink href={txExplorerLink} target="_blank">
|
||||
{executionData.timestamp > 0 ? formatTimestamp(executionData.timestamp) : ''}
|
||||
</ExplorerTxLink>
|
||||
</td>
|
||||
</AgeTd>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -7,10 +7,7 @@ import styled from 'styled-components'
|
||||
import { ConfirmationParam } from '../hooks/useMessageConfirmations'
|
||||
import { GreyLabel, RedLabel, SuccessLabel } from './commons/Labels'
|
||||
import { ExplorerTxLink } from './commons/ExplorerTxLink'
|
||||
|
||||
const Thead = styled.thead`
|
||||
border-bottom: 2px solid #9e9e9e;
|
||||
`
|
||||
import { Thead, AgeTd, StatusTd } from './commons/Table'
|
||||
|
||||
const RequiredConfirmations = styled.label`
|
||||
font-size: 14px;
|
||||
@ -70,14 +67,14 @@ export const ValidatorsConfirmations = ({
|
||||
return (
|
||||
<tr key={i}>
|
||||
<td>{windowWidth < 850 ? formatTxHash(validator) : validator}</td>
|
||||
<td className="text-center">{getValidatorStatusElement(displayedStatus)}</td>
|
||||
<td className="text-center">
|
||||
<StatusTd className="text-center">{getValidatorStatusElement(displayedStatus)}</StatusTd>
|
||||
<AgeTd className="text-center">
|
||||
<ExplorerTxLink href={explorerLink} target="_blank">
|
||||
{confirmation && confirmation.timestamp > 0
|
||||
? formatTimestamp(confirmation.timestamp)
|
||||
: elementIfNoTimestamp}
|
||||
</ExplorerTxLink>
|
||||
</td>
|
||||
</AgeTd>
|
||||
</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 { Contract } from 'web3-eth-contract'
|
||||
import { getRequiredBlockConfirmations } from '../utils/contract'
|
||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||
|
||||
export interface UseBlockConfirmationsParams {
|
||||
fromHome: boolean
|
||||
@ -17,17 +18,19 @@ export const useBlockConfirmations = ({ receipt, fromHome }: UseBlockConfirmatio
|
||||
const callRequireBlockConfirmations = async (
|
||||
contract: Contract,
|
||||
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)
|
||||
}
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
const bridgeContract = fromHome ? home.bridgeContract : foreign.bridgeContract
|
||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||
if (!bridgeContract || !receipt) return
|
||||
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations)
|
||||
callRequireBlockConfirmations(bridgeContract, receipt, setBlockConfirmations, snapshotProvider)
|
||||
},
|
||||
[home.bridgeContract, foreign.bridgeContract, receipt, fromHome]
|
||||
)
|
||||
|
@ -1,7 +1,8 @@
|
||||
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 [chainId, setChainId] = useState(0)
|
||||
const web3 = getWeb3(url)
|
||||
@ -9,14 +10,14 @@ export const useNetwork = (url: string) => {
|
||||
useEffect(
|
||||
() => {
|
||||
setLoading(true)
|
||||
const getChainId = async () => {
|
||||
const id = await web3.eth.getChainId()
|
||||
const getWeb3ChainId = async () => {
|
||||
const id = await getChainId(web3, snapshotProvider)
|
||||
setChainId(id)
|
||||
setLoading(false)
|
||||
}
|
||||
getChainId()
|
||||
getWeb3ChainId()
|
||||
},
|
||||
[web3.eth]
|
||||
[web3, snapshotProvider]
|
||||
)
|
||||
|
||||
return {
|
||||
|
@ -5,6 +5,7 @@ import { getRequiredSignatures, getValidatorAddress, getValidatorList } from '..
|
||||
import { BRIDGE_VALIDATORS_ABI } from '../abis'
|
||||
import { useStateProvider } from '../state/StateProvider'
|
||||
import { TransactionReceipt } from 'web3-eth'
|
||||
import { foreignSnapshotProvider, homeSnapshotProvider, SnapshotProvider } from '../services/SnapshotProvider'
|
||||
|
||||
export interface useValidatorContractParams {
|
||||
fromHome: boolean
|
||||
@ -28,16 +29,22 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
||||
const callRequiredSignatures = async (
|
||||
contract: Maybe<Contract>,
|
||||
receipt: TransactionReceipt,
|
||||
setResult: Function
|
||||
setResult: Function,
|
||||
snapshotProvider: SnapshotProvider
|
||||
) => {
|
||||
if (!contract) return
|
||||
const result = await getRequiredSignatures(contract, receipt.blockNumber)
|
||||
const result = await getRequiredSignatures(contract, receipt.blockNumber, snapshotProvider)
|
||||
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
|
||||
const result = await getValidatorList(contract, receipt.blockNumber)
|
||||
const result = await getValidatorList(contract, receipt.blockNumber, snapshotProvider)
|
||||
setResult(result)
|
||||
}
|
||||
|
||||
@ -55,10 +62,11 @@ export const useValidatorContract = ({ receipt, fromHome }: useValidatorContract
|
||||
useEffect(
|
||||
() => {
|
||||
if (!receipt) return
|
||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures)
|
||||
callValidatorList(validatorContract, receipt, setValidatorList)
|
||||
const snapshotProvider = fromHome ? homeSnapshotProvider : foreignSnapshotProvider
|
||||
callRequiredSignatures(validatorContract, receipt, setRequiredSignatures, snapshotProvider)
|
||||
callValidatorList(validatorContract, receipt, setValidatorList, snapshotProvider)
|
||||
},
|
||||
[validatorContract, receipt]
|
||||
[validatorContract, receipt, fromHome]
|
||||
)
|
||||
|
||||
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 { useBridgeContracts } from '../hooks/useBridgeContracts'
|
||||
import { Contract } from 'web3-eth-contract'
|
||||
import { foreignSnapshotProvider, homeSnapshotProvider } from '../services/SnapshotProvider'
|
||||
|
||||
export interface BaseNetworkParams {
|
||||
chainId: number
|
||||
@ -47,8 +48,8 @@ const initialState = {
|
||||
const StateContext = createContext<StateContext>(initialState)
|
||||
|
||||
export const StateProvider = ({ children }: { children: ReactNode }) => {
|
||||
const homeNetwork = useNetwork(HOME_RPC_URL)
|
||||
const foreignNetwork = useNetwork(FOREIGN_RPC_URL)
|
||||
const homeNetwork = useNetwork(HOME_RPC_URL, homeSnapshotProvider)
|
||||
const foreignNetwork = useNetwork(FOREIGN_RPC_URL, foreignSnapshotProvider)
|
||||
const { homeBridge, foreignBridge } = useBridgeContracts({
|
||||
homeWeb3: homeNetwork.web3,
|
||||
foreignWeb3: foreignNetwork.web3
|
||||
|
@ -1,10 +1,24 @@
|
||||
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) => {
|
||||
const events = await contract.getPastEvents('RequiredBlockConfirmationChanged', {
|
||||
fromBlock: 0,
|
||||
toBlock: blockNumber
|
||||
})
|
||||
export const getRequiredBlockConfirmations = async (
|
||||
contract: Contract,
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
const events = [...eventsFromSnapshot, ...contractEvents]
|
||||
|
||||
let blockConfirmations
|
||||
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 getRequiredSignatures = async (contract: Contract, blockNumber: number) => {
|
||||
const events = await contract.getPastEvents('RequiredSignaturesChanged', {
|
||||
fromBlock: 0,
|
||||
toBlock: blockNumber
|
||||
})
|
||||
export const getRequiredSignatures = async (
|
||||
contract: Contract,
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
const events = [...eventsFromSnapshot, ...contractEvents]
|
||||
|
||||
// Use the value form last event before the transaction
|
||||
const event = events[events.length - 1]
|
||||
@ -33,19 +59,26 @@ export const getRequiredSignatures = async (contract: Contract, blockNumber: num
|
||||
return parseInt(requiredSignatures)
|
||||
}
|
||||
|
||||
export const getValidatorList = async (contract: Contract, blockNumber: number) => {
|
||||
let currentList: string[] = await contract.methods.validatorList().call()
|
||||
const [added, removed] = await Promise.all([
|
||||
export const getValidatorList = async (contract: Contract, blockNumber: number, snapshotProvider: SnapshotProvider) => {
|
||||
const addedEventsFromSnapshot = snapshotProvider.validatorAddedEvents(blockNumber)
|
||||
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', {
|
||||
fromBlock: blockNumber
|
||||
fromBlock
|
||||
}),
|
||||
contract.getPastEvents('ValidatorRemoved', {
|
||||
fromBlock: blockNumber
|
||||
fromBlock
|
||||
})
|
||||
])
|
||||
|
||||
// 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
|
||||
const validatorList = new Set(currentList)
|
||||
|
@ -5,6 +5,7 @@ import { AbiItem } from 'web3-utils'
|
||||
import memoize from 'fast-memoize'
|
||||
import promiseRetry from 'promise-retry'
|
||||
import { HOME_AMB_ABI, FOREIGN_AMB_ABI } from '../abis'
|
||||
import { SnapshotProvider } from '../services/SnapshotProvider'
|
||||
|
||||
export interface MessageObject {
|
||||
id: string
|
||||
@ -61,3 +62,11 @@ export const getBlock = async (web3: Web3, blockNumber: number): Promise<BlockTr
|
||||
}
|
||||
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"
|
||||
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:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905"
|
||||
|
Loading…
Reference in New Issue
Block a user