diff --git a/.env.dist b/.env.dist index 5c31c5e43..0aa6aa726 100644 --- a/.env.dist +++ b/.env.dist @@ -3,5 +3,8 @@ SENTRY_DSN=https://xxxxx@o365379.ingest.sentry.io/yyyyyyy SENTRY_ORG=nodefactory SENTRY_PROJECT=chainguardian SENTRY_AUTH_TOKEN=xxx -DOCKER_LIGHTHOUSE_IMAGE=sigp/lighthouse:v1.1.1 -DOCKER_TEKU_IMAGE=consensys/teku:21.3.2 +DOCKER_LIGHTHOUSE_IMAGE=sigp/lighthouse:v1.3.0 +DOCKER_TEKU_IMAGE=consensys/teku:21.5 +DOCKER_PRYSM_IMAGE=gcr.io/prysmaticlabs/prysm/beacon-chain:v1.3.11 +DOCKER_PRYSM_VALIDATOR_IMAGE=gcr.io/prysmaticlabs/prysm/validator:v1.3.11 +DOCKER_NIMBUS_IMAGE=statusim/nimbus-eth2:amd64-v1.4.0 diff --git a/.gitignore b/.gitignore index 26a9520de..c9d4c14ea 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,5 @@ coverage *.log package-lock.json *.db -/eth2_testnet/genesis.ssz .tmp *.sqlite* diff --git a/integration/nimbus-keystore.json b/integration/nimbus-keystore.json new file mode 100644 index 000000000..8c5d9edc2 --- /dev/null +++ b/integration/nimbus-keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"394aa7bf7b8543bec9328678fabbb82b1d88b651a1629992c596011c87035ee0"},"message":""},"checksum":{"function":"sha256","params":{},"message":"4e1093d856e9cfa77b2ef37e49d96e248aa2b88be51c542a1a5c295f97eb30c2"},"cipher":{"function":"aes-128-ctr","params":{"iv":"8fa9958ef656695f12e3999d869d291e"},"message":"5869a4b6f5bab27676d6212737afbdedf5823ecb522ea88a72322c50a2f4c392"}},"description":"","pubkey":"8309a5281dd43297a3eccc1e70553831ec4dbf6a0b5b38fc910b49fb4eecf37075c90269443fd5fc6b8cad701e3eec53","path":"m/12381/3600/29/0/0","uuid":"97ee5497-09d8-489b-af81-e060358f5d5c","version":4} \ No newline at end of file diff --git a/integration/nimbus.ts b/integration/nimbus.ts new file mode 100644 index 000000000..64d09f76a --- /dev/null +++ b/integration/nimbus.ts @@ -0,0 +1,38 @@ +import assert from "assert"; +import {restValidation} from "./restValidation"; +import {config} from "@chainsafe/lodestar-config/lib/presets/mainnet"; +import {CgNimbusEth2Api} from "../src/renderer/services/eth2/client/module"; +import {SecretKey} from "@chainsafe/bls"; +import {Keystore} from "@chainsafe/bls-keystore"; + +import keystore from "./nimbus-keystore.json"; +const keystorePassword = "4E015C5AF6C9610B0230DBC4FD9714B786F24A28414E49C52D85950E1ED23AD8"; + +(async function (): Promise { + const {proposer, attestation} = await restValidation({ + baseUrl: "http://localhost:5052", + getValidatorPrivateKey: async () => + SecretKey.fromBytes(await Keystore.fromObject(keystore).decrypt(keystorePassword)), + limit: 5, + config, + ApiClient: CgNimbusEth2Api, + }); + + console.log("\n\n\n"); + let isFailed = false; + try { + assert.equal(proposer.proposed, proposer.delegated); + console.info(`Successfully proposed all ${proposer.delegated} blocks`); + } catch (e) { + console.error("Proposals", e.message); + isFailed = true; + } + try { + assert.equal(attestation.attestations, attestation.delegated); + console.info(`Successfully provide all ${proposer.delegated} attestations`); + } catch (e) { + console.error("Attestations", e.message); + isFailed = true; + } + process.exit(Number(isFailed)); +})(); diff --git a/integration/prysm.ts b/integration/prysm.ts new file mode 100644 index 000000000..d59771c60 --- /dev/null +++ b/integration/prysm.ts @@ -0,0 +1,33 @@ +import {getInteropKey} from "../src/renderer/services/validator/interop_keys"; +import assert from "assert"; +import {restValidation} from "./restValidation"; +import {config} from "@chainsafe/lodestar-config/lib/presets/mainnet"; +import {CgPrysmEth2Api} from "../src/renderer/services/eth2/client/module"; + +(async function (): Promise { + const {proposer, attestation} = await restValidation({ + baseUrl: "http://localhost:5050", + getValidatorPrivateKey: async () => getInteropKey(7), + limit: 5, + config, + ApiClient: CgPrysmEth2Api, + }); + + console.log("\n\n\n"); + let isFailed = false; + try { + assert.equal(proposer.proposed, proposer.delegated); + console.info(`Successfully proposed all ${proposer.delegated} blocks`); + } catch (e) { + console.error("Proposals", e.message); + isFailed = true; + } + try { + assert.equal(attestation.attestations, attestation.delegated); + console.info(`Successfully provide all ${proposer.delegated} attestations`); + } catch (e) { + console.error("Attestations", e.message); + isFailed = true; + } + process.exit(Number(isFailed)); +})(); diff --git a/lighthouse-testnet.yml b/lighthouse-testnet.yml index f2a456536..1317330f3 100644 --- a/lighthouse-testnet.yml +++ b/lighthouse-testnet.yml @@ -5,7 +5,7 @@ version: "3.0" services: beacon_node: - image: "${DOCKER_LIGHTHOUSE_IMAGE:-sigp/lighthouse:v1.1.1}" + image: "${DOCKER_LIGHTHOUSE_IMAGE:-sigp/lighthouse:v1.3.0}" container_name: "eth2_testnet_beacon_lighthouse" volumes: - ./testnet/lighthouse/data:/root/testnet @@ -16,7 +16,7 @@ services: command: sh /root/scripts/start-beacon-node.sh second_beacon_node: - image: "${DOCKER_LIGHTHOUSE_IMAGE:-sigp/lighthouse:v1.1.1}" + image: "${DOCKER_LIGHTHOUSE_IMAGE:-sigp/lighthouse:v1.3.0}" container_name: "eth2_testnet_second_beacon_lighthouse" volumes: - ./testnet/lighthouse/data:/root/testnet @@ -30,7 +30,7 @@ services: command: sh /root/scripts/start-second-beacon-node.sh validator_client: - image: "${DOCKER_LIGHTHOUSE_IMAGE:-sigp/lighthouse:v1.1.1}" + image: "${DOCKER_LIGHTHOUSE_IMAGE:-sigp/lighthouse:v1.3.0}" container_name: "eth2_testnet_validator_lighthouse" network_mode: "host" volumes: diff --git a/nimbus-testnet.yml b/nimbus-testnet.yml new file mode 100644 index 000000000..aec04a61f --- /dev/null +++ b/nimbus-testnet.yml @@ -0,0 +1,13 @@ +version: "3.4" + +services: + beacon_node: + image: "${DOCKER_NIMBUS_IMAGE:-statusim/nimbus-eth2:amd64-v1.4.0}" + container_name: "eth2_testnet_beacon_nimbus" + entrypoint: "/bin/bash" + ports: + - "9190:9190" + - "5052:5052" + volumes: + - ./testnet/nimbus:/tmp/scripts + command: /tmp/scripts/run_local_testnet.sh --reuse-existing-data-dir --data-dir /tmp/scripts --disable-vc --nodes 1 \ No newline at end of file diff --git a/package.json b/package.json index 57ddcfa77..6e3b3947e 100644 --- a/package.json +++ b/package.json @@ -55,11 +55,22 @@ "storybook": "start-storybook -p 6006", "codecov": "codecov", "script": "node -r ts-node/register", - "generate:validators": "yarn run script scripts/generate_interop_validators.ts", - "testnet:dev": "./testnet/lighthouse/reset_genesis_time.sh && docker-compose -f lighthouse-testnet.yml up", "build-storybook": "build-storybook", + "generate:validators": "yarn run script scripts/generate_interop_validators.ts", + "testnet:lighthouse": "docker-compose -f lighthouse-testnet.yml up", + "testnet:lighthouse:down": "docker-compose -f lighthouse-testnet.yml down", + "testnet:lighthouse:reset-genesis": "cd ./testnet/lighthouse && ./reset_genesis_time.sh", + "testnet:teku": "docker-compose -f teku-testnet.yml up", + "testnet:teku:down": "docker-compose -f teku-testnet.yml down", + "testnet:nimbus": "docker-compose -f nimbus-testnet.yml up", + "testnet:nimbus:down": "docker-compose -f nimbus-testnet.yml down", + "testnet:prysm": "docker-compose -f prysm-testnet.yml up", + "testnet:prysm:down": "docker-compose -f prysm-testnet.yml down", + "testnet:all:down": "yarn run testnet:lighthouse:down && yarn run testnet:teku:down && yarn run testnet:nimbus:down && yarn run testnet:prysm:down", "integration:lighthouse": "yarn run script integration/lighthouse.ts", - "integration:teku": "yarn run script integration/teku.ts.ts" + "integration:teku": "yarn run script integration/teku.ts", + "integration:prysm": "yarn run script integration/prysm.ts", + "integration:nimbus": "yarn run script integration/nimbus.ts" }, "jest": { "transform": { diff --git a/prysm-testnet.yml b/prysm-testnet.yml new file mode 100644 index 000000000..4ac63ce87 --- /dev/null +++ b/prysm-testnet.yml @@ -0,0 +1,41 @@ +version: '3.6' + +services: + prysm_beacon: + image: "${DOCKER_PRYSM_IMAGE:-gcr.io/prysmaticlabs/prysm/beacon-chain:v1.3.11}" + container_name: "eth2_testnet_prysm_beacon" + volumes: + - ./testnet/prysm/data:/data + ports: + - '5050:5050' + - '4000:4000' + - '13000:13000' + - '12000:12000' + network_mode: "host" + env_file: ./testnet/prysm/vars.env + command: > + --accept-terms-of-use + --disable-monitoring + --force-clear-db + --datadir=/data + --grpc-gateway-port=5050 + --min-sync-peers=0 + --bootstrap-node= + --disable-sync + --interop-genesis-state /data/genesis.ssz + --interop-eth1data-votes + + prysm_validator: + image: "${DOCKER_PRYSM_VALIDATOR_IMAGE:-gcr.io/prysmaticlabs/prysm/validator:v1.3.11}" + container_name: "eth2_testnet_prysm_validator" + volumes: + - ./testnet/prysm/data:/data + network_mode: "host" + env_file: ./testnet/prysm/vars.env + command: > + --accept-terms-of-use + --disable-monitoring + --force-clear-db + --datadir=/data + --interop-start-index=0 + --interop-num-validators=15 \ No newline at end of file diff --git a/src/renderer/components/ConfigureBeaconNode/ConfigureBeaconNode.tsx b/src/renderer/components/ConfigureBeaconNode/ConfigureBeaconNode.tsx index 9eb7e3d64..72cc61895 100644 --- a/src/renderer/components/ConfigureBeaconNode/ConfigureBeaconNode.tsx +++ b/src/renderer/components/ConfigureBeaconNode/ConfigureBeaconNode.tsx @@ -27,17 +27,17 @@ interface IConfigureBNProps { clientName?: string; } -const clients = ["teku", "lighthouse"]; +const clients = ["nimbus", "teku", "lighthouse"]; export const ConfigureBeaconNode: React.FunctionComponent = (props: IConfigureBNProps) => { // TODO: refactor to use list from src/renderer/services/eth2/networks/index.ts const [networkIndex, setNetworkIndex] = useState(0); const [clientIndex, setClientIndex] = useState(0); - const defaults = getDefaultsForClient(props.clientName); + const defaults = getDefaultsForClient(clients[clientIndex]); const [images, setImages] = useState([]); useEffect(() => { - getAvailableClientReleases(clients[clientIndex]).then((imageList) => { + getAvailableClientReleases(clients[clientIndex], defaults.beacon.versionPrefix).then((imageList) => { setImages(imageList); setImageIndex(imageList.length - 1); }); @@ -139,6 +139,7 @@ export const ConfigureBeaconNode: React.FunctionComponent = ( onChange={setImageIndex} options={images} verifiedIndex={images.length - 1} + className='beacon-config' /> diff --git a/src/renderer/components/Dropdown/Dropdown.tsx b/src/renderer/components/Dropdown/Dropdown.tsx index 8c25b5a29..0076a99dc 100644 --- a/src/renderer/components/Dropdown/Dropdown.tsx +++ b/src/renderer/components/Dropdown/Dropdown.tsx @@ -8,6 +8,7 @@ export interface IDropdownProps { label?: string; onChange?: (selected: number) => void; verifiedIndex?: number; + className?: string; } export const Dropdown: React.FunctionComponent = ({ @@ -16,6 +17,7 @@ export const Dropdown: React.FunctionComponent = ({ label, onChange, verifiedIndex, + className = "", }) => { const [visible, setVisible] = useState("none"); options = Array.isArray(options) ? {...options} : options; @@ -50,7 +52,7 @@ export const Dropdown: React.FunctionComponent = ({ } return ( -
+
{label &&

{label}

}
hide()} className='dropdown-screen'>
diff --git a/src/renderer/components/Dropdown/dropdown.scss b/src/renderer/components/Dropdown/dropdown.scss index 1c9997160..8a37665ce 100644 --- a/src/renderer/components/Dropdown/dropdown.scss +++ b/src/renderer/components/Dropdown/dropdown.scss @@ -5,14 +5,14 @@ // z-index: -100; } .dropdown-container{ -display: flex; -flex-direction: column; -font-family: "Palanquin", sans-serif; -font-weight: 400; -font-size: 18px; -line-height: 28px; -color: $neutral-100; -z-index: 100; + display: flex; + flex-direction: column; + font-family: "Palanquin", sans-serif; + font-weight: 400; + font-size: 18px; + line-height: 28px; + color: $neutral-100; + z-index: 100; } .dropdown-selected{ @@ -57,9 +57,9 @@ z-index: 100; .dropdown-item{ // display: none; border-bottom: 1px solid $neutral-600; - margin-bottom: 8px; padding: 13px 24px; - margin: 0px; + margin: 0; + &.none{ display: none; } @@ -86,4 +86,14 @@ z-index: 100; .dropdown-item:hover{ background-color: $neutral-600; cursor: pointer; +} + +.beacon-config { + .dropdown-selected { + width: 550px; + } + + .dropdown-items { + width: 630px; + } } \ No newline at end of file diff --git a/src/renderer/ducks/beacon/sagas.ts b/src/renderer/ducks/beacon/sagas.ts index 81865cddb..e7666b57b 100644 --- a/src/renderer/ducks/beacon/sagas.ts +++ b/src/renderer/ducks/beacon/sagas.ts @@ -47,7 +47,7 @@ import {ValidatorStatus} from "../../constants/validatorStatus"; import {cgLogger, createLogger, getBeaconLogfileFromURL, mainLogger} from "../../../main/logger"; import {setInitialBeacons} from "../settings/actions"; import {DockerRegistry} from "../../services/docker/docker-registry"; -import {CgEth2ApiClient, readBeaconChainNetwork} from "../../services/eth2/client/module"; +import {CgEth2ApiClient, getBeaconNodeEth2ApiClient, readBeaconChainNetwork} from "../../services/eth2/client/module"; import {getClientParams} from "../../services/docker/getClientParams"; export function* pullDockerImage( @@ -98,21 +98,20 @@ function* startLocalBeaconSaga({ if (pullSuccess) { yield put( addBeacon(`http://localhost:${rpcPort}`, network, { - id: (yield call( - BeaconChain.startBeaconChain, - SupportedNetworks.LOCALHOST, - getClientParams(ports, { + id: (yield call(BeaconChain.startBeaconChain, SupportedNetworks.LOCALHOST, { + ...getClientParams({ network, libp2pPort, discoveryPort, rpcPort, client, - memory, eth1Url, chainDataDir, - image, }), - )).getParams().name, + memory, + ports, + image, + })).getParams().name, network, chainDataDir, eth1Url, @@ -239,10 +238,12 @@ export function* watchOnHead( (INetworkConfig | null) & Beacon & SyncingStatus & + typeof CgEth2ApiClient & boolean > { const config = yield retry(30, 1000, readBeaconChainNetwork, url); - const client = new CgEth2ApiClient(config?.eth2Config || mainnetConfig, url); + const ApiClient: typeof CgEth2ApiClient = yield call(getBeaconNodeEth2ApiClient, url); + const client = new ApiClient(config?.eth2Config || mainnetConfig, url); const eventStream = client.events.getEventStream([BeaconEventType.HEAD]); const beacon = yield select(getBeaconByKey, {key: url}); diff --git a/src/renderer/ducks/store.ts b/src/renderer/ducks/store.ts index eba34f55b..f8190d49e 100644 --- a/src/renderer/ducks/store.ts +++ b/src/renderer/ducks/store.ts @@ -31,4 +31,6 @@ if (typeof module.hot !== "undefined") { ); } +(window as any).store = store; + export default store; diff --git a/src/renderer/services/api/http/httpClient.ts b/src/renderer/services/api/http/httpClient.ts index 72e59ae22..299214331 100644 --- a/src/renderer/services/api/http/httpClient.ts +++ b/src/renderer/services/api/http/httpClient.ts @@ -15,6 +15,10 @@ export class HttpClient { }); } + public getBaseUrl(): string { + return this.client.defaults.baseURL; + } + /** * Method that handles GET * @param url endpoint url diff --git a/src/renderer/services/docker/chain.ts b/src/renderer/services/docker/chain.ts index b69f84f00..2215ff109 100644 --- a/src/renderer/services/docker/chain.ts +++ b/src/renderer/services/docker/chain.ts @@ -9,7 +9,7 @@ import {cgLogger} from "../../../main/logger"; export class BeaconChain extends Container { public static async startBeaconChain( network: SupportedNetworks, - params: Partial> = {}, + params: Partial> = {}, waitUntilReady = false, ): Promise { const imageName = BeaconChain.getContainerName(network); diff --git a/src/renderer/services/docker/getClientParams.ts b/src/renderer/services/docker/getClientParams.ts index 42cda6782..85d775a4f 100644 --- a/src/renderer/services/docker/getClientParams.ts +++ b/src/renderer/services/docker/getClientParams.ts @@ -1,12 +1,52 @@ -import {DockerPort, IDockerRunParams} from "./type"; +import {IDockerRunParams} from "./type"; import {IConfigureBNSubmitOptions} from "../../components/ConfigureBeaconNode/ConfigureBeaconNode"; -export const getClientParams = ( - ports: DockerPort[], - {network, libp2pPort, discoveryPort, rpcPort, eth1Url, chainDataDir, client, memory}: IConfigureBNSubmitOptions, -): Partial> => { +export const getClientParams = ({ + network, + libp2pPort, + discoveryPort, + rpcPort, + eth1Url, + chainDataDir, + client, +}: Omit): Partial> => { const eth1QueryLimit = 200; switch (client) { + case "nimbus": { + const cmd = [ + `--network=${network}`, + `--data-dir=/data`, + `--tcp-port=${libp2pPort}`, + `--udp-port=${discoveryPort}`, + `--rest`, + `--rest-address=0.0.0.0`, + `--rest-port=${rpcPort}`, + // TODO: add CORS for dev + `--web3-url=${eth1Url}`, + ].join(" "); + console.log(cmd, eth1Url); + return { + cmd, + volume: `${chainDataDir}:/data`, + }; + } + case "prysm": { + const networkEnvironment = network !== "mainet" ? " --" + network : ""; + const cmd = [ + `--accept-terms-of-use`, + `--datadir=/data${networkEnvironment}`, + `--p2p-tcp-port=${libp2pPort}`, + `--p2p-udp-port=${discoveryPort}`, + `--grpc-gateway-host=0.0.0.0`, + `--grpc-gateway-port=${rpcPort}`, + `--http-web3provider=${eth1Url}`, + // --fallback-web3provider= --fallback-web3provider= + ].join(" "); + return { + cmd, + volume: `${chainDataDir}:/data`, + }; + } case "teku": { const cors = process.env.NODE_ENV !== "production" ? " --rest-api-cors-origins=http://localhost:2003 " : " "; @@ -21,9 +61,7 @@ export const getClientParams = ( `--log-destination=CONSOLE`, ].join(" "); return { - ports, cmd, - memory, volume: `${chainDataDir}:/opt/teku/.local/share/teku/beacon`, }; } @@ -39,9 +77,7 @@ export const getClientParams = ( `--eth1-blocks-per-log-query ${eth1QueryLimit}`, ].join(" "); return { - ports, cmd, - memory, volume: `${chainDataDir}:/root/.lighthouse`, }; } diff --git a/src/renderer/services/eth2/client/defaults.ts b/src/renderer/services/eth2/client/defaults.ts index 020bf8bc7..d920859fc 100644 --- a/src/renderer/services/eth2/client/defaults.ts +++ b/src/renderer/services/eth2/client/defaults.ts @@ -6,6 +6,7 @@ export interface IDefaultBeaconNodeConfig { owner: string; repo: string; dockerImage: string; + versionPrefix: string; } // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -53,6 +54,7 @@ export const getDefaultsForClient = (clientName: string): IDefaults => owner: "none", repo: "none", dockerImage: "none", + versionPrefix: "", }, validator: {}, }; diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts index 1f3672056..ac32b1896 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconApi.ts @@ -15,8 +15,8 @@ export class CgEth2BeaconApi implements ICGEth2BeaconApi { public state: ICGBeaconStateApi; public pool: IBeaconPoolApi; - private readonly httpClient: HttpClient; - private readonly config: IBeaconConfig; + protected readonly httpClient: HttpClient; + protected readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient, publicKey?: string, dispatch?: Dispatch) { this.config = config; this.httpClient = httpClient; diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts index cdd1ed6a8..6231618cf 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconBlocksApi.ts @@ -7,8 +7,8 @@ import {Attestation} from "@chainsafe/lodestar-types/lib/types/operations"; import {matomo} from "../../../tracking"; export class CgEth2BeaconBlocksApi implements ICGETH2BeaconBlocksApi { - private readonly httpClient: HttpClient; - private readonly config: IBeaconConfig; + protected readonly httpClient: HttpClient; + protected readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { this.config = config; this.httpClient = httpClient; @@ -19,8 +19,8 @@ export class CgEth2BeaconBlocksApi implements ICGETH2BeaconBlocksApi { "/eth/v1/beacon/blocks", this.config.types.SignedBeaconBlock.toJson(block, {case: "snake"}), ); - if (process.env.NODE_ENV !== "validator-test") - if (matomo) matomo.trackEvent({category: "block", action: "proposed", value: block.message.slot}); + if (process.env.NODE_ENV !== "validator-test" && matomo) + matomo.trackEvent({category: "block", action: "proposed", value: block.message.slot}); }; public getBlock = async (blockId: "head" | "genesis" | "finalized" | number): Promise => { @@ -28,6 +28,7 @@ export class CgEth2BeaconBlocksApi implements ICGETH2BeaconBlocksApi { return this.config.types.SignedBeaconBlock.fromJson(blocksResponse.data, {case: "snake"}); }; + // TODO: rewrite this to more generic way and then overwrite for the needed cases? public getBlockAttestations = async ( blockId: "head" | "genesis" | "finalized" | number, ): Promise | null> => { diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts index e5f5cfe07..ab210958e 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconPoolApi.ts @@ -7,10 +7,10 @@ import {toHex} from "@chainsafe/lodestar-utils"; import {Dispatch} from "redux"; export class CgEth2BeaconPoolApi implements IBeaconPoolApi { - private readonly httpClient: HttpClient; - private readonly config: IBeaconConfig; - private readonly publicKey?: string; - private readonly dispatch?: Dispatch; + protected readonly httpClient: HttpClient; + protected readonly config: IBeaconConfig; + protected readonly publicKey?: string; + protected readonly dispatch?: Dispatch; public constructor(config: IBeaconConfig, httpClient: HttpClient, publicKey?: string, dispatch?: Dispatch) { this.config = config; diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts index fdcc329b8..7c5fb3ce4 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2BeaconStateApi.ts @@ -7,8 +7,8 @@ import logger from "electron-log"; import {cgLogger} from "../../../../../main/logger"; export class CgEth2BeaconStateApi implements ICGBeaconStateApi { - private readonly httpClient: HttpClient; - private readonly config: IBeaconConfig; + protected readonly httpClient: HttpClient; + protected readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { this.config = config; this.httpClient = httpClient; diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2Config.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2Config.ts index 2731c7f02..b0aa3dfb7 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2Config.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2Config.ts @@ -6,8 +6,8 @@ import {Fork} from "@chainsafe/lodestar-types"; import {Json} from "@chainsafe/ssz"; export class CgEth2Config implements ICGEth2Config { - private readonly httpClient: HttpClient; - private readonly config: IBeaconConfig; + protected readonly httpClient: HttpClient; + protected readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { this.config = config; this.httpClient = httpClient; diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts index 56dbd3a4f..b5927dfab 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2EventsApi.ts @@ -7,7 +7,7 @@ import EventSource from "eventsource"; export class CgEth2EventsApi implements ICGEventsApi { protected readonly config: IBeaconConfig; - private readonly baseUrl: string; + protected readonly baseUrl: string; public constructor(config: IBeaconConfig, baseUrl: string) { this.config = config; this.baseUrl = baseUrl; diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2NodeApi.ts b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2NodeApi.ts index 3ef613d0f..2ba902243 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2NodeApi.ts +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2NodeApi.ts @@ -5,8 +5,8 @@ import {SyncingStatus} from "@chainsafe/lodestar-types"; import {Json} from "@chainsafe/ssz"; export class CgEth2NodeApi implements ICGEth2NodeApi { - private readonly httpClient: HttpClient; - private readonly config: IBeaconConfig; + protected readonly httpClient: HttpClient; + protected readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { this.config = config; this.httpClient = httpClient; diff --git a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx index 915a6a6f6..56c68722c 100644 --- a/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx +++ b/src/renderer/services/eth2/client/eth2ApiClient/cgEth2ValidatorApi.tsx @@ -19,8 +19,8 @@ import querystring from "querystring"; import {aAPLogger} from "../../../../../main/logger"; export class CgEth2ValidatorApi implements ICGEth2ValidatorApi { - private readonly httpClient: HttpClient; - private readonly config: IBeaconConfig; + protected readonly httpClient: HttpClient; + protected readonly config: IBeaconConfig; public constructor(config: IBeaconConfig, httpClient: HttpClient) { this.config = config; this.httpClient = httpClient; @@ -108,8 +108,6 @@ export class CgEth2ValidatorApi implements ICGEth2ValidatorApi { } catch (e) { aAPLogger.error(e); error = e; - } finally { - aAPLogger.debug(data); } if (error) throw error; }; diff --git a/src/renderer/services/eth2/client/lighthouse/defaults.ts b/src/renderer/services/eth2/client/lighthouse/defaults.ts index 15c8d5b6e..0ee48dacb 100644 --- a/src/renderer/services/eth2/client/lighthouse/defaults.ts +++ b/src/renderer/services/eth2/client/lighthouse/defaults.ts @@ -7,6 +7,7 @@ export const beaconNode: IDefaultBeaconNodeConfig = { memory: "3500m", owner: "sigp", repo: "lighthouse", + versionPrefix: "", dockerImage: process.env.DOCKER_LIGHTHOUSE_IMAGE, }; diff --git a/src/renderer/services/eth2/client/module.ts b/src/renderer/services/eth2/client/module.ts index fa5e0c4d9..d21614ef9 100644 --- a/src/renderer/services/eth2/client/module.ts +++ b/src/renderer/services/eth2/client/module.ts @@ -7,6 +7,8 @@ export * from "./eth2ApiClient"; export * from "./lighthouse"; export * from "./teku"; +export * from "./nimbus"; +export * from "./prysm"; // as you wish export * from "./utils"; diff --git a/src/renderer/services/eth2/client/nimbus/cgNimbusEth2EventsApi.ts b/src/renderer/services/eth2/client/nimbus/cgNimbusEth2EventsApi.ts new file mode 100644 index 000000000..d82639993 --- /dev/null +++ b/src/renderer/services/eth2/client/nimbus/cgNimbusEth2EventsApi.ts @@ -0,0 +1,215 @@ +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {CgEth2EventsApi} from "../eth2ApiClient/cgEth2EventsApi"; +import {CGBeaconEvent, CGBeaconEventType, ErrorEvent} from "../interface"; +import {IStoppableEventIterable, LodestarEventIterator} from "@chainsafe/lodestar-utils"; +import {HttpClient} from "../../../api"; +import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@chainsafe/lodestar-beacon-state-transition/lib/util/epoch"; +import {BeaconEventType} from "@chainsafe/lodestar-validator/lib/api/interface/events"; +import {cgLogger} from "../../../../../main/logger"; + +type BlockState = { + slot: number; + epoch: number; + state: string; +}; + +type BlockResponse = { + data: { + root: string; + canonical: boolean; + header: { + message: { + slot: string; + // eslint-disable-next-line camelcase + proposer_index: string; + // eslint-disable-next-line camelcase + parent_root: string; + // eslint-disable-next-line camelcase + state_root: string; + // eslint-disable-next-line camelcase + body_root: string; + }; + signature: string; + }; + }; +}; + +type PushedAttestation = { + slot: number; + index: number; + beaconBlockRoot: string; +}; + +type Attestation = { + // eslint-disable-next-line camelcase + aggregation_bits: string; + data: { + slot: string; + index: string; + // eslint-disable-next-line camelcase + beacon_block_root: string; + source: { + epoch: string; + root: string; + }; + target: { + epoch: string; + root: string; + }; + }; + signature: string; +}; + +export class CgNimbusEth2EventsApi extends CgEth2EventsApi { + private currentBlock: BlockState; + private depend: BlockState; + private previousDepend: BlockState; + private pushedAttestation: PushedAttestation[] = []; + + public constructor(config: IBeaconConfig, baseUrl: string) { + super(config, baseUrl); + } + + // topics: head, block, attestation, voluntary_exit, finalized_checkpoint, chain_reorg + public getEventStream = (topics: CGBeaconEventType[]): IStoppableEventIterable => { + const httpClient = new HttpClient(this.baseUrl + "/eth/v1/beacon"); + return new LodestarEventIterator(({push}): (() => void) => { + let interval: NodeJS.Timeout; + (async (): Promise => { + // eslint-disable-next-line no-constant-condition + while (true) { + try { + await this.initializeEventPooling(httpClient); + break; + } catch (e) { + cgLogger.warn("Failed to initialize data", e, "\n Retying..."); + } + } + + interval = (setInterval(async () => { + try { + const result = await httpClient.get("headers/head"); + const slot = Number(result.data.header.message.slot); + + if (this.currentBlock.slot !== slot) { + this.pushedAttestation = []; + + if (topics.some((topic) => topic === CGBeaconEventType.BLOCK)) + push({ + type: BeaconEventType.BLOCK, + message: this.config.types.BlockEventPayload.fromJson({ + slot, + block: result.data.root, + }), + }); + + const epoch = computeEpochAtSlot(this.config, slot); + if (this.currentBlock.epoch !== epoch) { + this.previousDepend = this.depend; + this.depend = this.currentBlock; + } + + if (topics.some((topic) => topic === CGBeaconEventType.HEAD)) + // root => block + // state => header.message.state_root + // epoch_transition => on epoch changed + // TODO: ⇩ implement after ssz add this fields ⇩ + // previous_duty_dependent_root => if epoch_transition then state before + // current_duty_dependent_root => if epoch_transition then state before + push({ + type: BeaconEventType.HEAD, + message: this.config.types.ChainHead.fromJson({ + slot, + block: result.data.root, + state: result.data.header.message.state_root, + epochTransition: this.currentBlock.epoch !== epoch, + }), + }); + + this.currentBlock = { + slot, + epoch, + state: result.data.root, + }; + } + + if (topics.some((topic) => topic === CGBeaconEventType.ATTESTATION)) { + const attestations = await httpClient.get<{data: Attestation[]}>( + `pool/attestations?slot=${slot}`, + ); + for (const attestation of attestations.data) { + const slot = Number(attestation.data.slot); + const index = Number(attestation.data.index); + if ( + !this.pushedAttestation.some( + (pushed) => + pushed.slot === slot && + pushed.index === index && + pushed.beaconBlockRoot === attestation.data.beacon_block_root, + ) + ) { + this.pushedAttestation.push({ + slot, + index, + beaconBlockRoot: attestation.data.beacon_block_root, + }); + push({ + type: CGBeaconEventType.ATTESTATION, + message: this.config.types.Attestation.fromJson(attestation, {case: "snake"}), + }); + } + } + } + } catch (e) { + push({type: CGBeaconEventType.ERROR}); + } + }, 1000) as unknown) as NodeJS.Timeout; + })(); + return (): void => { + if (interval) clearInterval(interval); + }; + }); + }; + + private initializeEventPooling = async (httpClient: HttpClient): Promise => { + if (!this.currentBlock || !this.depend || !this.previousDepend) { + if (!this.currentBlock) { + const result = await httpClient.get("headers/head"); + const slot = Number(result.data.header.message.slot); + this.currentBlock = { + slot, + epoch: computeEpochAtSlot(this.config, slot), + state: result.data.root, + }; + } + if (!this.depend) { + try { + const previousEpochLastSlot = computeStartSlotAtEpoch(this.config, this.currentBlock.epoch) - 1; + const result = await httpClient.get(`headers/${previousEpochLastSlot}`); + const slot = Number(result.data.header.message.slot); + this.depend = { + slot, + epoch: computeEpochAtSlot(this.config, slot), + state: result.data.root, + }; + } catch (e) { + cgLogger.warn("Event error while fetching depend", e); + } + } + if (!this.previousDepend) { + try { + const previousEpochLastSlot = computeStartSlotAtEpoch(this.config, this.depend.epoch) - 1; + const result = await httpClient.get(`headers/${previousEpochLastSlot}`); + const slot = Number(result.data.header.message.slot); + this.previousDepend = { + slot, + epoch: computeEpochAtSlot(this.config, slot), + state: result.data.root, + }; + } catch (e) { + cgLogger.warn("Event error while fetching previousDepend", e); + } + } + } + }; +} diff --git a/src/renderer/services/eth2/client/nimbus/cgNimbusEth2ValidatorApi.ts b/src/renderer/services/eth2/client/nimbus/cgNimbusEth2ValidatorApi.ts new file mode 100644 index 000000000..5fc0e435f --- /dev/null +++ b/src/renderer/services/eth2/client/nimbus/cgNimbusEth2ValidatorApi.ts @@ -0,0 +1,25 @@ +import {CgEth2ValidatorApi} from "../eth2ApiClient/cgEth2ValidatorApi"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {HttpClient} from "../../../api"; +import {CommitteeIndex, Slot, ValidatorIndex} from "@chainsafe/lodestar-types"; + +export class CgNimbusEth2ValidatorApi extends CgEth2ValidatorApi { + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + super(config, httpClient); + } + + public prepareBeaconCommitteeSubnet = async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + validatorIndex: ValidatorIndex, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + committeeIndex: CommitteeIndex, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + committeesAtSlot: number, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + slot: Slot, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isAggregator: boolean, + ): Promise => { + // Intentionally left empty! + }; +} diff --git a/src/renderer/services/eth2/client/nimbus/defaults.ts b/src/renderer/services/eth2/client/nimbus/defaults.ts new file mode 100644 index 000000000..50e3bea0e --- /dev/null +++ b/src/renderer/services/eth2/client/nimbus/defaults.ts @@ -0,0 +1,14 @@ +import {IDefaultBeaconNodeConfig, IDefaultValidatorConfig} from "../defaults"; + +export const beaconNode: IDefaultBeaconNodeConfig = { + rpcPort: 5052, + libp2pPort: 9000, + discoveryPort: 9000, + memory: "3500m", + owner: "status-im", + repo: "nimbus-eth2", + versionPrefix: "amd64-", + dockerImage: process.env.DOCKER_NIMBUS_IMAGE, +}; + +export const validator: IDefaultValidatorConfig = {}; diff --git a/src/renderer/services/eth2/client/nimbus/index.ts b/src/renderer/services/eth2/client/nimbus/index.ts new file mode 100644 index 000000000..b9858a09e --- /dev/null +++ b/src/renderer/services/eth2/client/nimbus/index.ts @@ -0,0 +1,20 @@ +import {CgEth2ApiClient} from "../module"; +import {IEventsApi} from "@chainsafe/lodestar-validator/lib/api/interface/events"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {Dispatch} from "redux"; +import {CgNimbusEth2EventsApi} from "./cgNimbusEth2EventsApi"; +import {CgNimbusEth2ValidatorApi} from "./cgNimbusEth2ValidatorApi"; + +export class CgNimbusEth2Api extends CgEth2ApiClient { + public constructor( + config: IBeaconConfig, + url: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + {publicKey, dispatch}: {publicKey?: string; dispatch?: Dispatch} = {}, + ) { + super(config, url); + + this.validator = new CgNimbusEth2ValidatorApi(config, this.httpClient); + this.events = (new CgNimbusEth2EventsApi(config, url) as unknown) as IEventsApi; + } +} diff --git a/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconApi.ts b/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconApi.ts new file mode 100644 index 000000000..a69d3c92c --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconApi.ts @@ -0,0 +1,41 @@ +import {CgEth2BeaconApi} from "../eth2ApiClient/cgEth2BeaconApi"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {HttpClient} from "../../../api"; +import {Dispatch} from "redux"; +import {CgPrysmEth2BeaconStateApi} from "./CgPrysmEth2BeaconStateApi"; +import {Genesis} from "@chainsafe/lodestar-types"; +import logger from "electron-log"; +import {base64ToHex} from "./utils"; +import {CgPrysmEth2BeaconPoolApi} from "./CgPrysmEth2BeaconPoolApi"; +import {CgPrysmEth2BeaconBlocksApi} from "./CgPrysmEth2BeaconBlocksApi"; + +export class CgPrysmEth2BeaconApi extends CgEth2BeaconApi { + public constructor(config: IBeaconConfig, httpClient: HttpClient, publicKey?: string, dispatch?: Dispatch) { + super(config, httpClient, publicKey, dispatch); + + this.blocks = new CgPrysmEth2BeaconBlocksApi(config, httpClient); + this.state = new CgPrysmEth2BeaconStateApi(config, httpClient); + this.pool = new CgPrysmEth2BeaconPoolApi(config, httpClient, publicKey, dispatch); + } + + public getGenesis = async (): Promise => { + try { + const {genesisTime, genesisValidatorsRoot} = await this.httpClient.get<{ + genesisTime: string; + genesisValidatorsRoot: string; + }>("/eth/v1alpha1/node/genesis"); + + const result = { + genesisTime: Math.round(new Date(genesisTime).getTime() / 1000).toString(), + genesisValidatorsRoot: base64ToHex(genesisValidatorsRoot), + // TODO: change mocked data with real + genesisForkVersion: "0x00000000", + }; + + return this.config.types.Genesis.fromJson(result, {case: "camel"}); + } catch (e) { + logger.error("Failed to obtain genesis time", {error: e.message}); + return null; + } + }; +} diff --git a/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconBlocksApi.ts b/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconBlocksApi.ts new file mode 100644 index 000000000..3c5da1b02 --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconBlocksApi.ts @@ -0,0 +1,73 @@ +import {CgEth2BeaconBlocksApi} from "../eth2ApiClient/cgEth2BeaconBlocksApi"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {HttpClient} from "../../../api"; +import {SignedBeaconBlock} from "@chainsafe/lodestar-types"; +import {matomo} from "../../../tracking"; +import {SignedBeaconBlockData} from "./map.types"; +import {mapProduceBlockDataToPrysmProduceBlock} from "./mapProduceBlockDataToPrysmProduceBlock"; +import {List} from "@chainsafe/ssz"; +import {Attestation} from "@chainsafe/lodestar-types/lib/types/operations"; +import {ChainHead, ListBlocksResponse} from "./types"; +import querystring from "querystring"; +import {mapProduceBlockResponseToStandardProduceBlock} from "./mapProduceBlockResponseToStandardProduceBlock"; +import {base64ToHex} from "./utils"; + +export class CgPrysmEth2BeaconBlocksApi extends CgEth2BeaconBlocksApi { + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + super(config, httpClient); + } + + public publishBlock = async (block: SignedBeaconBlock): Promise => { + const data = (this.config.types.SignedBeaconBlock.toJson(block, { + case: "snake", + }) as unknown) as SignedBeaconBlockData; + await this.httpClient.post("/eth/v1alpha1/validator/block", mapProduceBlockDataToPrysmProduceBlock(data)); + + if (process.env.NODE_ENV !== "validator-test" && matomo) + matomo.trackEvent({category: "block", action: "proposed", value: block.message.slot}); + }; + + public getBlock = async (blockId: "head" | "genesis" | "finalized" | number): Promise => { + const slot = await (async (): Promise => { + if (typeof blockId === "string") { + const data = await this.httpClient.get("/eth/v1alpha1/beacon/chainhead"); + if (blockId === "head" || blockId === "genesis") return Number(data.headSlot); + if (blockId === "finalized") return Number(data.finalizedSlot); + throw new Error(`block id: ${blockId} dose not exist`); + } + return blockId; + })(); + + const query = querystring.stringify( + blockId === "genesis" + ? {genesis: true} + : { + slot, + }, + ); + const response = await this.httpClient.get(`/eth/v1alpha1/beacon/blocks?${query}`); + const blocks = response.blockContainers.filter(({canonical}) => canonical); + if (!blocks.length) throw new Error(`Block ${blockId} not found`); + + return this.config.types.SignedBeaconBlock.fromJson( + { + message: mapProduceBlockResponseToStandardProduceBlock(blocks[0].block.block), + signature: base64ToHex(blocks[0].block.signature), + }, + {case: "snake"}, + ); + }; + + public getBlockAttestations = async ( + blockId: "head" | "genesis" | "finalized" | number, + ): Promise | null> => { + try { + const block = await this.getBlock(blockId); + + if (typeof blockId === "number" && block.message.slot !== blockId) return null; + return block.message.body.attestations; + } catch { + return null; + } + }; +} diff --git a/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconPoolApi.ts b/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconPoolApi.ts new file mode 100644 index 000000000..b61dd32cf --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconPoolApi.ts @@ -0,0 +1,73 @@ +import {CgEth2BeaconPoolApi} from "../eth2ApiClient/cgEth2BeaconPoolApi"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {HttpClient} from "../../../api"; +import {Dispatch} from "redux"; +import {Attestation, SignedVoluntaryExit} from "@chainsafe/lodestar-types"; +import {signedNewAttestation} from "../../../../ducks/validator/actions"; +import {toHex} from "@chainsafe/lodestar-utils"; +import {hexToBase64} from "./utils"; +import {Attestation as PrysmAttestation} from "./types"; + +type AttestationData = { + aggregationBits: string; + data: { + slot: string; + index: string; + beaconBlockRoot: string; + source: { + epoch: string; + root: string; + }; + target: { + epoch: string; + root: string; + }; + }; + signature: string; +}; + +export class CgPrysmEth2BeaconPoolApi extends CgEth2BeaconPoolApi { + public constructor(config: IBeaconConfig, httpClient: HttpClient, publicKey?: string, dispatch?: Dispatch) { + super(config, httpClient, publicKey, dispatch); + } + + public submitAttestation = async (attestation: Attestation): Promise => { + if (this.publicKey && this.dispatch) { + const validatorIndexInCommittee = attestation.aggregationBits.findIndex((bit) => bit); + if (validatorIndexInCommittee !== -1) + this.dispatch( + signedNewAttestation( + this.publicKey, + toHex(attestation.data.beaconBlockRoot), + attestation.data.index, + attestation.data.slot, + validatorIndexInCommittee, + ), + ); + } + const data = this.config.types.Attestation.toJson(attestation) as AttestationData; + const mapped: PrysmAttestation = { + aggregationBits: hexToBase64(data.aggregationBits), + data: { + slot: data.data.slot, + committeeIndex: data.data.index, + beaconBlockRoot: hexToBase64(data.data.beaconBlockRoot), + source: { + epoch: data.data.source.epoch, + root: hexToBase64(data.data.source.root), + }, + target: { + epoch: data.data.target.epoch, + root: hexToBase64(data.data.target.root), + }, + }, + signature: hexToBase64(data.signature), + }; + await this.httpClient.post("/eth/v1alpha1/validator/attestation", mapped); + }; + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async submitVoluntaryExit(signedVoluntaryExit: SignedVoluntaryExit): Promise { + throw new Error("submitVoluntaryExit not implemented"); + } +} diff --git a/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconStateApi.ts b/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconStateApi.ts new file mode 100644 index 000000000..8fbe444dc --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/CgPrysmEth2BeaconStateApi.ts @@ -0,0 +1,80 @@ +import {CgEth2BeaconStateApi} from "../eth2ApiClient/cgEth2BeaconStateApi"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {HttpClient} from "../../../api"; +import {BeaconCommitteeResponse, BLSPubkey, Fork, ValidatorIndex} from "@chainsafe/lodestar-types"; +import {ICGValidatorResponse} from "../interface"; +import {cgLogger} from "../../../../../main/logger"; +import {base64ToHex, hexToBase64} from "./utils"; +import logger from "electron-log"; +import {ValidatorStateResponse, ValidatorStatusResponse} from "./types"; + +export class CgPrysmEth2BeaconStateApi extends CgEth2BeaconStateApi { + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + super(config, httpClient); + } + + // TODO: changer mock with real data + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public getFork = async (stateId: "head"): Promise => { + try { + const forkMock = { + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + previous_version: "0x00000000", + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + current_version: "0x00000000", + epoch: "0", + }; + return this.config.types.Fork.fromJson(forkMock, {case: "snake"}); + } catch (e) { + logger.error("Failed to fetch head fork version", {error: e.message}); + return null; + } + }; + + public getStateValidator = async ( + stateId: "head" | number, + validatorId: ValidatorIndex | BLSPubkey, + ): Promise => { + const id = + typeof validatorId === "number" + ? validatorId.toString() + : this.config.types.BLSPubkey.toJson(validatorId)?.toString() ?? ""; + try { + const query = + typeof validatorId === "number" + ? `index=${validatorId}` + : `public_key=${encodeURIComponent(hexToBase64(id))}`; + + const [stateValidatorResponse, statusValidatorResponse, indexValidatorResponse] = await Promise.all([ + this.httpClient.get(`/eth/v1alpha1/validator?${query}`), + this.httpClient.get(`/eth/v1alpha1/validator/status?${query}`), + this.httpClient.get<{index: string}>(`/eth/v1alpha1/validator/index?${query}`), + ]); + + return this.config.types.ValidatorResponse.fromJson({ + index: indexValidatorResponse.index, + balance: stateValidatorResponse.effectiveBalance, + status: statusValidatorResponse.status, + validator: { + ...stateValidatorResponse, + pubkey: base64ToHex(stateValidatorResponse.publicKey), + withdrawalCredentials: base64ToHex(stateValidatorResponse.withdrawalCredentials), + }, + }) as ICGValidatorResponse; + } catch (e) { + if (!e.message.includes('"code":404')) + cgLogger.error("Failed to fetch validator", {validatorId: id, error: e.message}); + return null; + } + }; + + public getLastEpoch = async (): Promise => { + throw new Error("getLastEpoch not implemented"); + }; + + // TODO: implement this? required for CG testing + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public getCommittees = async (stateId: "head" | number = "head"): Promise => { + throw new Error("getCommittees not implemented"); + }; +} diff --git a/src/renderer/services/eth2/client/prysm/CgPrysmEth2EventsApi.ts b/src/renderer/services/eth2/client/prysm/CgPrysmEth2EventsApi.ts new file mode 100644 index 000000000..0552df6b0 --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/CgPrysmEth2EventsApi.ts @@ -0,0 +1,71 @@ +import {CgEth2EventsApi} from "../eth2ApiClient/cgEth2EventsApi"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {CGBeaconEvent, CGBeaconEventType, ErrorEvent} from "../interface"; +import {IStoppableEventIterable, LodestarEventIterator} from "@chainsafe/lodestar-utils"; +import {PrysmStreamReader} from "./PrysmStreamReader"; +import {Attestation as PrysmAttestation, SignedBeaconBlock} from "./types"; +import {BeaconEventType} from "@chainsafe/lodestar-validator/lib/api/interface/events"; +import {base64ToHex} from "./utils"; +import {Attestation} from "@chainsafe/lodestar-types"; +import {mapAttestation} from "./mapProduceBlockResponseToStandardProduceBlock"; +import {Json} from "@chainsafe/ssz"; + +export class CgPrysmEth2EventsApi extends CgEth2EventsApi { + public constructor(config: IBeaconConfig, baseUrl: string) { + super(config, baseUrl); + } + + public getEventStream = (topics: CGBeaconEventType[]): IStoppableEventIterable => { + const streams: {[key: string]: PrysmStreamReader} = {}; + return new LodestarEventIterator(({push}): (() => void) => { + // TODO: implement head + + // BLOCK + if (topics.some((topic) => topic === "block")) { + const url = new URL(`/eth/v1alpha1/beacon/blocks/stream`, this.baseUrl); + streams["block"] = new PrysmStreamReader(url); + streams["block"].on("data", (data: SignedBeaconBlock) => { + push({ + type: BeaconEventType.BLOCK, + message: this.config.types.BlockEventPayload.fromJson( + { + slot: data.block.slot, + block: base64ToHex(data.block.stateRoot), + }, + {case: "snake"}, + ), + }); + }); + } + + // ATTESTATION + if (topics.some((topic) => topic === "attestation")) { + const url = new URL(`/eth/v1alpha1/beacon/attestations/stream`, this.baseUrl); + streams["attestation"] = new PrysmStreamReader(url, { + transformer: (data): Attestation => + this.config.types.Attestation.fromJson((mapAttestation(data) as unknown) as Json, { + case: "snake", + }), + }); + streams["attestation"].on("data", (data) => { + push({ + type: CGBeaconEventType.ATTESTATION, + message: data, + }); + }); + } + + // TODO: implement voluntary_exit + + // TODO: implement finalized_checkpoint + + // TODO: implement chain_reorg + + return (): void => { + Object.keys(streams).forEach((key) => { + streams[key].removeAllListeners(); + }); + }; + }); + }; +} diff --git a/src/renderer/services/eth2/client/prysm/CgPrysmEth2NodeApi.ts b/src/renderer/services/eth2/client/prysm/CgPrysmEth2NodeApi.ts new file mode 100644 index 000000000..6da89f1c9 --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/CgPrysmEth2NodeApi.ts @@ -0,0 +1,23 @@ +import {CgEth2NodeApi} from "../eth2ApiClient/cgEth2NodeApi"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {HttpClient} from "../../../api"; +import {SyncingStatus} from "@chainsafe/lodestar-types"; +import {Json} from "@chainsafe/ssz"; + +export class CgPrysmEth2NodeApi extends CgEth2NodeApi { + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + super(config, httpClient); + } + + // TODO: this need to be implemented + public getSyncingStatus = async (): Promise => { + const syncingResponse = await this.httpClient.get<{data: Json}>("/eth/v1alpha1/node/syncing"); + this.httpClient.get("/eth/v1alpha1/beacon/chainhead").then(console.log); + return this.config.types.SyncingStatus.fromJson(syncingResponse.data, {case: "snake"}); + }; + + public getVersion = async (): Promise => { + const versionResponse = await this.httpClient.get<{version: string}>("/eth/v1alpha1/node/version"); + return versionResponse.version; + }; +} diff --git a/src/renderer/services/eth2/client/prysm/CgPrysmEth2ValidatorApi.ts b/src/renderer/services/eth2/client/prysm/CgPrysmEth2ValidatorApi.ts new file mode 100644 index 000000000..0cede7c69 --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/CgPrysmEth2ValidatorApi.ts @@ -0,0 +1,204 @@ +import {CgEth2ValidatorApi} from "../eth2ApiClient/cgEth2ValidatorApi"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {HttpClient} from "../../../api"; +import { + Attestation, + AttestationData, + AttesterDuty, + BeaconBlock, + CommitteeIndex, + Epoch, + ProposerDuty, + Root, + SignedAggregateAndProof, + Slot, + ValidatorIndex, +} from "@chainsafe/lodestar-types"; +import {Json, toHexString} from "@chainsafe/ssz"; +import {base64ToHex, hexToBase64} from "./utils"; +import { + DutiesResponse, + ValidatorStatusResponse, + Assignments, + BeaconBlock as PrysmBeaconBlock, + AttestationData as PrysmAttestationData, + Attestation as PrysmAttestation, +} from "./types"; +import {SignedAggregateAndProof as SignedAggregateAndProofDto} from "./map.types"; +import querystring from "querystring"; +import { + mapAttestation, + mapAttestationData, + mapProduceBlockResponseToStandardProduceBlock, +} from "./mapProduceBlockResponseToStandardProduceBlock"; +import {mapAttestation as mapAttestationToBase} from "./mapProduceBlockDataToPrysmProduceBlock"; +import {PrysmStreamReader} from "./PrysmStreamReader"; +import {aAPLogger} from "../../../../../main/logger"; + +export class CgPrysmEth2ValidatorApi extends CgEth2ValidatorApi { + private readonly stream: PrysmStreamReader; + + public constructor(config: IBeaconConfig, httpClient: HttpClient) { + super(config, httpClient); + + const url = new URL(`/eth/v1alpha1/beacon/attestations/stream`, httpClient.getBaseUrl()); + this.stream = new PrysmStreamReader(url, { + transformer: (data): Attestation => + this.config.types.Attestation.fromJson((mapAttestation(data) as unknown) as Json, { + case: "snake", + }), + maxElements: 128, + }); + } + + public getAttesterDuties = async (epoch: Epoch, validatorIndexes: ValidatorIndex[]): Promise => { + const pubkeyQuery = ( + await Promise.all( + validatorIndexes.map((index) => + this.httpClient.get(`/eth/v1alpha1/validator?index=${index}`), + ), + ) + ) + .map(({publicKey}) => `&public_keys=${encodeURIComponent(publicKey)}`) + .join(""); + const duties = await this.httpClient.get( + `/eth/v1alpha1/validator/duties?epoch=${Number(epoch.toString()) - 1}${pubkeyQuery}`, + ); + const transformed: Json[] = []; + for (const duty of duties.nextEpochDuties) { + transformed.push({ + pubkey: base64ToHex(duty.publicKey), + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + validator_index: duty.validatorIndex, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committee_index: duty.committeeIndex, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committee_length: duty.committee.length, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committees_at_slot: duty.committee.findIndex((validator) => validator === duty.validatorIndex) + 1, + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + validator_committee_index: duty.committeeIndex, + slot: duty.attesterSlot, + }); + } + return transformed.map((value) => this.config.types.AttesterDuty.fromJson(value, {case: "snake"})); + }; + + public getProposerDuties = async (epoch: Epoch): Promise => { + const url = `/eth/v1alpha1/validators/assignments?epoch=${epoch.toString()}`; + const responseData = await this.httpClient.get(url); + const transformed: Json[] = []; + for (const assignment of responseData.assignments) { + for (const slot of assignment.proposerSlots) { + transformed.push({ + pubkey: base64ToHex(assignment.publicKey), + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + validator_index: assignment.validatorIndex, + slot: slot, + }); + } + } + return transformed.map((value) => this.config.types.ProposerDuty.fromJson(value, {case: "snake"})); + }; + + public prepareBeaconCommitteeSubnet = async ( + validatorIndex: ValidatorIndex, + committeeIndex: CommitteeIndex, + committeesAtSlot: number, + slot: Slot, + isAggregator: boolean, + ): Promise => { + await this.httpClient.post("/eth/v1alpha1/validator/subnet/subscribe", { + slots: [slot], + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committee_ids: [committeesAtSlot], + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + is_aggregator: [isAggregator], + }); + }; + + public produceBlock = async (slot: Slot, randaoReveal: Uint8Array, graffiti: string): Promise => { + const values = { + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + randao_reveal: hexToBase64(toHexString(randaoReveal)), + graffiti: hexToBase64( + graffiti.startsWith("0x") + ? graffiti + : "0x" + Buffer.from(graffiti, "utf-8").toString("hex").padEnd(64, "0"), + ), + slot: slot.toString(), + }; + if (!graffiti) delete values.graffiti; + const query = querystring.stringify(values); + const responseData = await this.httpClient.get(`/eth/v1alpha1/validator/block?${query}`); + const transformedResponseData = mapProduceBlockResponseToStandardProduceBlock(responseData); + return this.config.types.BeaconBlock.fromJson((transformedResponseData as unknown) as Json, { + case: "snake", + }); + }; + + public produceAttestationData = async (index: CommitteeIndex, slot: Slot): Promise => { + const query = querystring.stringify({ + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + committee_index: index, + slot, + }); + const responseData = await this.httpClient.get( + `/eth/v1alpha1/validator/attestation?${query}`, + ); + return this.config.types.AttestationData.fromJson((mapAttestationData(responseData) as unknown) as Json, { + case: "snake", + }); + }; + + public getAggregatedAttestation = async (attestationDataRoot: Root, slot: Slot): Promise => { + const dataRoot = this.config.types.Root.toJson(attestationDataRoot); + const result = this.stream + .getAll() + .filter((attestation) => Number(attestation.data.slot) === slot) + .reverse() + .find( + (attestation) => + this.config.types.Root.toJson(this.config.types.AttestationData.hashTreeRoot(attestation.data)) === + dataRoot, + ); + + if (!result) throw new Error("Attestation not found"); + return result; + }; + + public publishAggregateAndProofs = async (signedAggregateAndProofs: SignedAggregateAndProof[]): Promise => { + let error: Error; + try { + await Promise.all( + signedAggregateAndProofs + .map( + (data) => + (this.config.types.SignedAggregateAndProof.toJson(data, { + case: "snake", + }) as unknown) as SignedAggregateAndProofDto, + ) + .map( + (data) => + (this.httpClient.post("/eth/v1alpha1/validator/aggregate", { + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + signed_aggregate_and_proof: { + message: { + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + aggregator_index: data.message.aggregator_index, + aggregate: mapAttestationToBase(data.message.aggregate), + // eslint-disable-next-line camelcase,@typescript-eslint/camelcase + selection_proof: hexToBase64(data.message.selection_proof), + }, + signature: hexToBase64(data.signature), + }, + }) as unknown) as Json, + ), + ); + } catch (e) { + aAPLogger.error(e); + error = e; + } + if (error) throw error; + }; +} diff --git a/src/renderer/services/eth2/client/prysm/PrysmStreamReader.ts b/src/renderer/services/eth2/client/prysm/PrysmStreamReader.ts new file mode 100644 index 000000000..a8772d04e --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/PrysmStreamReader.ts @@ -0,0 +1,50 @@ +import {EventEmitter} from "events"; +import axios from "axios"; +import {IncomingMessage} from "http"; + +type Options = { + maxElements?: number; + transformer?: (data: R) => T; +}; + +export class PrysmStreamReader extends EventEmitter { + private array: T[] = []; + + private readonly max: number; + + public constructor( + url: URL, + {maxElements = 25, transformer = (d: R): T => (d as unknown) as T}: Options = {}, + ) { + super(); + this.max = maxElements; + + try { + axios + .get(url.href, { + responseType: "stream", + }) + .then((r) => { + const event = r.data as IncomingMessage; + event.on("data", (buffer) => { + const data: R = JSON.parse(buffer.toString()); + this.push(transformer(data)); + }); + }); + } catch (e) { + this.emit("error", e); + } + } + + public push(item: T): void { + this.array.push(item); + if (this.array.length > this.max) { + this.array.splice(0, this.array.length - this.max); + } + this.emit("data", item); + } + + public getAll(): T[] { + return this.array.slice(); + } +} diff --git a/src/renderer/services/eth2/client/prysm/defaults.ts b/src/renderer/services/eth2/client/prysm/defaults.ts new file mode 100644 index 000000000..218c969da --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/defaults.ts @@ -0,0 +1,14 @@ +import {IDefaultBeaconNodeConfig, IDefaultValidatorConfig} from "../defaults"; + +export const beaconNode: IDefaultBeaconNodeConfig = { + rpcPort: 5052, + libp2pPort: 9000, + discoveryPort: 9000, + memory: "3500m", + versionPrefix: "", + dockerImage: process.env.DOCKER_PRYSM_IMAGE, + owner: "prysmaticlabs", + repo: "prysm", +}; + +export const validator: IDefaultValidatorConfig = {}; diff --git a/src/renderer/services/eth2/client/prysm/index.ts b/src/renderer/services/eth2/client/prysm/index.ts new file mode 100644 index 000000000..2214d3496 --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/index.ts @@ -0,0 +1,25 @@ +import {CgEth2ApiClient} from "../module"; +import {IBeaconConfig} from "@chainsafe/lodestar-config"; +import {Dispatch} from "redux"; +import {CgPrysmEth2BeaconApi} from "./CgPrysmEth2BeaconApi"; +import {CgPrysmEth2ValidatorApi} from "./CgPrysmEth2ValidatorApi"; +import {CgPrysmEth2NodeApi} from "./CgPrysmEth2NodeApi"; +import {CgPrysmEth2EventsApi} from "./CgPrysmEth2EventsApi"; +import {IEventsApi} from "@chainsafe/lodestar-validator/lib/api/interface/events"; + +export class CgPrysmEth2Api extends CgEth2ApiClient { + public constructor( + config: IBeaconConfig, + url: string, + {publicKey, dispatch}: {publicKey?: string; dispatch?: Dispatch} = {}, + ) { + super(config, url, {publicKey, dispatch}); + + this.validator = new CgPrysmEth2ValidatorApi(config, this.httpClient); + this.beacon = new CgPrysmEth2BeaconApi(config, this.httpClient, publicKey, dispatch); + this.node = new CgPrysmEth2NodeApi(config, this.httpClient); + this.events = (new CgPrysmEth2EventsApi(config, url) as unknown) as IEventsApi; + + // TODO: implement class "CgEth2Config(config, this.httpClient)" + } +} diff --git a/src/renderer/services/eth2/client/prysm/map.types.ts b/src/renderer/services/eth2/client/prysm/map.types.ts new file mode 100644 index 000000000..4e7175060 --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/map.types.ts @@ -0,0 +1,111 @@ +/* eslint-disable @typescript-eslint/interface-name-prefix */ +/* eslint-disable camelcase */ + +export type SignedBeaconBlockData = { + message: Block; + signature: string; +}; + +export interface Block { + slot: string; + proposer_index: string; + parent_root: string; + state_root: string; + body: Body; +} + +export interface Body { + randao_reveal: string; + eth1_data: Eth1Data; + graffiti: string; + proposer_slashings: ProposerSlashing[]; + attester_slashings: AttestationSlashing[]; + attestations: Attestation[]; + deposits: Deposit[]; + voluntary_exits: VoluntaryExit[]; +} + +export interface Eth1Data { + deposit_root: string; + deposit_count: string; + block_hash: string; +} + +export interface ProposerSlashing { + signed_header_1: SignedHeader; + signed_header_2: SignedHeader; +} + +export interface SignedHeader { + message: SignedHeaderMessage; + signature: string; +} + +export interface SignedHeaderMessage { + slot: string; + proposer_index: string; + parent_root: string; + state_root: string; + body_root: string; +} + +export interface AttestationSlashing { + attestation_1: AttestationSlashingAttestation; + attestation_2: AttestationSlashingAttestation; +} + +export interface AttestationSlashingAttestation { + attesting_indices?: string[] | null; + signature: string; + data: AttestationData; +} + +export interface AttestationData { + slot: string; + index: string; + beacon_block_root: string; + source: SourceOrTarget; + target: SourceOrTarget; +} + +export interface SourceOrTarget { + epoch: string; + root: string; +} + +export interface Attestation { + aggregation_bits: string; + signature: string; + data: AttestationData; +} + +export interface Deposit { + proof?: string[] | null; + data: DepositData; +} + +export interface DepositData { + pubkey: string; + withdrawal_credentials: string; + amount: string; + signature: string; +} + +export interface VoluntaryExit { + message: VoluntaryExitMessage; + signature: string; +} + +export interface VoluntaryExitMessage { + epoch: string; + validator_index: string; +} + +export interface SignedAggregateAndProof { + message: { + aggregator_index: string; + aggregate: Attestation; + selection_proof: string; + }; + signature: string; +} diff --git a/src/renderer/services/eth2/client/prysm/mapProduceBlockDataToPrysmProduceBlock.ts b/src/renderer/services/eth2/client/prysm/mapProduceBlockDataToPrysmProduceBlock.ts new file mode 100644 index 000000000..d466064ec --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/mapProduceBlockDataToPrysmProduceBlock.ts @@ -0,0 +1,117 @@ +import { + AttestationSlashingAttestation, + Attestation, + AttestationSlashing, + AttestationData, + Deposit, + ProposerSlashing, + SignedBeaconBlockData, + SignedHeader, + VoluntaryExit, +} from "./map.types"; +import { + Attestation as PrysmAttestation, + AttestationData as PrysmAttestationData, + AttesterSlashing as PrysmAttesterSlashing, + Deposit as PrysmDeposit, + IndexedAttestation as PrysmIndexedAttestation, + ProposerSlashing as PrysmProposerSlashing, + SignedBeaconBlockHeader as PrysmSignedBeaconBlockHeader, + SignedVoluntaryExit as PrysmSignedVoluntaryExit, + SignedBeaconBlock, +} from "./types"; +import {hexToBase64} from "./utils"; + +/* eslint-disable camelcase */ +/* eslint-disable @typescript-eslint/camelcase */ + +export const mapProduceBlockDataToPrysmProduceBlock = (data: SignedBeaconBlockData): SignedBeaconBlock => ({ + block: { + slot: data.message.slot, + proposerIndex: data.message.proposer_index, + parentRoot: hexToBase64(data.message.parent_root), + stateRoot: hexToBase64(data.message.state_root), + body: { + randaoReveal: hexToBase64(data.message.body.randao_reveal), + eth1Data: { + depositRoot: hexToBase64(data.message.body.eth1_data.deposit_root), + depositCount: data.message.body.eth1_data.deposit_count, + blockHash: hexToBase64(data.message.body.eth1_data.block_hash), + }, + graffiti: hexToBase64(data.message.body.graffiti), + proposerSlashings: data.message.body.proposer_slashings.map(mapProposerSlashing), + attesterSlashings: data.message.body.attester_slashings.map(mapAttesterSlashing), + attestations: data.message.body.attestations.map(mapAttestation), + deposits: data.message.body.deposits.map(mapDeposit), + voluntaryExits: data.message.body.voluntary_exits.map(mapVoluntaryExit), + }, + }, + signature: hexToBase64(data.signature), +}); + +export const mapProposerSlashing = (proposerSlashing: ProposerSlashing): PrysmProposerSlashing => ({ + header1: mapSignedHeader(proposerSlashing.signed_header_1), + header2: mapSignedHeader(proposerSlashing.signed_header_2), +}); + +export const mapSignedHeader = (signedHeader: SignedHeader): PrysmSignedBeaconBlockHeader => ({ + header: { + slot: signedHeader.message.slot, + proposerIndex: signedHeader.message.proposer_index, + parentRoot: hexToBase64(signedHeader.message.parent_root), + stateRoot: hexToBase64(signedHeader.message.state_root), + bodyRoot: hexToBase64(signedHeader.message.body_root), + }, + signature: hexToBase64(signedHeader.signature), +}); + +export const mapAttesterSlashing = (attesterSlashing: AttestationSlashing): PrysmAttesterSlashing => ({ + attestation1: mapAttesterSlashingAttestation(attesterSlashing.attestation_1), + attestation2: mapAttesterSlashingAttestation(attesterSlashing.attestation_2), +}); + +export const mapAttesterSlashingAttestation = ( + attesterSlashing: AttestationSlashingAttestation, +): PrysmIndexedAttestation => ({ + attestingIndices: attesterSlashing.attesting_indices || [], + data: mapAttestationData(attesterSlashing.data), + signature: hexToBase64(attesterSlashing.signature), +}); + +export const mapAttestation = (attestation: Attestation): PrysmAttestation => ({ + aggregationBits: hexToBase64(attestation.aggregation_bits), + data: mapAttestationData(attestation.data), + signature: hexToBase64(attestation.signature), +}); + +export const mapAttestationData = (data: AttestationData): PrysmAttestationData => ({ + slot: data.slot, + committeeIndex: data.index, + beaconBlockRoot: hexToBase64(data.beacon_block_root), + source: { + epoch: data.source.epoch, + root: hexToBase64(data.source.root), + }, + target: { + epoch: data.target.epoch, + root: hexToBase64(data.target.root), + }, +}); + +export const mapDeposit = (deposit: Deposit): PrysmDeposit => ({ + proof: deposit.proof || [], + data: { + publicKey: hexToBase64(deposit.data.pubkey), + withdrawalCredentials: hexToBase64(deposit.data.withdrawal_credentials), + amount: deposit.data.amount, + signature: hexToBase64(deposit.data.signature), + }, +}); + +export const mapVoluntaryExit = (voluntaryExit: VoluntaryExit): PrysmSignedVoluntaryExit => ({ + exit: { + epoch: voluntaryExit.message.epoch, + validatorIndex: voluntaryExit.message.validator_index, + }, + signature: hexToBase64(voluntaryExit.signature), +}); diff --git a/src/renderer/services/eth2/client/prysm/mapProduceBlockResponseToStandardProduceBlock.ts b/src/renderer/services/eth2/client/prysm/mapProduceBlockResponseToStandardProduceBlock.ts new file mode 100644 index 000000000..873d491f2 --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/mapProduceBlockResponseToStandardProduceBlock.ts @@ -0,0 +1,115 @@ +import { + Attestation as PrysmAttestation, + AttestationData as PrysmAttestationData, + AttesterSlashing as PrysmAttesterSlashing, + Deposit as PrysmDeposit, + BeaconBlock as PrysmBeaconBlock, + IndexedAttestation as PrysmIndexedAttestation, + ProposerSlashing as PrysmProposerSlashing, + SignedBeaconBlockHeader as PrysmSignedBeaconBlockHeader, + SignedVoluntaryExit as PrysmSignedVoluntaryExit, +} from "./types"; +import {base64ToHex} from "./utils"; +import { + ProposerSlashing, + SignedHeader, + AttestationSlashing, + AttestationSlashingAttestation, + Attestation, + AttestationData, + Deposit, + VoluntaryExit, +} from "./map.types"; +import {Json} from "@chainsafe/ssz"; + +/* eslint-disable camelcase */ +/* eslint-disable @typescript-eslint/camelcase */ + +export const mapProduceBlockResponseToStandardProduceBlock = (data: PrysmBeaconBlock): Json /*Block*/ => + (({ + slot: data.slot, + proposer_index: data.proposerIndex, + parent_root: base64ToHex(data.parentRoot), + state_root: base64ToHex(data.stateRoot), + body: { + randao_reveal: base64ToHex(data.body.randaoReveal), + graffiti: base64ToHex(data.body.graffiti), + eth1_data: { + deposit_root: base64ToHex(data.body.eth1Data.depositRoot), + deposit_count: data.body.eth1Data.depositCount, + block_hash: base64ToHex(data.body.eth1Data.blockHash), + }, + proposer_slashings: data.body.proposerSlashings.map(mapProposerSlashing), + attester_slashings: data.body.attesterSlashings.map(mapAttesterSlashing), + attestations: data.body.attestations.map(mapAttestation), + deposits: data.body.deposits.map(mapDeposit), + voluntary_exits: data.body.voluntaryExits.map(mapVoluntaryExit), + }, + } as unknown) as Json); + +export const mapProposerSlashing = (proposerSlashing: PrysmProposerSlashing): ProposerSlashing => ({ + signed_header_1: mapSignedHeader(proposerSlashing.header1), + signed_header_2: mapSignedHeader(proposerSlashing.header2), +}); + +export const mapSignedHeader = (signedHeader: PrysmSignedBeaconBlockHeader): SignedHeader => ({ + message: { + slot: signedHeader.header.slot, + proposer_index: signedHeader.header.proposerIndex, + parent_root: base64ToHex(signedHeader.header.parentRoot), + state_root: base64ToHex(signedHeader.header.stateRoot), + body_root: base64ToHex(signedHeader.header.bodyRoot), + }, + signature: base64ToHex(signedHeader.signature), +}); + +export const mapAttesterSlashing = (attesterSlashing: PrysmAttesterSlashing): AttestationSlashing => ({ + attestation_1: mapAttesterSlashingAttestation(attesterSlashing.attestation1), + attestation_2: mapAttesterSlashingAttestation(attesterSlashing.attestation2), +}); + +export const mapAttesterSlashingAttestation = ( + attesterSlashing: PrysmIndexedAttestation, +): AttestationSlashingAttestation => ({ + attesting_indices: attesterSlashing.attestingIndices || [], + signature: base64ToHex(attesterSlashing.signature), + data: mapAttestationData(attesterSlashing.data), +}); + +export const mapAttestation = (attestation: PrysmAttestation): Attestation => ({ + aggregation_bits: base64ToHex(attestation.aggregationBits), + signature: base64ToHex(attestation.signature), + data: mapAttestationData(attestation.data), +}); + +export const mapAttestationData = (data: PrysmAttestationData): AttestationData => ({ + slot: data.slot, + index: data.committeeIndex, + beacon_block_root: base64ToHex(data.beaconBlockRoot), + source: { + epoch: data.source.epoch, + root: base64ToHex(data.source.root), + }, + target: { + epoch: data.target.epoch, + root: base64ToHex(data.target.root), + }, +}); + +export const mapDeposit = (deposit: PrysmDeposit): Deposit => ({ + proof: deposit.proof || [], + data: { + pubkey: base64ToHex(deposit.data.publicKey), + withdrawal_credentials: base64ToHex(deposit.data.withdrawalCredentials), + amount: deposit.data.amount, + signature: base64ToHex(deposit.data.signature), + }, +}); + +export const mapVoluntaryExit = (voluntaryExit: PrysmSignedVoluntaryExit): VoluntaryExit => ({ + message: { + epoch: voluntaryExit.exit.epoch, + validator_index: voluntaryExit.exit.epoch, + }, + signature: base64ToHex(voluntaryExit.signature), +}); diff --git a/src/renderer/services/eth2/client/prysm/types.ts b/src/renderer/services/eth2/client/prysm/types.ts new file mode 100644 index 000000000..e8f7a5500 --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/types.ts @@ -0,0 +1,182 @@ +export type Assignments = { + epoch: string; + assignments: { + beaconCommittees: string[]; + committeeIndex: string; + attesterSlot: string; + proposerSlots: string[]; + publicKey: string; + validatorIndex: string; + }[]; + nextPageToken: string; + totalSize: number; +}; + +export type Duty = { + committee: string[]; + committeeIndex: string; + attesterSlot: string; + proposerSlots: string[]; + publicKey: string; + validatorIndex: string; + status: string; +}; + +export type DutiesResponse = { + currentEpochDuties: Duty[]; + nextEpochDuties: Duty[]; +}; + +export type ValidatorStatusResponse = { + publicKey: string; + withdrawalCredentials: string; + effectiveBalance: string; + slashed: boolean; + activationEligibilityEpoch: string; + activationEpoch: string; + exitEpoch: string; + withdrawableEpoch: string; +}; + +export type ValidatorStateResponse = { + status: string; + eth1DepositBlockNumber: string; + depositInclusionSlot: string; + activationEpoch: string; + positionInActivationQueue: string; +}; + +export type BeaconBlock = { + slot: string; + proposerIndex: string; + parentRoot: string; + stateRoot: string; + body: { + randaoReveal: string; + eth1Data: { + depositRoot: string; + depositCount: string; + blockHash: string; + }; + graffiti: string; + proposerSlashings: ProposerSlashing[]; + attesterSlashings: AttesterSlashing[]; + attestations: Attestation[]; + deposits: Deposit[]; + voluntaryExits: SignedVoluntaryExit[]; + }; +}; + +export type ProposerSlashing = { + header1: SignedBeaconBlockHeader; + header2: SignedBeaconBlockHeader; +}; + +export type SignedBeaconBlockHeader = { + signature: string; + header: BeaconBlockHeader; +}; + +export type BeaconBlockHeader = { + slot: string; + proposerIndex: string; + parentRoot: string; + stateRoot: string; + bodyRoot: string; +}; + +export type AttesterSlashing = { + attestation1: IndexedAttestation; + attestation2: IndexedAttestation; +}; + +export type IndexedAttestation = { + attestingIndices: string[]; + signature: string; + data: AttestationData; +}; + +export type Attestation = { + aggregationBits: string; + data: AttestationData; + signature: string; +}; + +export type AttestationData = { + slot: string; + committeeIndex: string; + beaconBlockRoot: string; + source: Checkpoint; + target: Checkpoint; +}; + +export type Checkpoint = { + epoch: string; + root: string; +}; + +export type Deposit = { + proof: string[]; + data: { + publicKey: string; + withdrawalCredentials: string; + amount: string; + signature: string; + }; +}; + +export type SignedVoluntaryExit = { + exit: VoluntaryExit; + signature: string; +}; + +export type VoluntaryExit = { + epoch: string; + validatorIndex: string; +}; + +export type SignedBeaconBlock = { + block: BeaconBlock; + signature: string; +}; + +export type AggregateAttestationAndProof = { + aggregatorIndex: string; + aggregate: Attestation; + selectionProof: string; +}; + +export type SignedAggregateAttestationAndProof = { + message: AggregateAttestationAndProof; + signature: string; +}; + +export type ChainHead = { + headSlot: string; + headEpoch: string; + headBlockRoot: string; + + finalizedSlot: string; + finalizedEpoch: string; + finalizedBlockRoot: string; + + justifiedSlot: string; + justifiedEpoch: string; + justifiedBlockRoot: string; + + previousJustifiedSlot: string; + previousJustifiedEpoch: string; + previousJustifiedBlockRoot: string; +}; + +export type ListBlocksResponse = { + blockContainers: BeaconBlockContainer[]; + nextPageToken: string; + totalSize: number; +}; + +export type BeaconBlockContainer = { + block: SignedBeaconBlock; + blockRoot: string; + canonical: boolean; +}; diff --git a/src/renderer/services/eth2/client/prysm/utils.ts b/src/renderer/services/eth2/client/prysm/utils.ts new file mode 100644 index 000000000..6f08d625a --- /dev/null +++ b/src/renderer/services/eth2/client/prysm/utils.ts @@ -0,0 +1,2 @@ +export const base64ToHex = (value: string): string => "0x" + Buffer.from(value, "base64").toString("hex"); +export const hexToBase64 = (value: string): string => Buffer.from(value.substring(2), "hex").toString("base64"); diff --git a/src/renderer/services/eth2/client/teku/defaults.ts b/src/renderer/services/eth2/client/teku/defaults.ts index 40e60ea63..f7a6f9ed9 100644 --- a/src/renderer/services/eth2/client/teku/defaults.ts +++ b/src/renderer/services/eth2/client/teku/defaults.ts @@ -7,6 +7,7 @@ export const beaconNode: IDefaultBeaconNodeConfig = { memory: "3500m", owner: "ConsenSys", repo: "teku", + versionPrefix: "", dockerImage: process.env.DOCKER_TEKU_IMAGE, }; diff --git a/src/renderer/services/eth2/client/utils.ts b/src/renderer/services/eth2/client/utils.ts index 62cd00996..a4a064adb 100644 --- a/src/renderer/services/eth2/client/utils.ts +++ b/src/renderer/services/eth2/client/utils.ts @@ -2,7 +2,8 @@ import {INetworkConfig} from "../../interfaces"; import {getNetworkConfig, getNetworkConfigByGenesisVersion} from "../networks"; import {ICgEth2ApiClient} from "./interface"; import {HttpClient} from "../../api"; -import {CgLighthouseEth2Api, CgTekuEth2Api, CgEth2ApiClient} from "./module"; +import {CgLighthouseEth2Api, CgTekuEth2Api, CgEth2ApiClient, CgNimbusEth2Api} from "./module"; +import {CgPrysmEth2Api} from "./prysm"; export function getEth2ApiClient(url: string, network: string): ICgEth2ApiClient | undefined { const networkConfig = getNetworkConfig(network); @@ -31,6 +32,10 @@ export async function getBeaconNodeEth2ApiClient(beaconNodeUrl: string): Promise const version = response.data.version.toLowerCase(); switch (true) { + case version.includes("nimbus"): + return CgNimbusEth2Api; + case version.includes("prysm"): + return CgPrysmEth2Api; case version.includes("lighthouse"): return CgLighthouseEth2Api; case version.includes("teku"): diff --git a/src/renderer/services/utils/githubReleases.ts b/src/renderer/services/utils/githubReleases.ts index 3b9fd6e33..de648ebf1 100644 --- a/src/renderer/services/utils/githubReleases.ts +++ b/src/renderer/services/utils/githubReleases.ts @@ -27,7 +27,7 @@ export const isCurrentOrNewerVersion = (current: string, comparingWith: string): return true; }; -export const getAvailableClientReleases = async (client: string): Promise => { +export const getAvailableClientReleases = async (client: string, versionPrefix: string): Promise => { const { beacon: {dockerImage, owner, repo}, } = getDefaultsForClient(client); @@ -36,11 +36,10 @@ export const getAvailableClientReleases = async (client: string): Promise - !draft && !prerelease && isCurrentOrNewerVersion(currentTag, tag_name), + ({tag_name: tag, draft, prerelease}) => + !draft && !prerelease && isCurrentOrNewerVersion(currentTag, versionPrefix + tag), ) // eslint-disable-next-line camelcase, @typescript-eslint/camelcase - .map(({tag_name}) => dockerImage.split(":")[0] + ":" + tag_name) + .map(({tag_name}) => dockerImage.split(":")[0] + ":" + versionPrefix + tag_name) ); }; diff --git a/teku-testnet.yml b/teku-testnet.yml index a80f0ec79..32088f4e3 100644 --- a/teku-testnet.yml +++ b/teku-testnet.yml @@ -5,7 +5,7 @@ version: '3.6' services: teku: - image: "${DOCKER_TEKU_IMAGE:-consensys/teku:21.2}" + image: "${DOCKER_TEKU_IMAGE:-consensys/teku:21.5}" user: root container_name: "eth2_testnet_teku" volumes: diff --git a/test/components/__snapshots__/Dropdown.spec.tsx.snap b/test/components/__snapshots__/Dropdown.spec.tsx.snap index 2d04a57b6..5b353537b 100644 --- a/test/components/__snapshots__/Dropdown.spec.tsx.snap +++ b/test/components/__snapshots__/Dropdown.spec.tsx.snap @@ -1,7 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Dropdown renders correctly with array of options 1`] = ` -
+
+
/dev/null +if [ ${PIPESTATUS[0]} != 4 ]; then + echo '`getopt --test` failed in this environment.' + exit 1 +fi + +OPTS="ht:n:d:g" +LONGOPTS="help,testnet:,nodes:,data-dir:,with-ganache,stop-at-epoch:,disable-htop,disable-vc,enable-logtrace,log-level:,base-port:,base-rpc-port:,base-metrics-port:,reuse-existing-data-dir,timeout:" + +# default values +TESTNET="1" +NUM_NODES="10" +DATA_DIR="local_testnet_data" +USE_HTOP="0" +USE_VC="1" +USE_GANACHE="0" +LOG_LEVEL="DEBUG" +BASE_PORT="9000" +BASE_METRICS_PORT="8008" +BASE_RPC_PORT="9190" +REUSE_EXISTING_DATA_DIR="0" +ENABLE_LOGTRACE="0" +STOP_AT_EPOCH_FLAG="" +TIMEOUT_DURATION="0" + +print_help() { + cat < [OTHER OPTIONS] -- [BEACON NODE OPTIONS] +E.g.: $(basename "$0") --testnet ${TESTNET} --nodes ${NUM_NODES} --stop-at-epoch 5 --data-dir "${DATA_DIR}" # defaults +CI run: $(basename "$0") --disable-htop -- --verify-finalization + + -h, --help this help message + -t, --testnet testnet number (default: ${TESTNET}) + -n, --nodes number of nodes to launch (default: ${NUM_NODES}) + -g, --with-ganache simulate a genesis event based on a deposit contract + -s, --stop-at-epoch stop simulation at epoch (default: infinite) + -d, --data-dir directory where all the node data and logs will end up + (default: "${DATA_DIR}") + --base-port bootstrap node's Eth2 traffic port (default: ${BASE_PORT}) + --base-rpc-port bootstrap node's RPC port (default: ${BASE_RPC_PORT}) + --base-metrics-port bootstrap node's metrics server port (default: ${BASE_METRICS_PORT}) + --disable-htop don't use "htop" to see the nimbus_beacon_node processes + --disable-vc don't use validator client binaries for validators (by default validators are split 50/50 between beacon nodes and validator clients) + --enable-logtrace display logtrace asr analysis + --log-level set the log level (default: ${LOG_LEVEL}) + --reuse-existing-data-dir instead of deleting and recreating the data dir, keep it and reuse everything we can from it + --timeout timeout in seconds (default: ${TIMEOUT_DURATION} - no timeout) +EOF +} + +! PARSED=$(${GETOPT_BINARY} --options=${OPTS} --longoptions=${LONGOPTS} --name "$0" -- "$@") +if [ ${PIPESTATUS[0]} != 0 ]; then + # getopt has complained about wrong arguments to stdout + exit 1 +fi + +# read getopt's output this way to handle the quoting right +eval set -- "$PARSED" +while true; do + case "$1" in + -h|--help) + print_help + exit + ;; + -t|--testnet) + TESTNET="$2" + shift 2 + ;; + -n|--nodes) + NUM_NODES="$2" + shift 2 + ;; + -d|--data-dir) + DATA_DIR="$2" + shift 2 + ;; + -g|--with-ganache) + USE_GANACHE="1" + shift + ;; + --stop-at-epoch) + STOP_AT_EPOCH_FLAG="--stop-at-epoch=$2" + shift 2 + ;; + --disable-htop) + USE_HTOP="0" + shift + ;; + --disable-vc) + USE_VC="0" + shift + ;; + --enable-logtrace) + ENABLE_LOGTRACE="1" + shift + ;; + --log-level) + LOG_LEVEL="$2" + shift 2 + ;; + --base-port) + BASE_PORT="$2" + shift 2 + ;; + --base-rpc-port) + BASE_RPC_PORT="$2" + shift 2 + ;; + --base-metrics-port) + BASE_METRICS_PORT="$2" + shift 2 + ;; + --reuse-existing-data-dir) + REUSE_EXISTING_DATA_DIR="1" + shift + ;; + --timeout) + TIMEOUT_DURATION="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + echo "argument parsing error" + print_help + exit 1 + esac +done + +# when sourcing env.sh, it will try to execute $@, so empty it +EXTRA_ARGS="$@" +if [[ $# != 0 ]]; then + shift $# +fi +NETWORK="testnet${TESTNET}" + +if [[ "$REUSE_EXISTING_DATA_DIR" == "0" ]]; then + rm -rf "${DATA_DIR}" +fi + +mkdir -m 0700 -p "${DATA_DIR}" + +DEPOSITS_FILE="${DATA_DIR}/validators/deposit_data.json" + +VALIDATORS_DIR="${DATA_DIR}/validators" +mkdir -p "${VALIDATORS_DIR}" + +SECRETS_DIR="${DATA_DIR}/secrets" +mkdir -p "${SECRETS_DIR}" + +NETWORK_DIR="${DATA_DIR}/network_dir" +mkdir -p "${NETWORK_DIR}" + +set -a +source "scripts/${NETWORK}.env" +set +a + +# Windows detection +if uname | grep -qiE "mingw|msys"; then + MAKE="mingw32-make" +else + MAKE="make" +fi + +# number of CPU cores +if uname | grep -qi darwin; then + NPROC="$(sysctl -n hw.logicalcpu)" +else + NPROC="$(nproc)" +fi + +# Build the binaries +BINARIES="nimbus_beacon_node nimbus_signing_process nimbus_validator_client deposit_contract" +if [[ "$ENABLE_LOGTRACE" == "1" ]]; then + BINARIES="${BINARIES} logtrace" +fi +# NETWORK_NIM_FLAGS=$(scripts/load-testnet-nim-flags.sh "${NETWORK}") +# $MAKE -j ${NPROC} LOG_LEVEL="${LOG_LEVEL}" NIMFLAGS="${NIMFLAGS} -d:testnet_servers_image -d:local_testnet ${NETWORK_NIM_FLAGS}" ${BINARIES} + +PIDS="" +WEB3_ARG="" +STATE_SNAPSHOT_ARG="" +BOOTSTRAP_TIMEOUT=30 # in seconds +DEPOSIT_CONTRACT_ADDRESS="0x0000000000000000000000000000000000000000" +DEPOSIT_CONTRACT_BLOCK="0x0000000000000000000000000000000000000000000000000000000000000000" +NETWORK_METADATA_FILE="${DATA_DIR}/network.json" +NUM_JOBS=${NUM_NODES} + +#if [[ "$REUSE_EXISTING_DATA_DIR" == "0" ]]; then +# ~/nimbus-eth2/build/deposit_contract generateSimulationDeposits \ +# --count=${TOTAL_VALIDATORS} \ +# --out-validators-dir="${VALIDATORS_DIR}" \ +# --out-secrets-dir="${SECRETS_DIR}" \ +# --out-deposits-file="${DEPOSITS_FILE}" +#fi + +if [[ $USE_GANACHE == "0" ]]; then + GENESIS_OFFSET=30 + BOOTSTRAP_IP="127.0.0.1" + + ~/nimbus-eth2/build/nimbus_beacon_node createTestnet \ + --data-dir="${DATA_DIR}" \ + --deposits-file="${DEPOSITS_FILE}" \ + --total-validators=${TOTAL_VALIDATORS} \ + --output-genesis="${NETWORK_DIR}/genesis.ssz" \ + --output-bootstrap-file="${NETWORK_DIR}/bootstrap_nodes.txt" \ + --bootstrap-address=${BOOTSTRAP_IP} \ + --bootstrap-port=${BASE_PORT} \ + --netkey-file=network_key.json \ + --insecure-netkey-password=true \ + --genesis-offset=${GENESIS_OFFSET} # Delay in seconds + + STATE_SNAPSHOT_ARG="--finalized-checkpoint-state=${NETWORK_DIR}/genesis.ssz" +else + echo "Launching ganache" + ganache-cli --blockTime 17 --gasLimit 100000000 -e 100000 --verbose > "${DATA_DIR}/log_ganache.txt" 2>&1 & + PIDS="${PIDS},$!" + + WEB3_ARG="--web3-url=ws://localhost:8545" + + echo "Deploying deposit contract" + DEPLOY_CMD_OUTPUT=$(./build/deposit_contract deploy $WEB3_ARG) + # https://stackoverflow.com/questions/918886/how-do-i-split-a-string-on-a-delimiter-in-bash + OUTPUT_PIECES=(${DEPLOY_CMD_OUTPUT//;/ }) + DEPOSIT_CONTRACT_ADDRESS=${OUTPUT_PIECES[0]} + DEPOSIT_CONTRACT_BLOCK=${OUTPUT_PIECES[1]} + + echo Contract deployed at "$DEPOSIT_CONTRACT_ADDRESS":"$DEPOSIT_CONTRACT_BLOCK" + + MIN_DELAY=1 + MAX_DELAY=5 + + BOOTSTRAP_TIMEOUT=$(( MAX_DELAY * TOTAL_VALIDATORS )) + + ./build/deposit_contract sendDeposits \ + --deposits-file="${DEPOSITS_FILE}" \ + --min-delay=$MIN_DELAY --max-delay=$MAX_DELAY \ + $WEB3_ARG \ + --deposit-contract=${DEPOSIT_CONTRACT_ADDRESS} > "${DATA_DIR}/log_deposit_maker.txt" 2>&1 & + + PIDS="${PIDS},$!" +fi + +# ./scripts/make_prometheus_config.sh \ +# --nodes ${NUM_NODES} \ +# --base-metrics-port ${BASE_METRICS_PORT} \ +# --config-file "${DATA_DIR}/prometheus.yml" || true # TODO: this currently fails on macOS, +# # but it can be considered non-critical + +echo Wrote $NETWORK_METADATA_FILE: +tee "$NETWORK_METADATA_FILE" </dev/null || true + pkill -f -P $$ nimbus_validator_client &>/dev/null || true + sleep 2 + pkill -f -9 -P $$ nimbus_beacon_node &>/dev/null || true + pkill -f -9 -P $$ nimbus_validator_client &>/dev/null || true +} +trap 'cleanup' SIGINT SIGTERM EXIT + +dump_logs() { + LOG_LINES=20 + for LOG in "${DATA_DIR}"/logs/log*.txt; do + echo "Last ${LOG_LINES} lines of ${LOG}:" + tail -n ${LOG_LINES} "${LOG}" + echo "======" + done +} + +dump_logtrace() { + if [[ "$ENABLE_LOGTRACE" == "1" ]]; then + find "${DATA_DIR}" -maxdepth 1 -type f -regex '.*/logs/log[0-9]+.txt' | sed -e"s/${DATA_DIR}\//--nodes=/" | sort | xargs ./build/logtrace asr --log-dir="${DATA_DIR}" || true + fi +} + +NODES_WITH_VALIDATORS=${NODES_WITH_VALIDATORS:-1} +BOOTSTRAP_NODE=0 +SYSTEM_VALIDATORS=$(( TOTAL_VALIDATORS - USER_VALIDATORS )) +VALIDATORS_PER_NODE=$(( SYSTEM_VALIDATORS / NODES_WITH_VALIDATORS )) +if [ "${USE_VC:-}" == "1" ]; then + # if using validator client binaries in addition to beacon nodes we will + # split the keys for this instance in half between the BN and the VC + # and the validators for the BNs will be from the first half of all validators + VALIDATORS_PER_NODE=$((VALIDATORS_PER_NODE / 2 )) + NUM_JOBS=$((NUM_JOBS * 2 )) +fi +VALIDATORS_PER_VALIDATOR=$(( (SYSTEM_VALIDATORS / NODES_WITH_VALIDATORS) / 2 )) +VALIDATOR_OFFSET=$((SYSTEM_VALIDATORS / 2)) +BOOTSTRAP_ENR="${DATA_DIR}/node${BOOTSTRAP_NODE}/beacon_node.enr" +NETWORK_KEYFILE="../network_key.json" + +for NUM_NODE in $(seq 0 $(( NUM_NODES - 1 ))); do + if [[ ${NUM_NODE} == ${BOOTSTRAP_NODE} ]]; then + BOOTSTRAP_ARG="--netkey-file=${NETWORK_KEYFILE} --insecure-netkey-password=true" + else + BOOTSTRAP_ARG="--bootstrap-file=${BOOTSTRAP_ENR}" + # Wait for the master node to write out its address file + START_TIMESTAMP=$(date +%s) + while [[ ! -f "${BOOTSTRAP_ENR}" ]]; do + sleep 0.1 + NOW_TIMESTAMP=$(date +%s) + if [[ "$(( NOW_TIMESTAMP - START_TIMESTAMP - GENESIS_OFFSET ))" -ge "$BOOTSTRAP_TIMEOUT" ]]; then + echo "Bootstrap node failed to start in ${BOOTSTRAP_TIMEOUT} seconds. Aborting." + dump_logs + exit 1 + fi + done + fi + + # Copy validators to individual nodes. + # The first $NODES_WITH_VALIDATORS nodes split them equally between them, after skipping the first $USER_VALIDATORS. + NODE_DATA_DIR="${DATA_DIR}/node${NUM_NODE}" + rm -rf "${NODE_DATA_DIR}" + mkdir -m 0700 -p "${NODE_DATA_DIR}" + mkdir -p "${NODE_DATA_DIR}/validators" + mkdir -p "${NODE_DATA_DIR}/secrets" + + if [[ $NUM_NODE -lt $NODES_WITH_VALIDATORS ]]; then + if [ "${USE_VC:-}" == "1" ]; then + VALIDATOR_DATA_DIR="${DATA_DIR}/validator${NUM_NODE}" + rm -rf "${VALIDATOR_DATA_DIR}" + mkdir -p "${VALIDATOR_DATA_DIR}/validators" + mkdir -p "${VALIDATOR_DATA_DIR}/secrets" + + for VALIDATOR in $(ls "${VALIDATORS_DIR}" | tail -n +$(( $USER_VALIDATORS + ($VALIDATORS_PER_VALIDATOR * $NUM_NODE) + 1 + $VALIDATOR_OFFSET )) | head -n $VALIDATORS_PER_VALIDATOR); do + cp -a "${VALIDATORS_DIR}/$VALIDATOR" "${VALIDATOR_DATA_DIR}/validators/" + cp -a "${SECRETS_DIR}/${VALIDATOR}" "${VALIDATOR_DATA_DIR}/secrets/" + done + fi + + for VALIDATOR in $(ls "${VALIDATORS_DIR}" | tail -n +$(( $USER_VALIDATORS + ($VALIDATORS_PER_NODE * $NUM_NODE) + 1 )) | head -n $VALIDATORS_PER_NODE); do + cp -a "${VALIDATORS_DIR}/$VALIDATOR" "${NODE_DATA_DIR}/validators/" + cp -a "${SECRETS_DIR}/${VALIDATOR}" "${NODE_DATA_DIR}/secrets/" + done + fi + + echo "Creating log dir" + rm -rf "${DATA_DIR}/logs" + mkdir -p "${DATA_DIR}/logs" + + echo "Running node" + ~/nimbus-eth2/build/nimbus_beacon_node \ + --non-interactive \ + --nat:extip:127.0.0.1 \ + --network="${NETWORK_METADATA_FILE}" \ + --log-level="${LOG_LEVEL}" \ + --tcp-port=$(( BASE_PORT + NUM_NODE )) \ + --udp-port=$(( BASE_PORT + NUM_NODE )) \ + --max-peers=1 \ + --data-dir="${NODE_DATA_DIR}" \ + ${BOOTSTRAP_ARG} \ + ${STATE_SNAPSHOT_ARG} \ + ${WEB3_ARG} \ + ${STOP_AT_EPOCH_FLAG} \ + --rpc \ + --rpc-address="0.0.0.0" \ + --rpc-port="$(( BASE_RPC_PORT ))" \ + --rest=true \ + --rest-address=0.0.0.0 \ + --metrics \ + --metrics-address="0.0.0.0" \ + --metrics-port="$(( BASE_METRICS_PORT + NUM_NODE ))" \ + --doppelganger-detection=off \ + ${EXTRA_ARGS} \ + > "${DATA_DIR}/logs/log${NUM_NODE}.txt" 2>&1 & + + if [[ "${PIDS}" == "" ]]; then + PIDS="$!" + else + PIDS="${PIDS},$!" + fi + + if [ "${USE_VC:-}" == "1" ]; then + ./build/nimbus_validator_client \ + --log-level="${LOG_LEVEL}" \ + ${STOP_AT_EPOCH_FLAG} \ + --data-dir="${VALIDATOR_DATA_DIR}" \ + --rpc-port="$(( BASE_RPC_PORT + NUM_NODE ))" \ + > "${DATA_DIR}/logs/log_val${NUM_NODE}.txt" 2>&1 & + fi +done + +# give the regular nodes time to crash +sleep 5 +BG_JOBS="$(jobs | wc -l | tr -d ' ')" +if [[ "$BG_JOBS" != "$NUM_JOBS" ]]; then + echo "$(( NUM_JOBS - BG_JOBS )) nimbus_beacon_node/nimbus_validator_client instance(s) exited early. Aborting." + dump_logs + dump_logtrace + exit 1 +fi + +# timeout - implemented with a background job +timeout_reached() { + echo -e "\nTimeout reached. Aborting.\n" + cleanup +} +trap 'timeout_reached' SIGALRM + +if [[ "${TIMEOUT_DURATION}" != "0" ]]; then + export PARENT_PID=$$ + ( sleep ${TIMEOUT_DURATION} && kill -ALRM ${PARENT_PID} ) 2>/dev/null & WATCHER_PID=$! +fi + +# launch htop or wait for background jobs +if [[ "$USE_HTOP" == "1" ]]; then + htop -p "$PIDS" + cleanup +else + FAILED=0 + for PID in $(echo "$PIDS" | tr ',' ' '); do + wait "$PID" || FAILED="$(( FAILED += 1 ))" + done + if [[ "$FAILED" != "0" ]]; then + echo "${FAILED} child processes had non-zero exit codes (or exited early)." + dump_logs + dump_logtrace + if [[ "${TIMEOUT_DURATION}" != "0" ]]; then + pkill -HUP -P ${WATCHER_PID} + fi + exit 1 + fi +fi + +dump_logtrace + +if [[ "${TIMEOUT_DURATION}" != "0" ]]; then + pkill -HUP -P ${WATCHER_PID} +fi diff --git a/testnet/nimbus/secrets/0x8309a5281dd43297a3eccc1e70553831ec4dbf6a0b5b38fc910b49fb4eecf37075c90269443fd5fc6b8cad701e3eec53 b/testnet/nimbus/secrets/0x8309a5281dd43297a3eccc1e70553831ec4dbf6a0b5b38fc910b49fb4eecf37075c90269443fd5fc6b8cad701e3eec53 new file mode 100644 index 000000000..3ea5a03ad --- /dev/null +++ b/testnet/nimbus/secrets/0x8309a5281dd43297a3eccc1e70553831ec4dbf6a0b5b38fc910b49fb4eecf37075c90269443fd5fc6b8cad701e3eec53 @@ -0,0 +1 @@ +4E015C5AF6C9610B0230DBC4FD9714B786F24A28414E49C52D85950E1ED23AD8 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x8377db159c6f19b06bd212017fc249c2f1a3933b1fb0c39013e5d9dcb3d4b4160e8cd90fbcaf3985031508b60a9a0ff5 b/testnet/nimbus/secrets/0x8377db159c6f19b06bd212017fc249c2f1a3933b1fb0c39013e5d9dcb3d4b4160e8cd90fbcaf3985031508b60a9a0ff5 new file mode 100644 index 000000000..a305110e2 --- /dev/null +++ b/testnet/nimbus/secrets/0x8377db159c6f19b06bd212017fc249c2f1a3933b1fb0c39013e5d9dcb3d4b4160e8cd90fbcaf3985031508b60a9a0ff5 @@ -0,0 +1 @@ +D7B9177C2224F7BC661216F62F1B47A325E6215F4208B724E1C6794C17F4FF22 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x842b47897d2f335919df34c989817190fb993965cda53aa73f1633ce581fbfdad7eb64c80ed89fdc85d524f906394217 b/testnet/nimbus/secrets/0x842b47897d2f335919df34c989817190fb993965cda53aa73f1633ce581fbfdad7eb64c80ed89fdc85d524f906394217 new file mode 100644 index 000000000..5d96ff72f --- /dev/null +++ b/testnet/nimbus/secrets/0x842b47897d2f335919df34c989817190fb993965cda53aa73f1633ce581fbfdad7eb64c80ed89fdc85d524f906394217 @@ -0,0 +1 @@ +A7D4740220B16D9DA91DAD3D7AB2DDD99AD1DC0CDF73631276927094D1B8DB7D \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x85c19c2d84f09a1c1e7420713c3d3327a2f80a8c8d012de09881cfdf65a0732ba7908ca9ba7441f25e7896c2174685b8 b/testnet/nimbus/secrets/0x85c19c2d84f09a1c1e7420713c3d3327a2f80a8c8d012de09881cfdf65a0732ba7908ca9ba7441f25e7896c2174685b8 new file mode 100644 index 000000000..879406eb6 --- /dev/null +++ b/testnet/nimbus/secrets/0x85c19c2d84f09a1c1e7420713c3d3327a2f80a8c8d012de09881cfdf65a0732ba7908ca9ba7441f25e7896c2174685b8 @@ -0,0 +1 @@ +B0C2EBE643B963D8A30592F80C4D3CD0ADCE418C27FAC2C2BB6F490F70DC4BC4 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x85c250d005163b8f9e1f1de9a9505727dd349c69c6613494d37b6b1e314727f5e6b80eb32805cc54ac2b851ff75cf275 b/testnet/nimbus/secrets/0x85c250d005163b8f9e1f1de9a9505727dd349c69c6613494d37b6b1e314727f5e6b80eb32805cc54ac2b851ff75cf275 new file mode 100644 index 000000000..1f411bfa7 --- /dev/null +++ b/testnet/nimbus/secrets/0x85c250d005163b8f9e1f1de9a9505727dd349c69c6613494d37b6b1e314727f5e6b80eb32805cc54ac2b851ff75cf275 @@ -0,0 +1 @@ +42F95D02E5778F2A1BA523768D852DEE720801BC7A51069023D379549DE79CE3 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x87a9093b834befae2523c073b34038065b329f85f1ca7c5cd617db78a9e2d27b55aa05bc7422e62510d5a8cf014257e5 b/testnet/nimbus/secrets/0x87a9093b834befae2523c073b34038065b329f85f1ca7c5cd617db78a9e2d27b55aa05bc7422e62510d5a8cf014257e5 new file mode 100644 index 000000000..974925288 --- /dev/null +++ b/testnet/nimbus/secrets/0x87a9093b834befae2523c073b34038065b329f85f1ca7c5cd617db78a9e2d27b55aa05bc7422e62510d5a8cf014257e5 @@ -0,0 +1 @@ +868D0A9AEB24E40F92B0170BF61C2D15D4D45ED9B1AA3A23D39C88A09FA4585C \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x8ab6b5ed1e3cedb684b8b604221567d55ad5b48c4aecf8b23fc988bdc78000ce26f6e0f6efff7ff3557ebbbebd04ef61 b/testnet/nimbus/secrets/0x8ab6b5ed1e3cedb684b8b604221567d55ad5b48c4aecf8b23fc988bdc78000ce26f6e0f6efff7ff3557ebbbebd04ef61 new file mode 100644 index 000000000..887812d86 --- /dev/null +++ b/testnet/nimbus/secrets/0x8ab6b5ed1e3cedb684b8b604221567d55ad5b48c4aecf8b23fc988bdc78000ce26f6e0f6efff7ff3557ebbbebd04ef61 @@ -0,0 +1 @@ +C980122A0DC780C54CE3A62FC3C53A2687C6D04B489B1490727B5B72706EE9D2 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x9364daa6d000495b138c8d80964f3306a32ec85680d1ddd45305f08ecb0f44d32a2e946c226cb070685b41bec663256a b/testnet/nimbus/secrets/0x9364daa6d000495b138c8d80964f3306a32ec85680d1ddd45305f08ecb0f44d32a2e946c226cb070685b41bec663256a new file mode 100644 index 000000000..560247743 --- /dev/null +++ b/testnet/nimbus/secrets/0x9364daa6d000495b138c8d80964f3306a32ec85680d1ddd45305f08ecb0f44d32a2e946c226cb070685b41bec663256a @@ -0,0 +1 @@ +D6F98797B00F5FEB0295ABDB118AC6A2AAFC2A8124A98C8CC3E9805845FD4A5D \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x93737d75235b7ef7ac7422cd31c00afac950b4376e5cf98468e25de6258d2c03a76035df6a6c89c4a015597eb4f0d3fc b/testnet/nimbus/secrets/0x93737d75235b7ef7ac7422cd31c00afac950b4376e5cf98468e25de6258d2c03a76035df6a6c89c4a015597eb4f0d3fc new file mode 100644 index 000000000..b55f05edb --- /dev/null +++ b/testnet/nimbus/secrets/0x93737d75235b7ef7ac7422cd31c00afac950b4376e5cf98468e25de6258d2c03a76035df6a6c89c4a015597eb4f0d3fc @@ -0,0 +1 @@ +8BBB9D0EDBA47B053049F40241B2F1A8AED13E8C053AC43AEA0D893939FD7C54 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x98252a182b4aaf410f066fb9f7bd9ff0ec43f5136cbe92c7d65d5d2831e5a58090ea993a644690c47fc85981eb2e1d2c b/testnet/nimbus/secrets/0x98252a182b4aaf410f066fb9f7bd9ff0ec43f5136cbe92c7d65d5d2831e5a58090ea993a644690c47fc85981eb2e1d2c new file mode 100644 index 000000000..7930bb429 --- /dev/null +++ b/testnet/nimbus/secrets/0x98252a182b4aaf410f066fb9f7bd9ff0ec43f5136cbe92c7d65d5d2831e5a58090ea993a644690c47fc85981eb2e1d2c @@ -0,0 +1 @@ +636A1F97CB5C550DB8061F887D1F9295EA3CCFAA2283DC80D4EF2D9FC026DAAC \ No newline at end of file diff --git a/testnet/nimbus/secrets/0x9997ca462621ba46a5988971bdab4a61a482817172312f96e046c5e364946383573d945c59ab8c1242def7be4b2ec146 b/testnet/nimbus/secrets/0x9997ca462621ba46a5988971bdab4a61a482817172312f96e046c5e364946383573d945c59ab8c1242def7be4b2ec146 new file mode 100644 index 000000000..8bf9f57ab --- /dev/null +++ b/testnet/nimbus/secrets/0x9997ca462621ba46a5988971bdab4a61a482817172312f96e046c5e364946383573d945c59ab8c1242def7be4b2ec146 @@ -0,0 +1 @@ +10CFBD29741D329C2E4EEAAE0B7645FB3ACCB4200CA39F55621F4B848885CACC \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xa34353d86c69fc4ac08698960158a92748b6e25821b31b0c5cd764ff3d6fa5855d9d8d2aacb2260cafc8e2821a0b4343 b/testnet/nimbus/secrets/0xa34353d86c69fc4ac08698960158a92748b6e25821b31b0c5cd764ff3d6fa5855d9d8d2aacb2260cafc8e2821a0b4343 new file mode 100644 index 000000000..c977cd786 --- /dev/null +++ b/testnet/nimbus/secrets/0xa34353d86c69fc4ac08698960158a92748b6e25821b31b0c5cd764ff3d6fa5855d9d8d2aacb2260cafc8e2821a0b4343 @@ -0,0 +1 @@ +FB887682033864CDD15C081503BBF66025010A9DA0A7E07C5CA88DF766BDC405 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xa5451d7b02b2241f0df105288154fcda8517d59a8fc758676c04997c0ab02d8d265e4728970da3d894fc5f5431af4c53 b/testnet/nimbus/secrets/0xa5451d7b02b2241f0df105288154fcda8517d59a8fc758676c04997c0ab02d8d265e4728970da3d894fc5f5431af4c53 new file mode 100644 index 000000000..3aa771bef --- /dev/null +++ b/testnet/nimbus/secrets/0xa5451d7b02b2241f0df105288154fcda8517d59a8fc758676c04997c0ab02d8d265e4728970da3d894fc5f5431af4c53 @@ -0,0 +1 @@ +59A6F8936173FC73B306B19BCC8DFBE704AF2541EEB9940FF5CDDB97D1D85F4E \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xa59df5c2ff63a77317524b71b9be7e74e95d42cc80a0c53bf841eb6355916a7d7d5ffab863db1e263f570ab248b6f27c b/testnet/nimbus/secrets/0xa59df5c2ff63a77317524b71b9be7e74e95d42cc80a0c53bf841eb6355916a7d7d5ffab863db1e263f570ab248b6f27c new file mode 100644 index 000000000..62b3891b0 --- /dev/null +++ b/testnet/nimbus/secrets/0xa59df5c2ff63a77317524b71b9be7e74e95d42cc80a0c53bf841eb6355916a7d7d5ffab863db1e263f570ab248b6f27c @@ -0,0 +1 @@ +DC772BD1FF3F93247A58235C487F6817D934B922BCEF757101CBAA286B37C3C6 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xa5d1f7d985bed2bba07cedd714b078b4cfe6185a246eb277ae68098715bcd24488b0e2dc8d19f4674937cb5656a1d927 b/testnet/nimbus/secrets/0xa5d1f7d985bed2bba07cedd714b078b4cfe6185a246eb277ae68098715bcd24488b0e2dc8d19f4674937cb5656a1d927 new file mode 100644 index 000000000..5e586f4b2 --- /dev/null +++ b/testnet/nimbus/secrets/0xa5d1f7d985bed2bba07cedd714b078b4cfe6185a246eb277ae68098715bcd24488b0e2dc8d19f4674937cb5656a1d927 @@ -0,0 +1 @@ +D687AEF4E234E8DFFF64E9A5C16B4649AA3A13ABC62C79F0A95FA6B074B75532 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xa66a5b7d1dfe156e65f239e885282d7fb1f6879afa483e05092a9001e6228af5ba47573882d9f0e7e8b13685d21a3d0c b/testnet/nimbus/secrets/0xa66a5b7d1dfe156e65f239e885282d7fb1f6879afa483e05092a9001e6228af5ba47573882d9f0e7e8b13685d21a3d0c new file mode 100644 index 000000000..d67b0ec62 --- /dev/null +++ b/testnet/nimbus/secrets/0xa66a5b7d1dfe156e65f239e885282d7fb1f6879afa483e05092a9001e6228af5ba47573882d9f0e7e8b13685d21a3d0c @@ -0,0 +1 @@ +04FDF89ABBE5919D2D55A49894606F5A50D27AFCABBA8E1DC2581CEBBBECF90E \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xa6fc251771b193b3121424b9e5eea580ee4fd7355d3be1e6c6e2aa1155bd8bd247db4d82e6a9a3aab76e8aacbfb00ae1 b/testnet/nimbus/secrets/0xa6fc251771b193b3121424b9e5eea580ee4fd7355d3be1e6c6e2aa1155bd8bd247db4d82e6a9a3aab76e8aacbfb00ae1 new file mode 100644 index 000000000..f3b7d9f69 --- /dev/null +++ b/testnet/nimbus/secrets/0xa6fc251771b193b3121424b9e5eea580ee4fd7355d3be1e6c6e2aa1155bd8bd247db4d82e6a9a3aab76e8aacbfb00ae1 @@ -0,0 +1 @@ +137F694A43F44C20A6252A22D3FA63BD45733AF27E44636792666521552322C3 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xac660a01fdd86fd4bec526c5d1096164e6acd85fe5e738def40d33861a5c57bc7be5fc304304022271f9ea2405214a7c b/testnet/nimbus/secrets/0xac660a01fdd86fd4bec526c5d1096164e6acd85fe5e738def40d33861a5c57bc7be5fc304304022271f9ea2405214a7c new file mode 100644 index 000000000..f5acd4a4f --- /dev/null +++ b/testnet/nimbus/secrets/0xac660a01fdd86fd4bec526c5d1096164e6acd85fe5e738def40d33861a5c57bc7be5fc304304022271f9ea2405214a7c @@ -0,0 +1 @@ +23ED373FDD3B20A4BDDF52ADB5FD24D21F37DD338680FE1D2898D76EAC022B39 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb0e0bb95eabcb2daa1cc931ca15bf9f8e9335f3c131f01d309567039ab52f1c5b8cbfcf6cd5c949708a4d38542e201f4 b/testnet/nimbus/secrets/0xb0e0bb95eabcb2daa1cc931ca15bf9f8e9335f3c131f01d309567039ab52f1c5b8cbfcf6cd5c949708a4d38542e201f4 new file mode 100644 index 000000000..96a8aeb3b --- /dev/null +++ b/testnet/nimbus/secrets/0xb0e0bb95eabcb2daa1cc931ca15bf9f8e9335f3c131f01d309567039ab52f1c5b8cbfcf6cd5c949708a4d38542e201f4 @@ -0,0 +1 @@ +CEEE335DDF6AAF597DA562B38DE8414E2EAC1FAAC15C2678011A8DA7DDCFD048 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb0f33dd02682ac8406aea86ebefe8cdde946f0d840a8442a5ec4496d03fe3c7cd89c4515847721d0fa150005b98f2c3a b/testnet/nimbus/secrets/0xb0f33dd02682ac8406aea86ebefe8cdde946f0d840a8442a5ec4496d03fe3c7cd89c4515847721d0fa150005b98f2c3a new file mode 100644 index 000000000..01e3ef7cc --- /dev/null +++ b/testnet/nimbus/secrets/0xb0f33dd02682ac8406aea86ebefe8cdde946f0d840a8442a5ec4496d03fe3c7cd89c4515847721d0fa150005b98f2c3a @@ -0,0 +1 @@ +CC64A371FF318E427EE9B0B41BAF74CEAB9AF0758FC1ADB6721B2186F96AE2FE \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb0f464fe938e9279ddf6cd4072285363984f93c8d6bfd5e7ce94124d54fa16bce96fe0452173d5ecd2fed6b61f116c0b b/testnet/nimbus/secrets/0xb0f464fe938e9279ddf6cd4072285363984f93c8d6bfd5e7ce94124d54fa16bce96fe0452173d5ecd2fed6b61f116c0b new file mode 100644 index 000000000..1d69a3bc1 --- /dev/null +++ b/testnet/nimbus/secrets/0xb0f464fe938e9279ddf6cd4072285363984f93c8d6bfd5e7ce94124d54fa16bce96fe0452173d5ecd2fed6b61f116c0b @@ -0,0 +1 @@ +BB959F61D806884FD967A1760299936ED7269CF31EDA50BCC168ADDB539D5E0D \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb15be8807d46e9bb9428a5442cb994c1ebe5f77459df518dc62cf38e9c291a0b0f9ade6a336841e247d55b8a372edcb9 b/testnet/nimbus/secrets/0xb15be8807d46e9bb9428a5442cb994c1ebe5f77459df518dc62cf38e9c291a0b0f9ade6a336841e247d55b8a372edcb9 new file mode 100644 index 000000000..2f81db0e9 --- /dev/null +++ b/testnet/nimbus/secrets/0xb15be8807d46e9bb9428a5442cb994c1ebe5f77459df518dc62cf38e9c291a0b0f9ade6a336841e247d55b8a372edcb9 @@ -0,0 +1 @@ +F62CE401424EC4A201ED0E34EDCC0BD8AE0B336E3EC39FF0BA2B40F2FAE1A74B \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb1b0f384a1057a2411c81f7c1555ffdc2e2b245198614cb77af40c8772630e5057c9d691fd6ab0fe74d837680011f996 b/testnet/nimbus/secrets/0xb1b0f384a1057a2411c81f7c1555ffdc2e2b245198614cb77af40c8772630e5057c9d691fd6ab0fe74d837680011f996 new file mode 100644 index 000000000..b2f12310f --- /dev/null +++ b/testnet/nimbus/secrets/0xb1b0f384a1057a2411c81f7c1555ffdc2e2b245198614cb77af40c8772630e5057c9d691fd6ab0fe74d837680011f996 @@ -0,0 +1 @@ +7E7DEDD06E35C72D4B2D929A467CBF69227A52F1CFC17226F3073C756044A187 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb1c355f22b9b9c34ceeeaddfe2a58ccf3122c8706b0fb85bb925a57d7a2a78b1bb191e3062381485e2884eb3ee3956c9 b/testnet/nimbus/secrets/0xb1c355f22b9b9c34ceeeaddfe2a58ccf3122c8706b0fb85bb925a57d7a2a78b1bb191e3062381485e2884eb3ee3956c9 new file mode 100644 index 000000000..421a3e12c --- /dev/null +++ b/testnet/nimbus/secrets/0xb1c355f22b9b9c34ceeeaddfe2a58ccf3122c8706b0fb85bb925a57d7a2a78b1bb191e3062381485e2884eb3ee3956c9 @@ -0,0 +1 @@ +FD6D25237983ACBABC68FFB213C51BD5F8163F99BE37687D4829264AB79A5409 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb3386a09faa3be115be868f91fbf40578e5348939c8334972c0b8fe1863de41054df0cec5c2d5afd3c8626dbd9cce3aa b/testnet/nimbus/secrets/0xb3386a09faa3be115be868f91fbf40578e5348939c8334972c0b8fe1863de41054df0cec5c2d5afd3c8626dbd9cce3aa new file mode 100644 index 000000000..a7b1fcad4 --- /dev/null +++ b/testnet/nimbus/secrets/0xb3386a09faa3be115be868f91fbf40578e5348939c8334972c0b8fe1863de41054df0cec5c2d5afd3c8626dbd9cce3aa @@ -0,0 +1 @@ +AB415DE06F28A380120F482313E8BD66A4D30F6797889F3F0D5D1E562A9860E9 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb45f3c2d53c92b1cc6437548ccd8f2bc7b180455536d1ef0f1f3188fb91645a3c69c9832aea408fada4931a95944df1e b/testnet/nimbus/secrets/0xb45f3c2d53c92b1cc6437548ccd8f2bc7b180455536d1ef0f1f3188fb91645a3c69c9832aea408fada4931a95944df1e new file mode 100644 index 000000000..4c481b20e --- /dev/null +++ b/testnet/nimbus/secrets/0xb45f3c2d53c92b1cc6437548ccd8f2bc7b180455536d1ef0f1f3188fb91645a3c69c9832aea408fada4931a95944df1e @@ -0,0 +1 @@ +7DBCD35ADA629BE901D0DCB46AC38B684FE5D1F6690188B35876CC38816A6318 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb48cca1ccf42383065abd73587b1e93cca15fe02900611e7428aad67c4222a701e44e199ab0b488251b90083d297f75a b/testnet/nimbus/secrets/0xb48cca1ccf42383065abd73587b1e93cca15fe02900611e7428aad67c4222a701e44e199ab0b488251b90083d297f75a new file mode 100644 index 000000000..70966c258 --- /dev/null +++ b/testnet/nimbus/secrets/0xb48cca1ccf42383065abd73587b1e93cca15fe02900611e7428aad67c4222a701e44e199ab0b488251b90083d297f75a @@ -0,0 +1 @@ +566419BEB3AAB4AF33193B93D1E7863EB5F7612EB99B67C119F1D2D5DF6EB61C \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb6bcf566c45bef5607d95865757c02a2153f7bd858d036665dc835a0cceff60a6403bf4d21627600d078ff6c7e4d8b53 b/testnet/nimbus/secrets/0xb6bcf566c45bef5607d95865757c02a2153f7bd858d036665dc835a0cceff60a6403bf4d21627600d078ff6c7e4d8b53 new file mode 100644 index 000000000..17e2cf257 --- /dev/null +++ b/testnet/nimbus/secrets/0xb6bcf566c45bef5607d95865757c02a2153f7bd858d036665dc835a0cceff60a6403bf4d21627600d078ff6c7e4d8b53 @@ -0,0 +1 @@ +DB3921D3AB6579BF7DF92E49B8A4E737EE71C42961B070235C6CB54D891EBCD8 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb7a0c7c0bd0a57f1a898c1e94d81248aef4c8855f29c49ebda35c5e982e67662b4a1709a88584a819a9eb7cf97bb9191 b/testnet/nimbus/secrets/0xb7a0c7c0bd0a57f1a898c1e94d81248aef4c8855f29c49ebda35c5e982e67662b4a1709a88584a819a9eb7cf97bb9191 new file mode 100644 index 000000000..126951476 --- /dev/null +++ b/testnet/nimbus/secrets/0xb7a0c7c0bd0a57f1a898c1e94d81248aef4c8855f29c49ebda35c5e982e67662b4a1709a88584a819a9eb7cf97bb9191 @@ -0,0 +1 @@ +8EE726F600742DA80EF99650D6072776F09ED6FDE1AEAC73AB4D6B07B72EA9D6 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb7ad82481970ed4f05b4ca53620bc6ac34c9b5a472ad69f74e6b09e52046d450879c4accec0b65b567cb685b28443531 b/testnet/nimbus/secrets/0xb7ad82481970ed4f05b4ca53620bc6ac34c9b5a472ad69f74e6b09e52046d450879c4accec0b65b567cb685b28443531 new file mode 100644 index 000000000..4b0c8fd7e --- /dev/null +++ b/testnet/nimbus/secrets/0xb7ad82481970ed4f05b4ca53620bc6ac34c9b5a472ad69f74e6b09e52046d450879c4accec0b65b567cb685b28443531 @@ -0,0 +1 @@ +BC39D9D7FE2518E8C2D63441D9F9E2D322D600FCCCF55D4597CEE1E3C94200A7 \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb91d92c0e32cd11fd729929919ff8e0976b3961a32062d992361d5104e5a1afaabeb811b4791ed39ba849799e6a15b1a b/testnet/nimbus/secrets/0xb91d92c0e32cd11fd729929919ff8e0976b3961a32062d992361d5104e5a1afaabeb811b4791ed39ba849799e6a15b1a new file mode 100644 index 000000000..e87f14fa0 --- /dev/null +++ b/testnet/nimbus/secrets/0xb91d92c0e32cd11fd729929919ff8e0976b3961a32062d992361d5104e5a1afaabeb811b4791ed39ba849799e6a15b1a @@ -0,0 +1 @@ +19821BC0A2B4852E14E1EB80C7BC6B846F125EBA3565262A42EDACDD1EB78A6A \ No newline at end of file diff --git a/testnet/nimbus/secrets/0xb93b74b64c52238777eae5ad0f0c79eca42ca6a053f233dd55a907ae58f5614313cd80f71bdb5184d02f5209379d2fdb b/testnet/nimbus/secrets/0xb93b74b64c52238777eae5ad0f0c79eca42ca6a053f233dd55a907ae58f5614313cd80f71bdb5184d02f5209379d2fdb new file mode 100644 index 000000000..ab796b007 --- /dev/null +++ b/testnet/nimbus/secrets/0xb93b74b64c52238777eae5ad0f0c79eca42ca6a053f233dd55a907ae58f5614313cd80f71bdb5184d02f5209379d2fdb @@ -0,0 +1 @@ +7D43C77CF0E832448EAB86B200B29923193D16FE6211052FA6F136999C7B7485 \ No newline at end of file diff --git a/testnet/nimbus/testnet1.env b/testnet/nimbus/testnet1.env new file mode 100644 index 000000000..3e7fec537 --- /dev/null +++ b/testnet/nimbus/testnet1.env @@ -0,0 +1,4 @@ +CONST_PRESET=mainnet +USER_VALIDATORS=1 +TOTAL_VALIDATORS=32 +BOOTSTRAP_PORT=9100 diff --git a/testnet/nimbus/validators/0x8309a5281dd43297a3eccc1e70553831ec4dbf6a0b5b38fc910b49fb4eecf37075c90269443fd5fc6b8cad701e3eec53/keystore.json b/testnet/nimbus/validators/0x8309a5281dd43297a3eccc1e70553831ec4dbf6a0b5b38fc910b49fb4eecf37075c90269443fd5fc6b8cad701e3eec53/keystore.json new file mode 100644 index 000000000..8c5d9edc2 --- /dev/null +++ b/testnet/nimbus/validators/0x8309a5281dd43297a3eccc1e70553831ec4dbf6a0b5b38fc910b49fb4eecf37075c90269443fd5fc6b8cad701e3eec53/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"394aa7bf7b8543bec9328678fabbb82b1d88b651a1629992c596011c87035ee0"},"message":""},"checksum":{"function":"sha256","params":{},"message":"4e1093d856e9cfa77b2ef37e49d96e248aa2b88be51c542a1a5c295f97eb30c2"},"cipher":{"function":"aes-128-ctr","params":{"iv":"8fa9958ef656695f12e3999d869d291e"},"message":"5869a4b6f5bab27676d6212737afbdedf5823ecb522ea88a72322c50a2f4c392"}},"description":"","pubkey":"8309a5281dd43297a3eccc1e70553831ec4dbf6a0b5b38fc910b49fb4eecf37075c90269443fd5fc6b8cad701e3eec53","path":"m/12381/3600/29/0/0","uuid":"97ee5497-09d8-489b-af81-e060358f5d5c","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x8377db159c6f19b06bd212017fc249c2f1a3933b1fb0c39013e5d9dcb3d4b4160e8cd90fbcaf3985031508b60a9a0ff5/keystore.json b/testnet/nimbus/validators/0x8377db159c6f19b06bd212017fc249c2f1a3933b1fb0c39013e5d9dcb3d4b4160e8cd90fbcaf3985031508b60a9a0ff5/keystore.json new file mode 100644 index 000000000..951f937a9 --- /dev/null +++ b/testnet/nimbus/validators/0x8377db159c6f19b06bd212017fc249c2f1a3933b1fb0c39013e5d9dcb3d4b4160e8cd90fbcaf3985031508b60a9a0ff5/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"380f98b0134c3d3c38983da79c2265d93882449bad5944257c80048d10c4de9d"},"message":""},"checksum":{"function":"sha256","params":{},"message":"25303793dcf4ef306e8b9d7e46170f4e6c2918317be5d394c09a123cd7546114"},"cipher":{"function":"aes-128-ctr","params":{"iv":"db2b37badb1b2975cf3bb71346d41c35"},"message":"2255f2bd6f0d695d79546916be79304c02af79c5693798a7042afb1281d4fa6f"}},"description":"","pubkey":"8377db159c6f19b06bd212017fc249c2f1a3933b1fb0c39013e5d9dcb3d4b4160e8cd90fbcaf3985031508b60a9a0ff5","path":"m/12381/3600/15/0/0","uuid":"67577eeb-ac81-4165-abde-e1c523280a24","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x842b47897d2f335919df34c989817190fb993965cda53aa73f1633ce581fbfdad7eb64c80ed89fdc85d524f906394217/keystore.json b/testnet/nimbus/validators/0x842b47897d2f335919df34c989817190fb993965cda53aa73f1633ce581fbfdad7eb64c80ed89fdc85d524f906394217/keystore.json new file mode 100644 index 000000000..002a5d3d9 --- /dev/null +++ b/testnet/nimbus/validators/0x842b47897d2f335919df34c989817190fb993965cda53aa73f1633ce581fbfdad7eb64c80ed89fdc85d524f906394217/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"3a45176404f32e58d4402019201104d1b7483d36185d226877e9102638f52c0a"},"message":""},"checksum":{"function":"sha256","params":{},"message":"f584e56d4d8f6774eb5f1c41d1a3ceb42792c270ab15e3ac9f3739bc503db619"},"cipher":{"function":"aes-128-ctr","params":{"iv":"04aa436ac0f39c6c32dd3e020e3f1503"},"message":"b8e084c73c052afb44fbf4da724bb7238457fd0714d72dd508af21b9a65761ec"}},"description":"","pubkey":"842b47897d2f335919df34c989817190fb993965cda53aa73f1633ce581fbfdad7eb64c80ed89fdc85d524f906394217","path":"m/12381/3600/11/0/0","uuid":"1ef5fadf-bbd6-4d06-becb-8d2245e42a79","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x85c19c2d84f09a1c1e7420713c3d3327a2f80a8c8d012de09881cfdf65a0732ba7908ca9ba7441f25e7896c2174685b8/keystore.json b/testnet/nimbus/validators/0x85c19c2d84f09a1c1e7420713c3d3327a2f80a8c8d012de09881cfdf65a0732ba7908ca9ba7441f25e7896c2174685b8/keystore.json new file mode 100644 index 000000000..0cc9481df --- /dev/null +++ b/testnet/nimbus/validators/0x85c19c2d84f09a1c1e7420713c3d3327a2f80a8c8d012de09881cfdf65a0732ba7908ca9ba7441f25e7896c2174685b8/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"ace782e81b2ffbb46f60409dde4d56cdb2568cdf4b5fca2bc6592fd1afca23fe"},"message":""},"checksum":{"function":"sha256","params":{},"message":"6b6dcf9c93985a722e7d3a0cdeea60bd1427f7397874e5ae569f52d9c95c1e77"},"cipher":{"function":"aes-128-ctr","params":{"iv":"39bbf0415d1faf53bcd90abb86945f1d"},"message":"0664ccfe59acc844f608220f885b4ead270311baa289cfecda16796ea00d3a48"}},"description":"","pubkey":"85c19c2d84f09a1c1e7420713c3d3327a2f80a8c8d012de09881cfdf65a0732ba7908ca9ba7441f25e7896c2174685b8","path":"m/12381/3600/3/0/0","uuid":"864b9e8b-d6ba-40dd-aef6-e9711c46225c","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x85c250d005163b8f9e1f1de9a9505727dd349c69c6613494d37b6b1e314727f5e6b80eb32805cc54ac2b851ff75cf275/keystore.json b/testnet/nimbus/validators/0x85c250d005163b8f9e1f1de9a9505727dd349c69c6613494d37b6b1e314727f5e6b80eb32805cc54ac2b851ff75cf275/keystore.json new file mode 100644 index 000000000..a28ca7f87 --- /dev/null +++ b/testnet/nimbus/validators/0x85c250d005163b8f9e1f1de9a9505727dd349c69c6613494d37b6b1e314727f5e6b80eb32805cc54ac2b851ff75cf275/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"e527e4fcad2bf1af3a8f0df5fab0cc762097ef08aa0ce576d55ecd0c0bf6d6a0"},"message":""},"checksum":{"function":"sha256","params":{},"message":"656417d1e6daf15d41831d81b363d9ebd47a36c537b06374d922b1c32b904519"},"cipher":{"function":"aes-128-ctr","params":{"iv":"da3be0aac42a3a2dd22c94b4fa9abd32"},"message":"d6199321f31653028ad93b1e8deda2937418aabf2e6a3ccea4823da90c39562e"}},"description":"","pubkey":"85c250d005163b8f9e1f1de9a9505727dd349c69c6613494d37b6b1e314727f5e6b80eb32805cc54ac2b851ff75cf275","path":"m/12381/3600/10/0/0","uuid":"b5ef0bf4-42e8-4524-9d1d-bd8dcfac8848","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x87a9093b834befae2523c073b34038065b329f85f1ca7c5cd617db78a9e2d27b55aa05bc7422e62510d5a8cf014257e5/keystore.json b/testnet/nimbus/validators/0x87a9093b834befae2523c073b34038065b329f85f1ca7c5cd617db78a9e2d27b55aa05bc7422e62510d5a8cf014257e5/keystore.json new file mode 100644 index 000000000..c64a7fda8 --- /dev/null +++ b/testnet/nimbus/validators/0x87a9093b834befae2523c073b34038065b329f85f1ca7c5cd617db78a9e2d27b55aa05bc7422e62510d5a8cf014257e5/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"580ea333b30120f202241e77e5cb3ef2edc3c7372141d8d8d497432de8eb650a"},"message":""},"checksum":{"function":"sha256","params":{},"message":"c7dd40193bbff13b5024712d0335c7fc1063c424b621062d618e0dd09654853d"},"cipher":{"function":"aes-128-ctr","params":{"iv":"d67318327a5faa772b16835b5aaf9116"},"message":"70c10ddf147d5ce7bb6689094abd31884f8e2e37c6f800f8483739dc836bb913"}},"description":"","pubkey":"87a9093b834befae2523c073b34038065b329f85f1ca7c5cd617db78a9e2d27b55aa05bc7422e62510d5a8cf014257e5","path":"m/12381/3600/17/0/0","uuid":"f2c4c701-59f8-4f13-af53-8f8894a0a1cf","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x8ab6b5ed1e3cedb684b8b604221567d55ad5b48c4aecf8b23fc988bdc78000ce26f6e0f6efff7ff3557ebbbebd04ef61/keystore.json b/testnet/nimbus/validators/0x8ab6b5ed1e3cedb684b8b604221567d55ad5b48c4aecf8b23fc988bdc78000ce26f6e0f6efff7ff3557ebbbebd04ef61/keystore.json new file mode 100644 index 000000000..2bac636fa --- /dev/null +++ b/testnet/nimbus/validators/0x8ab6b5ed1e3cedb684b8b604221567d55ad5b48c4aecf8b23fc988bdc78000ce26f6e0f6efff7ff3557ebbbebd04ef61/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"c26e33ac1bf53491c5276c4307776c4da7adfbb836012e71e80421306d0fde93"},"message":""},"checksum":{"function":"sha256","params":{},"message":"17817d90708d058935f1fd2f21f1006d190813ad4ce786775120f5f4035d67e7"},"cipher":{"function":"aes-128-ctr","params":{"iv":"f2b1422e65ae7f3ab4e869cf4f15b41d"},"message":"be19994daa36d4959b3928621cdd71db849c9beddab23ba30a8104c6b8a682ad"}},"description":"","pubkey":"8ab6b5ed1e3cedb684b8b604221567d55ad5b48c4aecf8b23fc988bdc78000ce26f6e0f6efff7ff3557ebbbebd04ef61","path":"m/12381/3600/21/0/0","uuid":"95e31034-2fcc-43fb-b56a-a7919872cf4b","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x9364daa6d000495b138c8d80964f3306a32ec85680d1ddd45305f08ecb0f44d32a2e946c226cb070685b41bec663256a/keystore.json b/testnet/nimbus/validators/0x9364daa6d000495b138c8d80964f3306a32ec85680d1ddd45305f08ecb0f44d32a2e946c226cb070685b41bec663256a/keystore.json new file mode 100644 index 000000000..8185e0c31 --- /dev/null +++ b/testnet/nimbus/validators/0x9364daa6d000495b138c8d80964f3306a32ec85680d1ddd45305f08ecb0f44d32a2e946c226cb070685b41bec663256a/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"003fe03f061660618b80e7acbf57850f5739f961c611b40e1dee9a75fb410064"},"message":""},"checksum":{"function":"sha256","params":{},"message":"02fa5666eee6ebb9f18e1f61dd643abc9ad630c48910369496a57ab0521038a6"},"cipher":{"function":"aes-128-ctr","params":{"iv":"7f752b3b8a8bed37a97264c5810fb2f1"},"message":"5fcb4fe2b7bb8f612920ef7c0675b2d8bd0bb12e53f1bdb0bd75c35c7c71cbe1"}},"description":"","pubkey":"9364daa6d000495b138c8d80964f3306a32ec85680d1ddd45305f08ecb0f44d32a2e946c226cb070685b41bec663256a","path":"m/12381/3600/14/0/0","uuid":"5c1f060a-6a31-4f28-a6c4-44916def5f29","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x93737d75235b7ef7ac7422cd31c00afac950b4376e5cf98468e25de6258d2c03a76035df6a6c89c4a015597eb4f0d3fc/keystore.json b/testnet/nimbus/validators/0x93737d75235b7ef7ac7422cd31c00afac950b4376e5cf98468e25de6258d2c03a76035df6a6c89c4a015597eb4f0d3fc/keystore.json new file mode 100644 index 000000000..02870436a --- /dev/null +++ b/testnet/nimbus/validators/0x93737d75235b7ef7ac7422cd31c00afac950b4376e5cf98468e25de6258d2c03a76035df6a6c89c4a015597eb4f0d3fc/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"9ad5fbc37f7dc47936c92b9d6c96d7e68ca6bdf95ffba48713a697d00b369c4a"},"message":""},"checksum":{"function":"sha256","params":{},"message":"62769d6e97dafdab27f86e435c2bd8ba87c0ef7555c87abc03407975d55e8722"},"cipher":{"function":"aes-128-ctr","params":{"iv":"07fdd99312bec142d0e7f2b59405e468"},"message":"ee3ebdcc72fe8599c5d94359e21bf462da7cf2aa9bf43536b8fac07f8280f751"}},"description":"","pubkey":"93737d75235b7ef7ac7422cd31c00afac950b4376e5cf98468e25de6258d2c03a76035df6a6c89c4a015597eb4f0d3fc","path":"m/12381/3600/25/0/0","uuid":"d8d4a07f-bf88-47d5-adfc-55834eb29024","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x98252a182b4aaf410f066fb9f7bd9ff0ec43f5136cbe92c7d65d5d2831e5a58090ea993a644690c47fc85981eb2e1d2c/keystore.json b/testnet/nimbus/validators/0x98252a182b4aaf410f066fb9f7bd9ff0ec43f5136cbe92c7d65d5d2831e5a58090ea993a644690c47fc85981eb2e1d2c/keystore.json new file mode 100644 index 000000000..7b87851a3 --- /dev/null +++ b/testnet/nimbus/validators/0x98252a182b4aaf410f066fb9f7bd9ff0ec43f5136cbe92c7d65d5d2831e5a58090ea993a644690c47fc85981eb2e1d2c/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"714db766a15980d185a1b436fece319ec00be4f0e6b399a51f32e156b0ccdbfc"},"message":""},"checksum":{"function":"sha256","params":{},"message":"10dab4928e66cc564b51064e5e031fcbb111da0c230f5b4fac509377e9550d23"},"cipher":{"function":"aes-128-ctr","params":{"iv":"c5d920834d66cb5f2b8b2611646badc9"},"message":"6d45ef04e2264afef3fb7b4ccec9206c54d6c7f68d3e5e9e6d7bb709836ee374"}},"description":"","pubkey":"98252a182b4aaf410f066fb9f7bd9ff0ec43f5136cbe92c7d65d5d2831e5a58090ea993a644690c47fc85981eb2e1d2c","path":"m/12381/3600/2/0/0","uuid":"60e76009-5432-4f03-adcd-2d01691b0bdb","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0x9997ca462621ba46a5988971bdab4a61a482817172312f96e046c5e364946383573d945c59ab8c1242def7be4b2ec146/keystore.json b/testnet/nimbus/validators/0x9997ca462621ba46a5988971bdab4a61a482817172312f96e046c5e364946383573d945c59ab8c1242def7be4b2ec146/keystore.json new file mode 100644 index 000000000..71a8c79ba --- /dev/null +++ b/testnet/nimbus/validators/0x9997ca462621ba46a5988971bdab4a61a482817172312f96e046c5e364946383573d945c59ab8c1242def7be4b2ec146/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"9581e8dba346fadab0e719893ffe142ca736df193f6a87910a727aa1b261c172"},"message":""},"checksum":{"function":"sha256","params":{},"message":"a56007b39c5231a459a475dd4fe53efbf2653a851161122852527e65481fdec3"},"cipher":{"function":"aes-128-ctr","params":{"iv":"f283409573de42ce201e61a9cd8b7f85"},"message":"70390e24df4cab76f1a75c5c0669c263433deec55d045a34cd1e6c6a5989b03a"}},"description":"","pubkey":"9997ca462621ba46a5988971bdab4a61a482817172312f96e046c5e364946383573d945c59ab8c1242def7be4b2ec146","path":"m/12381/3600/12/0/0","uuid":"2c0e096a-d896-4afc-b18b-5a1c9458c213","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xa34353d86c69fc4ac08698960158a92748b6e25821b31b0c5cd764ff3d6fa5855d9d8d2aacb2260cafc8e2821a0b4343/keystore.json b/testnet/nimbus/validators/0xa34353d86c69fc4ac08698960158a92748b6e25821b31b0c5cd764ff3d6fa5855d9d8d2aacb2260cafc8e2821a0b4343/keystore.json new file mode 100644 index 000000000..e1f0c45f9 --- /dev/null +++ b/testnet/nimbus/validators/0xa34353d86c69fc4ac08698960158a92748b6e25821b31b0c5cd764ff3d6fa5855d9d8d2aacb2260cafc8e2821a0b4343/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"d207b6569dd659efdbe92d814e0ee0ff623bbbc33e183ac6b549277d265c1474"},"message":""},"checksum":{"function":"sha256","params":{},"message":"205748a8a6b07dc38534df550b0bff3bd9834e131fc62eefba3c5e668b56bc90"},"cipher":{"function":"aes-128-ctr","params":{"iv":"9f6b669220d3bb75948424e4d59ebba8"},"message":"e4259afeecf2166d777b22cb3fc63091e0d6ef28333d501a26e16ce622997471"}},"description":"","pubkey":"a34353d86c69fc4ac08698960158a92748b6e25821b31b0c5cd764ff3d6fa5855d9d8d2aacb2260cafc8e2821a0b4343","path":"m/12381/3600/19/0/0","uuid":"05aa2b0b-da16-48f0-9a4b-4a9fb2692f51","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xa5451d7b02b2241f0df105288154fcda8517d59a8fc758676c04997c0ab02d8d265e4728970da3d894fc5f5431af4c53/keystore.json b/testnet/nimbus/validators/0xa5451d7b02b2241f0df105288154fcda8517d59a8fc758676c04997c0ab02d8d265e4728970da3d894fc5f5431af4c53/keystore.json new file mode 100644 index 000000000..3aabe959e --- /dev/null +++ b/testnet/nimbus/validators/0xa5451d7b02b2241f0df105288154fcda8517d59a8fc758676c04997c0ab02d8d265e4728970da3d894fc5f5431af4c53/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"98c62e22cbc6908eb46f2a073f866834abf1bc7da2af2659aaf71899c401e8c7"},"message":""},"checksum":{"function":"sha256","params":{},"message":"bb5b43b1f5bb5614f7ea3f1afcf5b91e8530413a0d3d7e2e8501e5bf1a21e45a"},"cipher":{"function":"aes-128-ctr","params":{"iv":"d05a17893e8fda0693e4ae9ba2a8ad93"},"message":"2e077b34800863d3ee447d2e86a70e926aa89456b6041a593b978921c80e4a9a"}},"description":"","pubkey":"a5451d7b02b2241f0df105288154fcda8517d59a8fc758676c04997c0ab02d8d265e4728970da3d894fc5f5431af4c53","path":"m/12381/3600/26/0/0","uuid":"53e8c407-e6d4-441f-9bfd-f6c2aecf9f3e","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xa59df5c2ff63a77317524b71b9be7e74e95d42cc80a0c53bf841eb6355916a7d7d5ffab863db1e263f570ab248b6f27c/keystore.json b/testnet/nimbus/validators/0xa59df5c2ff63a77317524b71b9be7e74e95d42cc80a0c53bf841eb6355916a7d7d5ffab863db1e263f570ab248b6f27c/keystore.json new file mode 100644 index 000000000..bc7189fac --- /dev/null +++ b/testnet/nimbus/validators/0xa59df5c2ff63a77317524b71b9be7e74e95d42cc80a0c53bf841eb6355916a7d7d5ffab863db1e263f570ab248b6f27c/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"8d8f3ba1b482ae6216d18871df5da3dff7ed060a7e2b36645aa32776677f4107"},"message":""},"checksum":{"function":"sha256","params":{},"message":"b8eb96d584a99674f371451ab544cc1f0fa74d9746181f0d4fcdb232efb85b02"},"cipher":{"function":"aes-128-ctr","params":{"iv":"b65448f5cf75b37182c71fe18973e414"},"message":"f038e1dfe0712ee89a240340354e270cd316a1495d22b64a8dbd0a8d6742a0a8"}},"description":"","pubkey":"a59df5c2ff63a77317524b71b9be7e74e95d42cc80a0c53bf841eb6355916a7d7d5ffab863db1e263f570ab248b6f27c","path":"m/12381/3600/0/0/0","uuid":"216f2ab6-bf60-4994-9232-700cc6840141","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xa5d1f7d985bed2bba07cedd714b078b4cfe6185a246eb277ae68098715bcd24488b0e2dc8d19f4674937cb5656a1d927/keystore.json b/testnet/nimbus/validators/0xa5d1f7d985bed2bba07cedd714b078b4cfe6185a246eb277ae68098715bcd24488b0e2dc8d19f4674937cb5656a1d927/keystore.json new file mode 100644 index 000000000..2649094eb --- /dev/null +++ b/testnet/nimbus/validators/0xa5d1f7d985bed2bba07cedd714b078b4cfe6185a246eb277ae68098715bcd24488b0e2dc8d19f4674937cb5656a1d927/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"090809f04fbeb248728932137a0767c33a568e5054deab147111e9754eb2ae45"},"message":""},"checksum":{"function":"sha256","params":{},"message":"6457c1de63c8b4159365bc2c5739a7799c3c1d4a1f5e9a559c57f5896bff73ad"},"cipher":{"function":"aes-128-ctr","params":{"iv":"18f5f371e56f7ae4547d2a924eb367d3"},"message":"90fecb461b92e8b7c7e31d5cbc2034c54baa44df8f8ecbf564dc9f0ce1e4162a"}},"description":"","pubkey":"a5d1f7d985bed2bba07cedd714b078b4cfe6185a246eb277ae68098715bcd24488b0e2dc8d19f4674937cb5656a1d927","path":"m/12381/3600/18/0/0","uuid":"265ceb52-dd1a-4533-a01a-d4cfa507feab","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xa66a5b7d1dfe156e65f239e885282d7fb1f6879afa483e05092a9001e6228af5ba47573882d9f0e7e8b13685d21a3d0c/keystore.json b/testnet/nimbus/validators/0xa66a5b7d1dfe156e65f239e885282d7fb1f6879afa483e05092a9001e6228af5ba47573882d9f0e7e8b13685d21a3d0c/keystore.json new file mode 100644 index 000000000..a914a5763 --- /dev/null +++ b/testnet/nimbus/validators/0xa66a5b7d1dfe156e65f239e885282d7fb1f6879afa483e05092a9001e6228af5ba47573882d9f0e7e8b13685d21a3d0c/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"61c69740eb322549ce21f09a259f2aead54db84ed5931a56d5a4f83f4348ca12"},"message":""},"checksum":{"function":"sha256","params":{},"message":"e27aa58dee0f939a2e934f92db3b90ddd24bee2224b87f3be35b01dbdbca51e9"},"cipher":{"function":"aes-128-ctr","params":{"iv":"4a2fcd702137e1a8592dd6459fe370cc"},"message":"bfd2bbcd7002270f08aaa870bf25dca84796dea4e4ed39136d9046b4033a27e1"}},"description":"","pubkey":"a66a5b7d1dfe156e65f239e885282d7fb1f6879afa483e05092a9001e6228af5ba47573882d9f0e7e8b13685d21a3d0c","path":"m/12381/3600/31/0/0","uuid":"64a4a5a3-7721-44b8-bb51-99b82bb4d11f","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xa6fc251771b193b3121424b9e5eea580ee4fd7355d3be1e6c6e2aa1155bd8bd247db4d82e6a9a3aab76e8aacbfb00ae1/keystore.json b/testnet/nimbus/validators/0xa6fc251771b193b3121424b9e5eea580ee4fd7355d3be1e6c6e2aa1155bd8bd247db4d82e6a9a3aab76e8aacbfb00ae1/keystore.json new file mode 100644 index 000000000..789156dd1 --- /dev/null +++ b/testnet/nimbus/validators/0xa6fc251771b193b3121424b9e5eea580ee4fd7355d3be1e6c6e2aa1155bd8bd247db4d82e6a9a3aab76e8aacbfb00ae1/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"df706d1aff24c3877006396ea9572888a3184612cb8b10dd687401fcd6bbd7be"},"message":""},"checksum":{"function":"sha256","params":{},"message":"4c4ecfb8ae75b95aac55002363faf3885e92ba71bac93549f17489e09f1d435d"},"cipher":{"function":"aes-128-ctr","params":{"iv":"ae44a3c4589ff66eb004aef4a6e9690a"},"message":"c67ab3bcb9c35079efbadd8bdf1d8a7d0f9e2efddb618e0b07f386431bdb965a"}},"description":"","pubkey":"a6fc251771b193b3121424b9e5eea580ee4fd7355d3be1e6c6e2aa1155bd8bd247db4d82e6a9a3aab76e8aacbfb00ae1","path":"m/12381/3600/27/0/0","uuid":"2efdf9cd-44d1-427a-bb49-f65a9cfaa262","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xac660a01fdd86fd4bec526c5d1096164e6acd85fe5e738def40d33861a5c57bc7be5fc304304022271f9ea2405214a7c/keystore.json b/testnet/nimbus/validators/0xac660a01fdd86fd4bec526c5d1096164e6acd85fe5e738def40d33861a5c57bc7be5fc304304022271f9ea2405214a7c/keystore.json new file mode 100644 index 000000000..ec6b03258 --- /dev/null +++ b/testnet/nimbus/validators/0xac660a01fdd86fd4bec526c5d1096164e6acd85fe5e738def40d33861a5c57bc7be5fc304304022271f9ea2405214a7c/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"8afaf450a833e9c90d27fc3ce6cc0af4fc82c623fc0e7cb22e2e82aa831548a6"},"message":""},"checksum":{"function":"sha256","params":{},"message":"df0c7c604fe1bc7d8d55c49f880cd6252f3341b8b7294521774afd6fd562e7a5"},"cipher":{"function":"aes-128-ctr","params":{"iv":"3cbbd196f6b4260a39e78d22b52586e3"},"message":"71725ee5df5f707aa2d6b5fcf2a19521ea513c64d139b0b0486bdadcd21a6b5e"}},"description":"","pubkey":"ac660a01fdd86fd4bec526c5d1096164e6acd85fe5e738def40d33861a5c57bc7be5fc304304022271f9ea2405214a7c","path":"m/12381/3600/1/0/0","uuid":"ffa882d5-d427-4d7a-990a-e7a79fffbd53","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb0e0bb95eabcb2daa1cc931ca15bf9f8e9335f3c131f01d309567039ab52f1c5b8cbfcf6cd5c949708a4d38542e201f4/keystore.json b/testnet/nimbus/validators/0xb0e0bb95eabcb2daa1cc931ca15bf9f8e9335f3c131f01d309567039ab52f1c5b8cbfcf6cd5c949708a4d38542e201f4/keystore.json new file mode 100644 index 000000000..521feff40 --- /dev/null +++ b/testnet/nimbus/validators/0xb0e0bb95eabcb2daa1cc931ca15bf9f8e9335f3c131f01d309567039ab52f1c5b8cbfcf6cd5c949708a4d38542e201f4/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"0aa863f23639a9f181ef200dacfdceee18b6bb61428044456a9ba4e4fa9cf1eb"},"message":""},"checksum":{"function":"sha256","params":{},"message":"3260a0a397eab944b93abd28c41bbaaf494bd800b0a7c695729198300f01dee7"},"cipher":{"function":"aes-128-ctr","params":{"iv":"58f8aee8a741a1585c52a396c4511b37"},"message":"cb79d277e08e354b2fecab8cbd672f90551a8f8cd8c6c2506f9284cbff2b015e"}},"description":"","pubkey":"b0e0bb95eabcb2daa1cc931ca15bf9f8e9335f3c131f01d309567039ab52f1c5b8cbfcf6cd5c949708a4d38542e201f4","path":"m/12381/3600/16/0/0","uuid":"4bbacfb0-13f8-4a4e-a6f0-d5ff031520ab","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb0f33dd02682ac8406aea86ebefe8cdde946f0d840a8442a5ec4496d03fe3c7cd89c4515847721d0fa150005b98f2c3a/keystore.json b/testnet/nimbus/validators/0xb0f33dd02682ac8406aea86ebefe8cdde946f0d840a8442a5ec4496d03fe3c7cd89c4515847721d0fa150005b98f2c3a/keystore.json new file mode 100644 index 000000000..43c7bd54d --- /dev/null +++ b/testnet/nimbus/validators/0xb0f33dd02682ac8406aea86ebefe8cdde946f0d840a8442a5ec4496d03fe3c7cd89c4515847721d0fa150005b98f2c3a/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"21df3e550790c977e2caea48d6d3ce6c737933e1a8ffa839d62b8bb287fb2acd"},"message":""},"checksum":{"function":"sha256","params":{},"message":"b116e99c3fe9d394cd9f1556e62ca9227df8f9392ba94877e3867909d2766f79"},"cipher":{"function":"aes-128-ctr","params":{"iv":"c51e82a60d36348e77382890c79b1223"},"message":"5a4b206d9e3a228b7f71cbcfdbd74f6a7dbbee2aa51b004c29452e08f9a45a60"}},"description":"","pubkey":"b0f33dd02682ac8406aea86ebefe8cdde946f0d840a8442a5ec4496d03fe3c7cd89c4515847721d0fa150005b98f2c3a","path":"m/12381/3600/23/0/0","uuid":"749fca70-2d0b-4026-9a68-71b3148aa4c4","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb0f464fe938e9279ddf6cd4072285363984f93c8d6bfd5e7ce94124d54fa16bce96fe0452173d5ecd2fed6b61f116c0b/keystore.json b/testnet/nimbus/validators/0xb0f464fe938e9279ddf6cd4072285363984f93c8d6bfd5e7ce94124d54fa16bce96fe0452173d5ecd2fed6b61f116c0b/keystore.json new file mode 100644 index 000000000..74e1fb895 --- /dev/null +++ b/testnet/nimbus/validators/0xb0f464fe938e9279ddf6cd4072285363984f93c8d6bfd5e7ce94124d54fa16bce96fe0452173d5ecd2fed6b61f116c0b/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"484da5f79e3699c8ae1c40c89d76f99f52b756eea5760b2a1b3ff66bc961cb6b"},"message":""},"checksum":{"function":"sha256","params":{},"message":"4c568125a73cf28726749b47ffea01b75143b95583980789ce28aed9ff149d3f"},"cipher":{"function":"aes-128-ctr","params":{"iv":"79dc8c058366a16e28e2d0418607ccc4"},"message":"83c450e16d3d9b3c60726c1579c96cb5d22af6ceebc8aac6c36da743196ae576"}},"description":"","pubkey":"b0f464fe938e9279ddf6cd4072285363984f93c8d6bfd5e7ce94124d54fa16bce96fe0452173d5ecd2fed6b61f116c0b","path":"m/12381/3600/24/0/0","uuid":"da9385b4-3e5c-4070-a1b2-d7c2a7c52f74","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb15be8807d46e9bb9428a5442cb994c1ebe5f77459df518dc62cf38e9c291a0b0f9ade6a336841e247d55b8a372edcb9/keystore.json b/testnet/nimbus/validators/0xb15be8807d46e9bb9428a5442cb994c1ebe5f77459df518dc62cf38e9c291a0b0f9ade6a336841e247d55b8a372edcb9/keystore.json new file mode 100644 index 000000000..cd9b610c6 --- /dev/null +++ b/testnet/nimbus/validators/0xb15be8807d46e9bb9428a5442cb994c1ebe5f77459df518dc62cf38e9c291a0b0f9ade6a336841e247d55b8a372edcb9/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"40bf1d0e0008b13f4f110e27256787e8a199e1a65031154ef67e822fa2c7fe0c"},"message":""},"checksum":{"function":"sha256","params":{},"message":"0387128533125e974f08bf3567bf5ad168be3f0b316142bbb40cfb4387163a7e"},"cipher":{"function":"aes-128-ctr","params":{"iv":"cb2a033e39b521b88276be7f8d2a829c"},"message":"2f745339e225f05693ec0aa95c8f316344f1fce055ad67384018398c81bc619e"}},"description":"","pubkey":"b15be8807d46e9bb9428a5442cb994c1ebe5f77459df518dc62cf38e9c291a0b0f9ade6a336841e247d55b8a372edcb9","path":"m/12381/3600/22/0/0","uuid":"74f4578b-8875-42a5-a7f6-e3b6ec0bf006","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb1b0f384a1057a2411c81f7c1555ffdc2e2b245198614cb77af40c8772630e5057c9d691fd6ab0fe74d837680011f996/keystore.json b/testnet/nimbus/validators/0xb1b0f384a1057a2411c81f7c1555ffdc2e2b245198614cb77af40c8772630e5057c9d691fd6ab0fe74d837680011f996/keystore.json new file mode 100644 index 000000000..6a48c7be9 --- /dev/null +++ b/testnet/nimbus/validators/0xb1b0f384a1057a2411c81f7c1555ffdc2e2b245198614cb77af40c8772630e5057c9d691fd6ab0fe74d837680011f996/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"882b60255046748d37d0a916706403647a5e7060b0b26586ff96de06bf47ed91"},"message":""},"checksum":{"function":"sha256","params":{},"message":"3c580154b7ad6f93177dd3fc7d179b6c24d087b8b862793170bd8f2ece44d2b4"},"cipher":{"function":"aes-128-ctr","params":{"iv":"1c536d4183cf81b6b6af4f9b39a0f5a9"},"message":"efc6ea025078756a21b42893a928deee4c5cd6289d2dd94c46c476650ff065e2"}},"description":"","pubkey":"b1b0f384a1057a2411c81f7c1555ffdc2e2b245198614cb77af40c8772630e5057c9d691fd6ab0fe74d837680011f996","path":"m/12381/3600/7/0/0","uuid":"8090d525-8933-4d1c-91e7-9b15f457361e","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb1c355f22b9b9c34ceeeaddfe2a58ccf3122c8706b0fb85bb925a57d7a2a78b1bb191e3062381485e2884eb3ee3956c9/keystore.json b/testnet/nimbus/validators/0xb1c355f22b9b9c34ceeeaddfe2a58ccf3122c8706b0fb85bb925a57d7a2a78b1bb191e3062381485e2884eb3ee3956c9/keystore.json new file mode 100644 index 000000000..de162bd8c --- /dev/null +++ b/testnet/nimbus/validators/0xb1c355f22b9b9c34ceeeaddfe2a58ccf3122c8706b0fb85bb925a57d7a2a78b1bb191e3062381485e2884eb3ee3956c9/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"f5b17e288849d80cc0122048a0b1ba353848d975b1db4fc20ff906ba6a944b15"},"message":""},"checksum":{"function":"sha256","params":{},"message":"eb00d6f0f05b7edbf4bde16ea0289f04ece4b188b11955b83e3c798848856756"},"cipher":{"function":"aes-128-ctr","params":{"iv":"36347debb2485b3523abb6fd76b589e0"},"message":"26d622c413ca2435804545a59c9bb9bfae67f502a29fc50ada0f5195394cbd03"}},"description":"","pubkey":"b1c355f22b9b9c34ceeeaddfe2a58ccf3122c8706b0fb85bb925a57d7a2a78b1bb191e3062381485e2884eb3ee3956c9","path":"m/12381/3600/13/0/0","uuid":"095cc408-ab07-4410-9a5d-650bfa858937","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb3386a09faa3be115be868f91fbf40578e5348939c8334972c0b8fe1863de41054df0cec5c2d5afd3c8626dbd9cce3aa/keystore.json b/testnet/nimbus/validators/0xb3386a09faa3be115be868f91fbf40578e5348939c8334972c0b8fe1863de41054df0cec5c2d5afd3c8626dbd9cce3aa/keystore.json new file mode 100644 index 000000000..8f5e2ccd4 --- /dev/null +++ b/testnet/nimbus/validators/0xb3386a09faa3be115be868f91fbf40578e5348939c8334972c0b8fe1863de41054df0cec5c2d5afd3c8626dbd9cce3aa/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"1dbb5becf08ec981c49f1bf652136b4ef7ff1c1e82d43ee76d05323b64ab6956"},"message":""},"checksum":{"function":"sha256","params":{},"message":"ede2bc1e038c3a9708506a06641d8203fd086722fcfc4d8fec17fc92f0818494"},"cipher":{"function":"aes-128-ctr","params":{"iv":"67016de53bf90241b68fdfa2e7762f97"},"message":"32c7110f0b3ffa5b5d08bb16d923ceac8f3efc34784211b81c835b1349c2896e"}},"description":"","pubkey":"b3386a09faa3be115be868f91fbf40578e5348939c8334972c0b8fe1863de41054df0cec5c2d5afd3c8626dbd9cce3aa","path":"m/12381/3600/8/0/0","uuid":"761b9069-48c6-4b84-a7c8-0e53e217999e","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb45f3c2d53c92b1cc6437548ccd8f2bc7b180455536d1ef0f1f3188fb91645a3c69c9832aea408fada4931a95944df1e/keystore.json b/testnet/nimbus/validators/0xb45f3c2d53c92b1cc6437548ccd8f2bc7b180455536d1ef0f1f3188fb91645a3c69c9832aea408fada4931a95944df1e/keystore.json new file mode 100644 index 000000000..fc25cc2b4 --- /dev/null +++ b/testnet/nimbus/validators/0xb45f3c2d53c92b1cc6437548ccd8f2bc7b180455536d1ef0f1f3188fb91645a3c69c9832aea408fada4931a95944df1e/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"b324dc1b85dccdf1b27a6b56bc0e8e6b8f7ad941df1375d6f351cb93c71fc733"},"message":""},"checksum":{"function":"sha256","params":{},"message":"0201f72ee9b77348452a8b8cba6cd24afba0d0a2b501c16cb4376ab53e53efc7"},"cipher":{"function":"aes-128-ctr","params":{"iv":"ae47c905ae24f48b612d7aedf5c407a6"},"message":"881d6abd42fd251345ae8a881afd4ee2cf042b2c726463eddcdcf1228bfd1d3a"}},"description":"","pubkey":"b45f3c2d53c92b1cc6437548ccd8f2bc7b180455536d1ef0f1f3188fb91645a3c69c9832aea408fada4931a95944df1e","path":"m/12381/3600/6/0/0","uuid":"b26d5104-6c38-4d0c-b814-9eecbd73ebb0","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb48cca1ccf42383065abd73587b1e93cca15fe02900611e7428aad67c4222a701e44e199ab0b488251b90083d297f75a/keystore.json b/testnet/nimbus/validators/0xb48cca1ccf42383065abd73587b1e93cca15fe02900611e7428aad67c4222a701e44e199ab0b488251b90083d297f75a/keystore.json new file mode 100644 index 000000000..b464da878 --- /dev/null +++ b/testnet/nimbus/validators/0xb48cca1ccf42383065abd73587b1e93cca15fe02900611e7428aad67c4222a701e44e199ab0b488251b90083d297f75a/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"880afd2b88f047c3c89464256fa9a7d9386e3c3062a9bcf7aa2f0a5856a69045"},"message":""},"checksum":{"function":"sha256","params":{},"message":"4cef1e6469f12136567069e1e5157555e79e4e9a0a042e0f779d89ee51039f1e"},"cipher":{"function":"aes-128-ctr","params":{"iv":"a1ff5f0887f2632064c4a907cf5e821a"},"message":"c39a643ce1fd8b01894b14c44241078d7c006974656480904c54e2ac0f5f7c51"}},"description":"","pubkey":"b48cca1ccf42383065abd73587b1e93cca15fe02900611e7428aad67c4222a701e44e199ab0b488251b90083d297f75a","path":"m/12381/3600/20/0/0","uuid":"528829f6-6661-4417-8b0e-fe5dfb8a6b33","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb6bcf566c45bef5607d95865757c02a2153f7bd858d036665dc835a0cceff60a6403bf4d21627600d078ff6c7e4d8b53/keystore.json b/testnet/nimbus/validators/0xb6bcf566c45bef5607d95865757c02a2153f7bd858d036665dc835a0cceff60a6403bf4d21627600d078ff6c7e4d8b53/keystore.json new file mode 100644 index 000000000..b5942dfd1 --- /dev/null +++ b/testnet/nimbus/validators/0xb6bcf566c45bef5607d95865757c02a2153f7bd858d036665dc835a0cceff60a6403bf4d21627600d078ff6c7e4d8b53/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"5bc7e622c46b2481304a3f9d7fcc98390537969853af39aec95fdbddac15514a"},"message":""},"checksum":{"function":"sha256","params":{},"message":"7cc743e8e7c36c5d106eb9cdeccbbac8cbf9f6b440b52dcc40ebe1bbed87def7"},"cipher":{"function":"aes-128-ctr","params":{"iv":"1db2819a7e00b7d6d2c0ebf499781a48"},"message":"0a3ec6e08579a4c6e113eddff9890f2d91f788f4bb7213837db4cafc83a042d8"}},"description":"","pubkey":"b6bcf566c45bef5607d95865757c02a2153f7bd858d036665dc835a0cceff60a6403bf4d21627600d078ff6c7e4d8b53","path":"m/12381/3600/9/0/0","uuid":"2ef0d191-a55c-41d8-a58e-ab3da7428752","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb7a0c7c0bd0a57f1a898c1e94d81248aef4c8855f29c49ebda35c5e982e67662b4a1709a88584a819a9eb7cf97bb9191/keystore.json b/testnet/nimbus/validators/0xb7a0c7c0bd0a57f1a898c1e94d81248aef4c8855f29c49ebda35c5e982e67662b4a1709a88584a819a9eb7cf97bb9191/keystore.json new file mode 100644 index 000000000..59b4b0bd7 --- /dev/null +++ b/testnet/nimbus/validators/0xb7a0c7c0bd0a57f1a898c1e94d81248aef4c8855f29c49ebda35c5e982e67662b4a1709a88584a819a9eb7cf97bb9191/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"e3509c89b685737e4ead5a85520ae838a695c141f84c51e86f060c66975a272d"},"message":""},"checksum":{"function":"sha256","params":{},"message":"df74a3a9124e638d355177f684b741a8020db0435ccf75131776169e38472076"},"cipher":{"function":"aes-128-ctr","params":{"iv":"7e680966066a2ba6d1c13dbb15d59f33"},"message":"71f0fb98bc8e915c844d482f8d96cfc48f8c8e5f3d120aba9303725c5d8276b2"}},"description":"","pubkey":"b7a0c7c0bd0a57f1a898c1e94d81248aef4c8855f29c49ebda35c5e982e67662b4a1709a88584a819a9eb7cf97bb9191","path":"m/12381/3600/5/0/0","uuid":"b79f642e-f5e9-464f-a0be-61416b905dc7","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb7ad82481970ed4f05b4ca53620bc6ac34c9b5a472ad69f74e6b09e52046d450879c4accec0b65b567cb685b28443531/keystore.json b/testnet/nimbus/validators/0xb7ad82481970ed4f05b4ca53620bc6ac34c9b5a472ad69f74e6b09e52046d450879c4accec0b65b567cb685b28443531/keystore.json new file mode 100644 index 000000000..2c564176f --- /dev/null +++ b/testnet/nimbus/validators/0xb7ad82481970ed4f05b4ca53620bc6ac34c9b5a472ad69f74e6b09e52046d450879c4accec0b65b567cb685b28443531/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"5cb39fdb3a81954cc557ace790ac3e761cd322f5b7a0ce31ac3fd3c5b2e92d55"},"message":""},"checksum":{"function":"sha256","params":{},"message":"89aa42ce6ca539ec4ce84af65f4261662a4621f8d649535cc740c208c8f9dd57"},"cipher":{"function":"aes-128-ctr","params":{"iv":"4c2d5fb0ab0bc10410092b5a1ed9f471"},"message":"e2f7a23748ed3f49ea8a58ddab4c62b099d482ac073f1abe0cbc4e0b84a60931"}},"description":"","pubkey":"b7ad82481970ed4f05b4ca53620bc6ac34c9b5a472ad69f74e6b09e52046d450879c4accec0b65b567cb685b28443531","path":"m/12381/3600/4/0/0","uuid":"64427dd6-96c2-435b-90bf-8fb8d1484524","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb91d92c0e32cd11fd729929919ff8e0976b3961a32062d992361d5104e5a1afaabeb811b4791ed39ba849799e6a15b1a/keystore.json b/testnet/nimbus/validators/0xb91d92c0e32cd11fd729929919ff8e0976b3961a32062d992361d5104e5a1afaabeb811b4791ed39ba849799e6a15b1a/keystore.json new file mode 100644 index 000000000..b243258c1 --- /dev/null +++ b/testnet/nimbus/validators/0xb91d92c0e32cd11fd729929919ff8e0976b3961a32062d992361d5104e5a1afaabeb811b4791ed39ba849799e6a15b1a/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"948d5c5aa4a25d42acf798e74150aef98b3a52823307394d48d6478bc5fde751"},"message":""},"checksum":{"function":"sha256","params":{},"message":"8099c57fd88b4236e9391c9767c5b41ab14899c6c0a538d56bff2158a6fd384d"},"cipher":{"function":"aes-128-ctr","params":{"iv":"46b0e51184f54212d96c16f4b43170e5"},"message":"c8be740ce6affc60699bfdaad928af2398a3862e7ac0f8ecff40b6c461ef99a3"}},"description":"","pubkey":"b91d92c0e32cd11fd729929919ff8e0976b3961a32062d992361d5104e5a1afaabeb811b4791ed39ba849799e6a15b1a","path":"m/12381/3600/30/0/0","uuid":"3dafe9f0-5ca3-45a4-bfcc-99d16c291d29","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/0xb93b74b64c52238777eae5ad0f0c79eca42ca6a053f233dd55a907ae58f5614313cd80f71bdb5184d02f5209379d2fdb/keystore.json b/testnet/nimbus/validators/0xb93b74b64c52238777eae5ad0f0c79eca42ca6a053f233dd55a907ae58f5614313cd80f71bdb5184d02f5209379d2fdb/keystore.json new file mode 100644 index 000000000..543bcafa1 --- /dev/null +++ b/testnet/nimbus/validators/0xb93b74b64c52238777eae5ad0f0c79eca42ca6a053f233dd55a907ae58f5614313cd80f71bdb5184d02f5209379d2fdb/keystore.json @@ -0,0 +1 @@ +{"crypto":{"kdf":{"function":"pbkdf2","params":{"dklen":32,"c":262144,"prf":"hmac-sha256","salt":"b80575f11fcadd6d0fe2547fa8aa876c451a17d52c19612e52ea722f5a93d1f6"},"message":""},"checksum":{"function":"sha256","params":{},"message":"86ff869c1b022b312bc7b3268e28c8fec2541c944702ff70ce89c24fd154e680"},"cipher":{"function":"aes-128-ctr","params":{"iv":"ea9e2a1112cdc2a42558367d19117005"},"message":"6f7a875dc75f1cba321f02da699fe5b7d8a2d8dd7e36984f3026edd5513e42ab"}},"description":"","pubkey":"b93b74b64c52238777eae5ad0f0c79eca42ca6a053f233dd55a907ae58f5614313cd80f71bdb5184d02f5209379d2fdb","path":"m/12381/3600/28/0/0","uuid":"a64d8d70-7184-47d7-98cc-f852dc23a43a","version":4} \ No newline at end of file diff --git a/testnet/nimbus/validators/deposit_data.json b/testnet/nimbus/validators/deposit_data.json new file mode 100644 index 000000000..c12b0c3c7 --- /dev/null +++ b/testnet/nimbus/validators/deposit_data.json @@ -0,0 +1 @@ +[{"pubkey":"a59df5c2ff63a77317524b71b9be7e74e95d42cc80a0c53bf841eb6355916a7d7d5ffab863db1e263f570ab248b6f27c","withdrawal_credentials":"005d83b517048ee697bda6ec745fede17fd083f7221fcc050a643436757fbb33","amount":32000000000,"signature":"b868fa5fddcea463bf96050a41928d2fb17ae262b7e7811d669417e9c2f51a41c4a8f0dcca800713eb6ebd400df601d5196371335ef458ede7789f1fe2f7da49876bbfd2fbcbb35b1c6e7d8830baafe42bd195620eb78aa4563cfb4e7e696952","deposit_message_root":"751cd0418509a267e719e0dbdcf046a0684a6df5835d15afef52c5854a8fe36c","deposit_data_root":"c7a6af66a1376d5d0f6492f61412d49898157e8f33aa04bdb46a447c2dcb5cfe","fork_version":"00000000"},{"pubkey":"ac660a01fdd86fd4bec526c5d1096164e6acd85fe5e738def40d33861a5c57bc7be5fc304304022271f9ea2405214a7c","withdrawal_credentials":"00b48c9cde93a0488bb5f4c7827c51247e04b9c0b53dfd740dc1b0bb524e90c6","amount":32000000000,"signature":"97263859f2ea4af7ddb1099ff6c1738f039b068b59744f126677a29409dcc59afd23d1e6ba39306d04d208b59ef90e9e17db2dc6b1f0a296767be9938f5d4d0ab5442dcd21b46f1c1c4e35281a722084dc17d935407f119d0ad827520f2b1a38","deposit_message_root":"90ed72660d8708524c8b9db353abb4ece88fc14996ead1c0c743dbd795779bef","deposit_data_root":"8b490488a8b582ce7e0e0882d1356ea15f8ebacac3b19bfc11f5ed7a597e82cf","fork_version":"00000000"},{"pubkey":"98252a182b4aaf410f066fb9f7bd9ff0ec43f5136cbe92c7d65d5d2831e5a58090ea993a644690c47fc85981eb2e1d2c","withdrawal_credentials":"0028c9c8b0bf146ba0ad32e68b6283c8a153f55b6017a2c018cc917e1a0cfd70","amount":32000000000,"signature":"a4c88e919eb5c3d64c0bdfc367bcf48bbd2ee9beb43bdd7244d6a655ade7ff396649815454c10d4693d054c3c500a3b40d5831a0a2d7eaffa6d2470f74802754bba87f10ed348b477ee485be56ec13fb5771f76642a0f365e0997db5ae8ac16d","deposit_message_root":"76dd978524055f237a4e62b9925222731312bd272b8e476b695a28091b870a94","deposit_data_root":"4ed93568a0539ea72bf7458f3d24eab939f7e3de066f9f2c3e5f080f88e902da","fork_version":"00000000"},{"pubkey":"85c19c2d84f09a1c1e7420713c3d3327a2f80a8c8d012de09881cfdf65a0732ba7908ca9ba7441f25e7896c2174685b8","withdrawal_credentials":"00103d1117f818ba23716ec825164ba74e7314f349ef83e2f5ce48ca730721b3","amount":32000000000,"signature":"8f8e581b97d09e5def9a23d2ac2a6aa3975c08ad75f194b486fa3a06f315d5a5d1defeae26c00518468496c0db0fa5cd13250cc45f737f88963d6c71e560d78f42f77f76fcad84d021dec03026a68c2797e562e1c3b0868b853467308afcf3aa","deposit_message_root":"327bfbc4b9c54968f9e1014563c57c76e1384c6c5ba6075ce9edf043066b61a5","deposit_data_root":"47461d770477990865657d9eaf974a91be64d742e7aa1b70b140b68d6675a8c0","fork_version":"00000000"},{"pubkey":"b7ad82481970ed4f05b4ca53620bc6ac34c9b5a472ad69f74e6b09e52046d450879c4accec0b65b567cb685b28443531","withdrawal_credentials":"00c5c1adaf5f8560cd7326dd37deea3be6407e31f8d00a79c9166635a1292e85","amount":32000000000,"signature":"8143176b3b664ffdf7a26818ceaea3e9fb33292e79676db28fbce9091fa345ad46ea862b2add4f98b94a97f3dfdcba9f0acefed2ae72c216f8ad400874688ca3ab4e9f2b318c286ea86455d72e9655cbe2160a36cf66fac5d9d22450e6cd96a7","deposit_message_root":"f0658fdd703b6f7d84fc69cb597e2ff1bb0e1fa4608936f78d56cbe5dc450ff2","deposit_data_root":"fdccaa495afce4c358d4949b5ddc396b5f860253951e4ea454128045ae15b7f8","fork_version":"00000000"},{"pubkey":"b7a0c7c0bd0a57f1a898c1e94d81248aef4c8855f29c49ebda35c5e982e67662b4a1709a88584a819a9eb7cf97bb9191","withdrawal_credentials":"0002d36424c3ce4d093d17c6cfb318bcd797d031f4586bea2c95fb9420e56061","amount":32000000000,"signature":"a4593d3faa3c6067a1ef7ec9cde6de1f64f391cf241f14718bf31e4f860727a3b409f0a38b7d47eec35a95f84b416d5c17ae164dd43efb2ec3a335debb9d82cd9aa5f06f9eceaf31909cd5d9d8353b40d9c900d30d2f27887a77ecc64024ef85","deposit_message_root":"1da357120fe3acbfd1bc11475214ae129792e9232302e973ce4935a37c48af63","deposit_data_root":"4a466f687c311e80cbe0bcdcc20092545f44205d014284abb8720b29beb98dd5","fork_version":"00000000"},{"pubkey":"b45f3c2d53c92b1cc6437548ccd8f2bc7b180455536d1ef0f1f3188fb91645a3c69c9832aea408fada4931a95944df1e","withdrawal_credentials":"00de46fbc3d6aa39e91dd263b255d6626caee47de95ebc8e3e08fd44fb8af4c5","amount":32000000000,"signature":"875742f683a432cf8cb56b03bc4b76e93eaf917fa39135fa1b57b0c60da0e5f01a731402a9c83b837333fe10b1c44d590fcc0d264d883d75902460e4636400780b5f2e3e81a240ed581af7282b86ea277d8ff0492406129c2bd61e3aaeba4223","deposit_message_root":"846ea25706c81d7f8b03bcb644f9cb225ecfb0197f7bd0623ae868562b29c9ac","deposit_data_root":"127a0dac7fdb9c924d40ee149baa51a5f7fc684a73c80e46ee12f049cdd66bcb","fork_version":"00000000"},{"pubkey":"b1b0f384a1057a2411c81f7c1555ffdc2e2b245198614cb77af40c8772630e5057c9d691fd6ab0fe74d837680011f996","withdrawal_credentials":"00a4836c9909ad174e70b9771adaa4f3ed1e09705316fb5d34981c83dbb678ce","amount":32000000000,"signature":"b3754cb8ecbd44f276298870ee8b8fcc8c12c067281b89ea5f4f08d45b7649328d19460a82d87942d7d6238972d572d8092c3e0a9c3dd3b7a88733c49e68f517a60b0aac9683d8b7f83ace5c47aa9e24b9e49e8683f9b7bde177b7b3f5f8b254","deposit_message_root":"f10568c6f3d21d054cd54bc9b746736c434f65725065dde3636ed2c868caaeae","deposit_data_root":"20774115de62e767648a34e87fb76e8791d1eefd856ad04685dd8c84dca30300","fork_version":"00000000"},{"pubkey":"b3386a09faa3be115be868f91fbf40578e5348939c8334972c0b8fe1863de41054df0cec5c2d5afd3c8626dbd9cce3aa","withdrawal_credentials":"00562da2d668d7078f9113be4b8bbad051648f83781bbd993ab48d81e1b91f3f","amount":32000000000,"signature":"ab488549976c1cb025ba4fb6cbb083c469d94a929b361b2f747a614e554213788fff157d0241850826db5c31cbf4d6db027623fd2a6b66a50b2ffec2da434c75bed3a8c2fe9b24493018217e71426ae8985d1aa652ce4a95afd7b509350e5866","deposit_message_root":"1eacf42c57bb1330053f5397046a24c32c91a8df082380da0aa71d25f29a0c64","deposit_data_root":"e7a3f4eaeed5137d72fe1e025facd45d7969469923ed45b058e3f4fc31c045e4","fork_version":"00000000"},{"pubkey":"b6bcf566c45bef5607d95865757c02a2153f7bd858d036665dc835a0cceff60a6403bf4d21627600d078ff6c7e4d8b53","withdrawal_credentials":"006b5ae93f7241d786a8529aa271cd25b98e6af9423a61bc5204a9c9efda28ae","amount":32000000000,"signature":"a955e7aef4a554510e6684b51300b7eaccbd5f748091a0cbeec7a27f265d9177652d6837a7432c246f7df8daa7afd4700bf42b7afa0aa2e697152f4d86e9728c92f68fe19c86b214076f21ed0f7f665cb8a1b6b66e969a8de66fca78a8550ed3","deposit_message_root":"958a33a942837b7cb41b268051a5f1fd69b4157da8225c8affdaaaf960dd8196","deposit_data_root":"9fa9c4f2833e6bada2f7ea27bf46f821acced35e9c2b8aca987336379eed8dee","fork_version":"00000000"},{"pubkey":"85c250d005163b8f9e1f1de9a9505727dd349c69c6613494d37b6b1e314727f5e6b80eb32805cc54ac2b851ff75cf275","withdrawal_credentials":"0095e062747d01348b0808cc99b66ab2492d156eeaf570edf5b3d5e3aab90695","amount":32000000000,"signature":"9780be8b209ec07d6d820ce75aeb9846bb71afddfe4373ce33c809f1121573a2574af57d283f91eb7fc8e05af88482c60956fb4c2df7cde2d6a852f2084c288205904ae71d3d5bdc3de9eda8149e6284f6ebe3c4cc8f62e7510e688bedd6fbc6","deposit_message_root":"ba18051c4867aa3d4128c7686f6c6c2e1c1fb30ae05dfdae14d7a5f80bb85bef","deposit_data_root":"4f2bc282bad2f92989efca9366a6c1a73278732a9dad7ecc80be9d9cd3a35e70","fork_version":"00000000"},{"pubkey":"842b47897d2f335919df34c989817190fb993965cda53aa73f1633ce581fbfdad7eb64c80ed89fdc85d524f906394217","withdrawal_credentials":"00b1c7b3374245ac28c3159bb431abaaec0ecb99dd91a48a2ab39a306affd57c","amount":32000000000,"signature":"a83e4fccbe80a1f125d86149c484870700ebddd226dbf855625b878e75a102c93b9735a5b7d1720b779a92b28f21c200055fd7db3e7ca0752dd99509da1bf72d5892779661863dee67727c6488f444c7fae793cf2018e713ecf693419adc08df","deposit_message_root":"1d1b3cab44a24527f8dea92d670d0096d208a2a0935c822f14709b9394d105de","deposit_data_root":"c2247019af0890b789d5b5846c33581e2e2463889452b0086a7bfe0723de7402","fork_version":"00000000"},{"pubkey":"9997ca462621ba46a5988971bdab4a61a482817172312f96e046c5e364946383573d945c59ab8c1242def7be4b2ec146","withdrawal_credentials":"00620a1fd496eeba4e2ad08789cc573786a3281398164f2ef88ef2a1ca4d21ae","amount":32000000000,"signature":"870a364e75e7549a6fd26934cf6254180d70cd799e9d6cd7a60aed5cc98a574a318c289022d7816cb53236f2f948f083073ac00c5cd65774ce98ea9146f5ebd7eb80a4ea25dc91551f79173416aeddc4a9d086fe521fc2cc4d04a506b09a81a8","deposit_message_root":"2b1d794a79b2b14afef065d4f47327d2f7c1287d7bd7f24bdc91fa8aef6c5c2f","deposit_data_root":"16c7875b6c788f5f0c5be27356d6416e11f3c8d964909bc7c4d6b2d68140eef9","fork_version":"00000000"},{"pubkey":"b1c355f22b9b9c34ceeeaddfe2a58ccf3122c8706b0fb85bb925a57d7a2a78b1bb191e3062381485e2884eb3ee3956c9","withdrawal_credentials":"0024ebed275c5bf01c26169a1b9854cee2853bc9ec835d9a31d67a70bfe55fc7","amount":32000000000,"signature":"80bf3d647fba09943b78984b7b63da6bedfbda364b65830b1b8c96c5409effaa5b9bd19bba39eb6013449f21f915c11b14188e89ea4d0d7391fb1ce8078f42b0453135505cf89745fbbc440fac3e0e4d72f8b441f84cdfc340b3018601a48fb1","deposit_message_root":"c5ea745041ad643d51b2ba8cd97b876addbc08d2d78babcff947b146011d16db","deposit_data_root":"7731bddff2bbb249856c1e6ef76858e5034eab9a3020ce665e99d2c8e383693e","fork_version":"00000000"},{"pubkey":"9364daa6d000495b138c8d80964f3306a32ec85680d1ddd45305f08ecb0f44d32a2e946c226cb070685b41bec663256a","withdrawal_credentials":"00156b3177c585db77d4b0ec2aa6666b94ac3359ed6f978694841fd6440e2760","amount":32000000000,"signature":"8c922cf29a0d99fda5b1c4395ff5a6d59988cf6f8153ba92e9f7cd8f52d4b3381334d1028d84cd8ca6dc047c23e8e209035183120b9aa46f744a0e826e5651c487ff33b3a7f223eb4fe5873c0e1649a27cd13206c2f01724805cc87cb2b05f6c","deposit_message_root":"c4a8f2d2b52de361d23fb2ee2e510c23fbd473901bcb4dda6e4940bbe7ea36b0","deposit_data_root":"80bcff4644c195aed0aaae08f26068e2465a62f74ae5e55025604d9ecbc0df9b","fork_version":"00000000"},{"pubkey":"8377db159c6f19b06bd212017fc249c2f1a3933b1fb0c39013e5d9dcb3d4b4160e8cd90fbcaf3985031508b60a9a0ff5","withdrawal_credentials":"00fbd0d37d113affc998d9aca7ccc465e9b1f0fa02620e37fae0166927cb9394","amount":32000000000,"signature":"b9293e66077bb9aa7828bc1fede6494935b3669a8e442b0fbdefda162fd1cbb6bba381e916f44a7b0bda341e11d670f711e92d5e409d280e4cc2ab385461f2278a2960a2a2b6a0353797dfddeb8432f0b6e7a9190a3b1902eced119dd768f411","deposit_message_root":"e19c8a8a97ba61914b78eae558ff6639453583a6fd8c82d79b2001895921ffdb","deposit_data_root":"c9e3d9db48068ff7c2c3ada848c3dc4d0c89f9e9c86a5672dd9e1b216dd1da1a","fork_version":"00000000"},{"pubkey":"b0e0bb95eabcb2daa1cc931ca15bf9f8e9335f3c131f01d309567039ab52f1c5b8cbfcf6cd5c949708a4d38542e201f4","withdrawal_credentials":"00eb24fca9debef65d6959551948b67b1fc466ea7749742e47f2420555f2b5af","amount":32000000000,"signature":"a02014f934f8a36c98e428a03fc026a08562942656292ac0e33ae5894eb713be22dc4d6d1405c4651e354ab1b8d7d08d03da9433d180b8ed71f8a691a1bf80fe2092ad9abd0922446c637d85231c6ec0eea298787424c89abfcd6b6ba87e5a90","deposit_message_root":"ca200cb2c141c9b3c26316b70d8d66e82f5c87be30e98029699b04c9a07a2584","deposit_data_root":"7363a0bed29a77fff8de0978af1f027be59fbd0c4dc7d33a27a07ed8a366f82f","fork_version":"00000000"},{"pubkey":"87a9093b834befae2523c073b34038065b329f85f1ca7c5cd617db78a9e2d27b55aa05bc7422e62510d5a8cf014257e5","withdrawal_credentials":"008ecc0a030d544a54c7142826b65a4d68c97c88fccf81c3a6446b217b9d1a29","amount":32000000000,"signature":"b0ff711a36e7355094cc9be873a67b3dab615e24ef7bb45f45d9448adb704c697314b89c899a32d6a4f16be1617355b510747f2fd1167d508615330296b35b155586ecbdaba7dc1804da5aa3b6bfa1a1c39832fc122aef967b804cf99e8c42a6","deposit_message_root":"55f472e9ccee37d48dd575f54779dcbc97a7537164003667c513144f3fd8257b","deposit_data_root":"71eab1aa33ad203dc0dc576008b837eb35d0ac3422742ee922821f527c05203e","fork_version":"00000000"},{"pubkey":"a5d1f7d985bed2bba07cedd714b078b4cfe6185a246eb277ae68098715bcd24488b0e2dc8d19f4674937cb5656a1d927","withdrawal_credentials":"00a83cbbdc9ac0e384fe4749a52ff9b71222ab3de274d15780d50d5de2e9212e","amount":32000000000,"signature":"82e807ff8fac620f3de8edf3d18cc11625961b7a9321692935d62b45b1eb859babe3beaca8e86a7ef487e05781faab7303094c2d3b30e0eff82ab63977f19f4da69811c4d3f8a8b89c00eb2da6d990087e94263f572a45eaa5ef975c42b3478a","deposit_message_root":"51d7b917c74eb693c493ce12ec28e9bbc35bca081545d44899d454b3c2bb7a39","deposit_data_root":"470d94b3bdcea8f215a16ebbfdf4077e9d9b4f5ccd84dc8c13e64d75d047c0ad","fork_version":"00000000"},{"pubkey":"a34353d86c69fc4ac08698960158a92748b6e25821b31b0c5cd764ff3d6fa5855d9d8d2aacb2260cafc8e2821a0b4343","withdrawal_credentials":"00d33af8fd431c1cfcde14a792dbb6536465f758cc0ef0d2fe1562081db1abd3","amount":32000000000,"signature":"a5d666581eb166c04c1403468882cbe312582a5560f6c56ba128a61e84a15280277c384af7f47342d33ba8604c29402c1389505c9d00953c5d38d2c51a22be0b5b48c2151edbf99569a74337ee0f7cc7899108cbeb77926736eb573160c0b6fd","deposit_message_root":"cd290e28461b0e07d9e500b22be572b9c0798131682fac8dc57c74dded3340dd","deposit_data_root":"3e55fae470f875f67a654f76eb1a3fb07e36a126bb1f8e7b8d6603233315a5f8","fork_version":"00000000"},{"pubkey":"b48cca1ccf42383065abd73587b1e93cca15fe02900611e7428aad67c4222a701e44e199ab0b488251b90083d297f75a","withdrawal_credentials":"004b0dcd69e7872f94540414018f2ab95975a89d289c6f90cb5b0679e9b8a41b","amount":32000000000,"signature":"ae2969f2cf59a1a5f6850befa83ecb4a8c639f6ac00199072ec38f40fe91889ddcc921a7f143d7f1117f41fa6dc1a9c310e7db9744768fb99f136ce0b85722a06d3af48b096ef6a8ab98605235161302578e4b86a19dcfe9c036d4d83e6c7074","deposit_message_root":"fd9ba0f12bbd6ba47d59866e10e3f3298954d5861d1ad4802a4ff070c7c2582d","deposit_data_root":"cf13f22ad7e92a623431d066142b79e13f09fd5ea7a4a962ae7ce94e439255df","fork_version":"00000000"},{"pubkey":"8ab6b5ed1e3cedb684b8b604221567d55ad5b48c4aecf8b23fc988bdc78000ce26f6e0f6efff7ff3557ebbbebd04ef61","withdrawal_credentials":"00b9ca682f12945b77baa5d007f36c4362ca4cc8cf92d4f4fcb63fc8156b21c1","amount":32000000000,"signature":"9239cc1227daf167c20c6750179ef9e275c42cf1290c2bca77535edf0621833f50139b1db588eaa53eea7768e7f873240c103b4d77ba16732c89c18ec9eaa2baa884c481c5e114a6b14dbd171b7f012c7f3dbc444dbeadc0b09c810ac4d92a57","deposit_message_root":"934e176cf2d2b72a6f26b778e088a372582d481191a8bed9de826e178ce30b28","deposit_data_root":"47030eab354bf5e43ff2971b4ea1fd02ecb8df850ace5c5c2e58e5a46b1bffab","fork_version":"00000000"},{"pubkey":"b15be8807d46e9bb9428a5442cb994c1ebe5f77459df518dc62cf38e9c291a0b0f9ade6a336841e247d55b8a372edcb9","withdrawal_credentials":"00dbf908d2149b8c12445f2f0da2083d4707d58db243fff46dfdcdb7f193f9d3","amount":32000000000,"signature":"a5d7d184fa1e3d3985f278bfc39067ef3590152bb363f788d9889c49e1ffae6be0d43bc51c9a4a5cf06aa49110bc541512e541538e8d55a17c3af16c991f6b633df52f1445ad68747b8b93b550782ea391518b6f22800cceb4a676a411c81775","deposit_message_root":"3d49c8c512f99612e276b450fd13bb7a55784eff8fa7da6b154021e78d876b25","deposit_data_root":"6f604ad5ea602a73ee3b8374774d63e399b2524d0af07ccc522064d3432f53e2","fork_version":"00000000"},{"pubkey":"b0f33dd02682ac8406aea86ebefe8cdde946f0d840a8442a5ec4496d03fe3c7cd89c4515847721d0fa150005b98f2c3a","withdrawal_credentials":"0081718c0eeee2e974166f23531952a31ce800f446240c28bfa953a0df39a5e2","amount":32000000000,"signature":"885b29fd6328269feba77cdf6b5986a6cb099aa53152b10ebc5a6ebc1af91aa22d2be268bf57d9d1a12dd0a86b5063ad07e5a3681b8537d7b23a6aecad09d06b0b6ac33c2d5844b0359d94622875d19acd0981fce1afc71ba42a53b82d3b9ada","deposit_message_root":"131e8c87c3c00862f36483552ee9d0b0f2d89567594ec38054a432ae180a1dd1","deposit_data_root":"2bf16e72722f878b2610d3ee3d1a2f9ace0a9a0512cb911ce3159503f36a5a08","fork_version":"00000000"},{"pubkey":"b0f464fe938e9279ddf6cd4072285363984f93c8d6bfd5e7ce94124d54fa16bce96fe0452173d5ecd2fed6b61f116c0b","withdrawal_credentials":"00805daf054cf5fba234e7d49e3569e349fb4a0c89313004e557953e91c04a54","amount":32000000000,"signature":"acf689aa9ac847550c583a471233070cc8a93d8b1cacabb5a66b4700be77977c74a592444ac0a2b421e8c865448d3841108a1c133c13a9100d80bb51e5710b51d8d6c3cd529cca5799e9dcb70766a700b68f9efd2786ba74e6d3cebd721bf682","deposit_message_root":"64d47b513fa3b78294a11394b1070d5b5a2ebed42a8392290f605665c8564698","deposit_data_root":"86dd1f3918fbf8138aa9d0cfec7d5503d8e0688581d2f433863d6f82d0007f7a","fork_version":"00000000"},{"pubkey":"93737d75235b7ef7ac7422cd31c00afac950b4376e5cf98468e25de6258d2c03a76035df6a6c89c4a015597eb4f0d3fc","withdrawal_credentials":"00ef263a90a55ddf8e15c9f2a53033f65337e4c748a9daa1a3450f045bcf17b4","amount":32000000000,"signature":"8f59e17d909b0fc81d66469b798b7d028a9fde71609ad5d43c10af436234e85b5b40d5897a55f21f9bc0996f3348d87e13ac13787c0e694ab8200b9b2e59c21d513e1dd8c838312c2b9b53243a362d6745610d3ec376f3234d64774e4c0644f6","deposit_message_root":"1b0f9cd2fd37cc759e7b5a6d3fb54d1b3cda81edcecebfc8b7ab66f055b2bcdf","deposit_data_root":"8c269ed13cb537b9b63bf2bafd9813345a461937a2b78062452cfbadc50eb64c","fork_version":"00000000"},{"pubkey":"a5451d7b02b2241f0df105288154fcda8517d59a8fc758676c04997c0ab02d8d265e4728970da3d894fc5f5431af4c53","withdrawal_credentials":"005f7e57f4abba816e0e2596f511fc9a25376c378875ff7273a36e7c93b3dbae","amount":32000000000,"signature":"b49f92aadeac8dfa7dcde3c8d47ff04bf6d65f3029bf073943c186c629ff883c9f43edbf0822a4b55b07b760ad59bb010f0f103929c3e198dcd968ad8b7500173838b6af249f5d2165385657fe04c62d17e884a9d3cb09cf3410e142525e3873","deposit_message_root":"6b517dabad77a81eb2760e9012ba30bc162d9de0983e7547a7f23d0461b62735","deposit_data_root":"be58fa93894e7dc816a52824e458e6d55bbfb2e5cf10e6cf95d7a5fab41b4e9c","fork_version":"00000000"},{"pubkey":"a6fc251771b193b3121424b9e5eea580ee4fd7355d3be1e6c6e2aa1155bd8bd247db4d82e6a9a3aab76e8aacbfb00ae1","withdrawal_credentials":"00e1285823937debe592ca67e61656eb3177ce7d14359ebb82f39052245595f5","amount":32000000000,"signature":"a55ae87bf2c15d8b8b1e8e65859668b6cbb818f462e5dd236dcd54d17cb28fbb6c288d2b04e0a3b48b09af5c5c0745cf0f636a14da37c86b989330c6e0427683e2259c1dec290d745f12877ef80bf7e7d69e566e14c4f7ae37b9986acb46788d","deposit_message_root":"01058c2171e54fd39db0395597007f2879b8e26b8a709f5c4a50a0df9f720ba5","deposit_data_root":"47dbb52e053094c7f3db2d3caeb90ee4056093f39206172afe044d39ff076c35","fork_version":"00000000"},{"pubkey":"b93b74b64c52238777eae5ad0f0c79eca42ca6a053f233dd55a907ae58f5614313cd80f71bdb5184d02f5209379d2fdb","withdrawal_credentials":"00d67293e923dd34b6ce8573499f9bbcf8bd9dd07d080abd6e7209f21bd79849","amount":32000000000,"signature":"b3508cdaf88e6dd809fc8b7e60534514b7801c6b44d070a81934d55a9f8b091e716b851c2d2a138f5f2727dfe7e67795057e59d3ab36aef48b832c86639959f2f4f193107c5bd08c4011f329764a1da5dc90295e8fd27f61d87ac4e599d3cc6f","deposit_message_root":"63b60df52a35ac2a7911845dbf29b98c1a457651323bb9c7b84653c2557c1421","deposit_data_root":"ecf298161120bc0da9935062252ee9b2ef40fba9d87300733e8d16c4f1144c10","fork_version":"00000000"},{"pubkey":"8309a5281dd43297a3eccc1e70553831ec4dbf6a0b5b38fc910b49fb4eecf37075c90269443fd5fc6b8cad701e3eec53","withdrawal_credentials":"0030e313787d04452eaaac4b3637e5db86733e71441abc9728309fd2fea1d48b","amount":32000000000,"signature":"a495c09661d88b28cf9064b082b6f78b6ece1882e38ba5bd0fd3eaffed207170b232bd92ab2fd0bad433437dcd7f030707561e41c5a8422b80bca150d05eff7b5a3e604b6c833c2300262a5a44cddec532092b479381925c0c04dc0bc52799c7","deposit_message_root":"9a4edbce5f2242cc538a2bf806c44007238724bbef6f243a4b3903000010e547","deposit_data_root":"bf10044c5952060578c3c8c5c47e5ddfe8aab8d120d32be0fbdffe4863e7a5b6","fork_version":"00000000"},{"pubkey":"b91d92c0e32cd11fd729929919ff8e0976b3961a32062d992361d5104e5a1afaabeb811b4791ed39ba849799e6a15b1a","withdrawal_credentials":"00e6c93ab29958b6327e72e1925bb038ada73c5b63a1f1b16007ae232a197640","amount":32000000000,"signature":"b0462da7435d72a0e96f901827e473a5912c4c11ff2cb4ec0a6053e164f609e7013e0a223f5092d362ff75f3df7624b60d4c897adf105272a7060144f5ec833a133d179809987f36527f90229c94c684839170b34c5855ad410a662a82a1b6ee","deposit_message_root":"92efc613379f4ed1360e33f677caf8108c60c634f26422ffd1c2ff31e4bf05fc","deposit_data_root":"1a450d01f786638c2bd40ae9086f85ccc7993f15d48661c3dd200a6dc78b4233","fork_version":"00000000"},{"pubkey":"a66a5b7d1dfe156e65f239e885282d7fb1f6879afa483e05092a9001e6228af5ba47573882d9f0e7e8b13685d21a3d0c","withdrawal_credentials":"00eb7ed248fdcfdae5b5f90ac8361732bc47e3cc18141577b4ba15e351f66b59","amount":32000000000,"signature":"8ed412ba8e58b5865796351290977cfbf8291f71dbfb780930ccfc967263356e406fb8e9013d6be3a77b47cf1565f3bf0b4cedb33b18df31a0476e690cafd751b545655fa379b2b5c32cc7b4fe57bc581d5fe5854e8aa55a05a0ded78bd342ba","deposit_message_root":"c0a4e2c7fbb6bdde1f6a13f357f06d7bde77e9e7225ae896deeed15a8a1e4351","deposit_data_root":"049f1b20a8decea97b52f797ec097b56607ecd03cea10a2dfc25b65a106224bf","fork_version":"00000000"}] \ No newline at end of file diff --git a/testnet/prysm/setup.sh b/testnet/prysm/setup.sh new file mode 100755 index 000000000..ef65998e7 --- /dev/null +++ b/testnet/prysm/setup.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# +# Produces a testnet specification and a genesis state where the genesis time is now. +# + +source ./vars.env +source ../../.env + +docker run -v $TESTNET_DIR:/data $DOCKER_GENESIS_STATE_GEN_IMAGE \ + --output-ssz=/data/genesis.ssz \ + --num-validators=$VALIDATOR_COUNT \ + --mainnet-config=true + +echo Created genesis state in $TESTNET_DIR diff --git a/testnet/prysm/vars.env b/testnet/prysm/vars.env new file mode 100644 index 000000000..063c5abb0 --- /dev/null +++ b/testnet/prysm/vars.env @@ -0,0 +1,6 @@ +DATADIR=$PWD +TESTNET_DIR=$DATADIR/data + +VALIDATOR_COUNT=16 + +DOCKER_GENESIS_STATE_GEN_IMAGE=gcr.io/prysmaticlabs/prysm/genesis-state-gen@sha256:fd2c9a33f2c492e5e76b0f2a437a6a2aa5170dde8447deae657a10d35fc12113