Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: add support for web3.js to simulation tests #6641

Merged
merged 7 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 0 additions & 53 deletions packages/cli/test/utils/simulation/Eth1ProviderWithAdmin.ts

This file was deleted.

4 changes: 2 additions & 2 deletions packages/cli/test/utils/simulation/SimulationEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,9 @@ export class SimulationEnvironment {
const el = this.nodes[i].execution;

// If eth1 is mock then genesis hash would be empty
const eth1Genesis = el.provider === null ? {hash: MOCK_ETH1_GENESIS_HASH} : await el.provider.getBlockByNumber(0);
const eth1Genesis = el.web3 === null ? {hash: MOCK_ETH1_GENESIS_HASH} : await el.web3?.eth.getBlock(0);

if (!eth1Genesis) {
if (!eth1Genesis.hash) {
throw new Error(`Eth1 genesis not found for node "${this.nodes[i].id}"`);
}

Expand Down
41 changes: 41 additions & 0 deletions packages/cli/test/utils/simulation/Web3Plugins.ts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know the simulation rig has file names in PascalCase but not sure that is the right way to go. Can we name this file web3JsPlugins.ts

Copy link
Contributor Author

@nazarhussain nazarhussain Apr 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know the simulation rig has file names in PascalCase but not sure that is the right way to go. Can we name this file web3JsPlugins.ts

Let's do the renaming of all files for consistent pattern in different PR.

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import {Web3PluginBase, Web3} from "web3";

class Web3AdminPlugin extends Web3PluginBase {
pluginNamespace = "admin";
nazarhussain marked this conversation as resolved.
Show resolved Hide resolved

async nodeInfo(): Promise<{
enode: string;
id: string;
ip: string;
listenAddr: string;
name: string;
ports: {
discovery: number;
listener: number;
};
protocols: {
eth: {
difficulty: number;
genesis: string;
head: string;
network: number;
};
};
}> {
return this.requestManager.send({method: "admin_nodeInfo", params: []});
}

async addPeer(enode: string): Promise<boolean> {
return this.requestManager.send({method: "admin_addPeer", params: [enode]});
}
}

declare module "web3" {
interface Web3Context {
admin: Web3AdminPlugin;
}
}

export function registerWeb3Plugins(web3: Web3): void {
nazarhussain marked this conversation as resolved.
Show resolved Hide resolved
web3.registerPlugin(new Web3AdminPlugin());
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import {EL_GENESIS_ACCOUNT} from "../constants.js";
import {AssertionMatch, AssertionResult, NodePair, SimulationAssertion} from "../interfaces.js";

function hexToBigInt(num: string): bigint {
return num.startsWith("0x") ? BigInt(num) : BigInt(`0x${num}`);
}

function bigIntToHex(num: bigint): string {
return `0x${num.toString(16)}`;
}

const transactionAmount = BigInt(2441406250);

export function createAccountBalanceAssertion({
Expand All @@ -30,17 +22,12 @@ export function createAccountBalanceAssertion({
return AssertionMatch.None;
},
async capture({node}) {
await node.execution.provider?.getRpc().fetch({
method: "eth_sendTransaction",
params: [
{
to: address,
from: EL_GENESIS_ACCOUNT,
gas: "0x76c0",
gasPrice: "0x9184e72a000",
value: bigIntToHex(transactionAmount),
},
],
await node.execution.web3?.eth.sendTransaction({
to: address,
from: EL_GENESIS_ACCOUNT,
gas: "0x76c0",
gasPrice: "0x9184e72a000",
value: transactionAmount,
});

// Capture the value transferred to account
Expand All @@ -57,10 +44,7 @@ export function createAccountBalanceAssertion({
expectedBalanceAtCurrentSlot += BigInt(store[captureSlot]);
}

const balance = hexToBigInt(
(await node.execution.provider?.getRpc().fetch({method: "eth_getBalance", params: [address, "latest"]})) ??
"0x0"
);
const balance = await node.execution.web3?.eth.getBalance(address, "latest");

if (balance !== expectedBalanceAtCurrentSlot) {
errors.push(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ export function createExecutionHeadAssertion({
return AssertionMatch.None;
},
async capture({node}) {
const blockNumber = await node.execution.provider?.getBlockNumber();
const blockNumber = await node.execution.web3?.eth.getBlockNumber();
if (blockNumber == null) throw new Error("Execution provider not available");
const executionHeadBlock = await node.execution.provider?.getBlockByNumber(blockNumber);
const executionHeadBlock = await node.execution.web3?.eth.getBlock(blockNumber);

const consensusHead = await node.beacon.api.beacon.getBlockV2("head");
ApiError.assert(consensusHead);
Expand Down
14 changes: 5 additions & 9 deletions packages/cli/test/utils/simulation/execution_clients/geth.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
/* eslint-disable @typescript-eslint/naming-convention */
import {writeFile} from "node:fs/promises";
import path from "node:path";
import got from "got";
import {ZERO_HASH} from "@lodestar/state-transition";
import {Web3} from "web3";
import {
EL_GENESIS_ACCOUNT,
EL_GENESIS_PASSWORD,
EL_GENESIS_SECRET_KEY,
SHARED_JWT_SECRET,
SIM_ENV_NETWORK_ID,
} from "../constants.js";
import {Eth1ProviderWithAdmin} from "../Eth1ProviderWithAdmin.js";
import {registerWeb3Plugins} from "../Web3Plugins.js";
import {ExecutionClient, ExecutionNodeGenerator, ExecutionStartMode, JobOptions, RunnerType} from "../interfaces.js";
import {getNodeMountedPaths} from "../utils/paths.js";
import {getNodePorts} from "../utils/ports.js";
Expand Down Expand Up @@ -166,11 +165,8 @@ export const generateGethNode: ExecutionNodeGenerator<ExecutionClient.Geth> = (o

const job = runner.create([{...initJobOptions, children: [{...importJobOptions, children: [startJobOptions]}]}]);

const provider = new Eth1ProviderWithAdmin(
{DEPOSIT_CONTRACT_ADDRESS: ZERO_HASH},
// To allow admin_* RPC methods had to add "ethRpcUrl"
{providerUrls: [ethRpcPublicUrl, engineRpcPublicUrl], jwtSecretHex: SHARED_JWT_SECRET}
);
const web3 = new Web3(ethRpcPublicUrl);
registerWeb3Plugins(web3);
nazarhussain marked this conversation as resolved.
Show resolved Hide resolved

return {
client: ExecutionClient.Geth,
Expand All @@ -181,7 +177,7 @@ export const generateGethNode: ExecutionNodeGenerator<ExecutionClient.Geth> = (o
ethRpcPrivateUrl,
ttd,
jwtSecretHex: SHARED_JWT_SECRET,
provider,
web3,
job,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const generateMockNode: ExecutionNodeGenerator<ExecutionClient.Mock> = (o
ethRpcPrivateUrl,
ttd,
jwtSecretHex: SHARED_JWT_SECRET,
provider: null,
web3: null,
job,
};
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
/* eslint-disable @typescript-eslint/naming-convention */
import {writeFile} from "node:fs/promises";
import path from "node:path";
import got from "got";
import {ZERO_HASH} from "@lodestar/state-transition";
import {Eth1ProviderWithAdmin} from "../Eth1ProviderWithAdmin.js";
import {Web3} from "web3";
import {registerWeb3Plugins} from "../Web3Plugins.js";
import {ExecutionClient, ExecutionNodeGenerator, JobOptions, RunnerType} from "../interfaces.js";
import {getNethermindChainSpec} from "../utils/execution_genesis.js";
import {getNodeMountedPaths} from "../utils/paths.js";
Expand Down Expand Up @@ -130,11 +129,8 @@ export const generateNethermindNode: ExecutionNodeGenerator<ExecutionClient.Neth

const job = runner.create([startJobOptions]);

const provider = new Eth1ProviderWithAdmin(
{DEPOSIT_CONTRACT_ADDRESS: ZERO_HASH},
// To allow admin_* RPC methods had to add "ethRpcUrl"
{providerUrls: [ethRpcPublicUrl, engineRpcPublicUrl], jwtSecretHex: SHARED_JWT_SECRET}
);
const web3 = new Web3(ethRpcPublicUrl);
registerWeb3Plugins(web3);
nazarhussain marked this conversation as resolved.
Show resolved Hide resolved

return {
client: ExecutionClient.Nethermind,
Expand All @@ -145,7 +141,7 @@ export const generateNethermindNode: ExecutionNodeGenerator<ExecutionClient.Neth
ethRpcPrivateUrl,
ttd,
jwtSecretHex: SHARED_JWT_SECRET,
provider,
web3,
job,
};
};
4 changes: 2 additions & 2 deletions packages/cli/test/utils/simulation/interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/naming-convention */
import {ChildProcess} from "node:child_process";
import type {SecretKey} from "@chainsafe/bls/types";
import Web3 from "web3";
import {Api} from "@lodestar/api";
import {Api as KeyManagerApi} from "@lodestar/api/keymanager";
import {ChainForkConfig} from "@lodestar/config";
Expand All @@ -11,7 +12,6 @@ import {BeaconArgs} from "../../../src/cmds/beacon/options.js";
import {IValidatorCliArgs} from "../../../src/cmds/validator/options.js";
import {GlobalArgs} from "../../../src/options/index.js";
import {EpochClock} from "./EpochClock.js";
import {Eth1ProviderWithAdmin} from "./Eth1ProviderWithAdmin.js";

export type NodeId = string;

Expand Down Expand Up @@ -208,7 +208,7 @@ export interface ExecutionNode<E extends ExecutionClient = ExecutionClient> {
*/
readonly ethRpcPrivateUrl: string;
readonly jwtSecretHex: string;
readonly provider: E extends ExecutionClient.Mock ? null : Eth1ProviderWithAdmin;
readonly web3: E extends ExecutionClient.Mock ? null : Web3;
readonly job: Job;
}

Expand Down
7 changes: 4 additions & 3 deletions packages/cli/test/utils/simulation/utils/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,17 @@ export async function connectNewCLNode(newNode: BeaconNode, nodes: BeaconNode[])
}

export async function connectNewELNode(newNode: ExecutionNode, nodes: ExecutionNode[]): Promise<void> {
const elIdentity = newNode.provider === null ? null : await newNode.provider.admin.nodeInfo();
const elIdentity = newNode.web3 === null ? null : await newNode.web3?.admin.nodeInfo();
if (elIdentity && !elIdentity.enode) return;

for (const node of nodes) {
if (node === newNode) continue;

// Nethermind had a bug in admin_addPeer RPC call
// https://github.com/NethermindEth/nethermind/issues/4876
if (node.provider !== null && node.client !== ExecutionClient.Nethermind && elIdentity) {
await node.provider.admin.addPeer(elIdentity.enode);
if (node.web3 !== null && node.client !== ExecutionClient.Nethermind && elIdentity) {
// `web3.admin` here refers to the Web3 plugin `Web3AdminPlugin`
matthewkeil marked this conversation as resolved.
Show resolved Hide resolved
await node.web3.admin.addPeer(elIdentity.enode);
}
}
}
Expand Down
Loading