Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
16 changes: 8 additions & 8 deletions docs/running_tests/execute/remote.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc

The value needs to be a private key that is used to sign the transactions that deploy the contracts and fund the accounts.

One last requirement is that the `--rpc-chain-id` flag is set to the chain id of the network that is being tested:
One last requirement is that the `--chain-id` flag is set to the chain id of the network that is being tested:

```bash
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --rpc-chain-id 12345
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --chain-id 12345
```

## Engine RPC Endpoint (Optional)
Expand All @@ -31,13 +31,13 @@ By default, the `execute remote` command assumes that the execution client is co
To use this feature, you need to provide both the `--engine-endpoint` and JWT authentication:

```bash
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --rpc-chain-id 12345 --engine-endpoint=https://engine.endpoint.io --engine-jwt-secret "your-jwt-secret-here"
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --chain-id 12345 --engine-endpoint=https://engine.endpoint.io --engine-jwt-secret "your-jwt-secret-here"
```

Alternatively, you can provide the JWT secret from a file:

```bash
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --rpc-chain-id 12345 --engine-endpoint=https://engine.endpoint.io --engine-jwt-secret-file /path/to/jwt-secret.txt
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --chain-id 12345 --engine-endpoint=https://engine.endpoint.io --engine-jwt-secret-file /path/to/jwt-secret.txt
```

The JWT secret file must contain only the JWT secret as a hex string.
Expand All @@ -49,7 +49,7 @@ The `execute remote` command will connect to the client via the RPC endpoint and
It is recommended to only run a subset of the tests when executing on a live network. To do so, a path to a specific test can be provided to the command:

```bash
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --rpc-chain-id 12345 ./tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_sstore
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --chain-id 12345 ./tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_sstore
```

## Address Stubs for Pre-deployed Contracts
Expand All @@ -70,19 +70,19 @@ You can provide address stubs in several formats:
**JSON string:**

```bash
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --rpc-chain-id 12345 --address-stubs '{"DEPOSIT_CONTRACT": "0x00000000219ab540356cbb839cbe05303d7705fa", "UNISWAP_V3_FACTORY": "0x1F98431c8aD98523631AE4a59f267346ea31F984"}'
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --chain-id 12345 --address-stubs '{"DEPOSIT_CONTRACT": "0x00000000219ab540356cbb839cbe05303d7705fa", "UNISWAP_V3_FACTORY": "0x1F98431c8aD98523631AE4a59f267346ea31F984"}'
```

**JSON file:**

```bash
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --rpc-chain-id 12345 --address-stubs ./contracts.json
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --chain-id 12345 --address-stubs ./contracts.json
```

**YAML file:**

```bash
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --rpc-chain-id 12345 --address-stubs ./contracts.yaml
uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc-seed-key 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --chain-id 12345 --address-stubs ./contracts.yaml
```

### Address Stubs File Format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def command(pytest_args: List[str], **_kwargs: Any) -> None:
"Execute tests using a remote RPC endpoint.",
required_args=[
"--rpc-endpoint=http://localhost:8545",
"--rpc-chain-id=1",
"--chain-id=1",
"--rpc-seed-key=1",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
from execution_testing.rpc import EngineRPC, EthRPC
from execution_testing.specs import BaseTest
from execution_testing.test_types import (
ChainConfigDefaults,
EnvironmentDefaults,
TransactionDefaults,
)
Expand Down Expand Up @@ -106,15 +105,6 @@ def pytest_addoption(parser: pytest.Parser) -> None:
"Time to wait after sending a forkchoice_updated before getting the payload."
),
)
execute_group.addoption(
"--chain-id",
action="store",
dest="chain_id",
required=False,
type=int,
default=None,
help="ID of the chain where the tests will be executed.",
)

report_group = parser.getgroup(
"tests", "Arguments defining html report behavior"
Expand Down Expand Up @@ -172,22 +162,6 @@ def pytest_configure(config: pytest.Config) -> None:
config.skip_transition_forks = True # type: ignore[attr-defined]
config.single_fork_mode = True # type: ignore[attr-defined]

# Configure the chain ID for the tests.
rpc_chain_id = config.getoption("rpc_chain_id", None)
chain_id = config.getoption("chain_id", None)
if rpc_chain_id is not None or chain_id is not None:
if rpc_chain_id is not None and chain_id is not None:
if chain_id != rpc_chain_id:
pytest.exit(
"Conflicting chain ID configuration. "
"The --rpc-chain-id flag is deprecated and will be removed in a future "
"release. Use --chain-id instead."
)
if rpc_chain_id is not None:
ChainConfigDefaults.chain_id = rpc_chain_id
if chain_id is not None:
ChainConfigDefaults.chain_id = chain_id


def pytest_metadata(metadata: dict[str, Any]) -> None:
"""Add or remove metadata to/from the pytest report."""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Plugin that handles correct setting of chain-id and rpc-chain-id."""

import pytest

from execution_testing.test_types.chain_config_types import ChainConfigDefaults


def pytest_addoption(parser: pytest.Parser) -> None:
"""Add command-line options to pytest."""
execute_commands_group = parser.getgroup(
"execute",
"Arguments defining chain configuration for execute commands",
)
execute_commands_group.addoption(
"--chain-id",
action="store",
dest="chain_id",
required=False,
type=int,
default=None,
help="ID of the chain where the tests will be executed.",
)
execute_commands_group.addoption(
"--rpc-chain-id",
action="store",
dest="rpc_chain_id",
required=False,
type=int,
default=None,
help=(
"ID of the chain where the tests will be executed. This flag "
"is deprecated and will be removed in a future release. "
"Use --chain-id instead."
),
)


@pytest.hookimpl(tryfirst=True)
def pytest_configure(config: pytest.Config) -> None:
"""
Set the provided command-line arguments.
"""
# Skip validation if we're just showing help
if config.option.help:
return

chain_id = config.getoption("chain_id")
rpc_chain_id = config.getoption("rpc_chain_id")

if not ((chain_id is None) ^ (rpc_chain_id is None)): # XOR
pytest.exit(
"ERROR: you must either pass --chain-id or --rpc-chain-id, "
"but not both!\n"
f"You passed: chain-id={chain_id}, rpc-chain-id={rpc_chain_id}",
returncode=4,
)

# Use rpc_chain_id if chain_id is not provided (for backwards compatibility)
if not chain_id:
chain_id = rpc_chain_id

# write to config
ChainConfigDefaults.chain_id = chain_id
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,6 @@ def pytest_addoption(parser: pytest.Parser) -> None:
dest="rpc_endpoint",
help="RPC endpoint to an execution client",
)
remote_rpc_group.addoption(
"--chain-id",
action="store",
dest="chain_id",
required=False,
type=int,
default=None,
help="ID of the chain where the tests will be executed.",
)
remote_rpc_group.addoption(
"--rpc-chain-id",
action="store",
dest="rpc_chain_id",
required=False,
type=int,
default=None,
help="DEPRECATED: ID of the chain where the tests will be executed. "
"This flag is deprecated and will be removed in a future release."
"Use --chain-id instead.",
)
remote_rpc_group.addoption(
"--tx-wait-timeout",
action="store",
Expand Down Expand Up @@ -100,27 +80,6 @@ def pytest_addoption(parser: pytest.Parser) -> None:

def pytest_configure(config: pytest.Config) -> None:
"""Check if a chain ID configuration is provided."""
rpc_chain_id = config.getoption("rpc_chain_id", None)
chain_id = config.getoption("chain_id", None)

if rpc_chain_id is None and chain_id is None:
pytest.exit("No chain ID configuration found. Please use --chain-id.")

# Handle both --chain-id and deprecated --rpc-chain-id
if rpc_chain_id is not None and chain_id is not None:
if chain_id != rpc_chain_id:
pytest.exit(
"Conflicting chain ID configuration. "
"The --rpc-chain-id flag is deprecated and will be removed in a future "
"release. Use --chain-id instead."
)

# Set the chain ID
if chain_id is not None:
ChainConfigDefaults.chain_id = chain_id
elif rpc_chain_id is not None:
ChainConfigDefaults.chain_id = rpc_chain_id

# Verify the chain ID configuration is consistent with the remote RPC endpoint
rpc_endpoint = config.getoption("rpc_endpoint")
eth_rpc = EthRPC(rpc_endpoint)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def pytest_configure(config: pytest.Config) -> None:
"pre-allocation behavior during test execution",
"sender key fixtures",
"remote seed sender",
"chain configuration",
],
)
elif config.getoption("show_execute_hive_help"):
Expand All @@ -124,6 +125,7 @@ def pytest_configure(config: pytest.Config) -> None:
"pre-allocation behavior during test execution",
"sender key fixtures",
"remote seed sender",
"chain configuration",
],
)
elif config.getoption("show_execute_recover_help"):
Expand All @@ -134,6 +136,7 @@ def pytest_configure(config: pytest.Config) -> None:
"fund recovery",
"remote RPC configuration",
"remote seed sender",
"chain configuration",
],
)
elif config.getoption("show_execute_eth_config_help"):
Expand All @@ -142,6 +145,7 @@ def pytest_configure(config: pytest.Config) -> None:
"pytest-execute-eth-config.ini",
[
"eth_config",
"chain configuration",
],
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ minversion = 7.0
python_files = *.py
# Note: register new markers via src/execution_testing/cli/pytest_commands/plugins/shared/execute_fill.py
addopts =
-p execution_testing.cli.pytest_commands.plugins.execute.execute_flags.execute_flags
-p execution_testing.cli.pytest_commands.plugins.execute.eth_config.eth_config
-p execution_testing.cli.pytest_commands.plugins.help.help
-p execution_testing.cli.pytest_commands.plugins.custom_logging.plugin_logging
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ console_output_style = count
minversion = 7.0
python_files = *.py
addopts =
-p execution_testing.cli.pytest_commands.plugins.execute.execute_flags.execute_flags
-p execution_testing.cli.pytest_commands.plugins.execute.rpc.remote
-p execution_testing.cli.pytest_commands.plugins.execute.recover
-p execution_testing.cli.pytest_commands.plugins.help.help
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ python_files = test_*.py
testpaths = tests/
# Note: register new markers via src/execution_testing/cli/pytest_commands/plugins/shared/execute_fill.py
addopts =
-p execution_testing.cli.pytest_commands.plugins.execute.execute_flags.execute_flags
-p execution_testing.cli.pytest_commands.plugins.concurrency
-p execution_testing.cli.pytest_commands.plugins.execute.sender
-p execution_testing.cli.pytest_commands.plugins.execute.pre_alloc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,69 @@ def test_execute_subcommands_have_help_text() -> None:

assert recover.__doc__ is not None
assert "recover" in recover.__doc__.lower()


def test_execute_main_help(runner: CliRunner) -> None:
"""Test that execute --help works without errors."""
result = runner.invoke(execute, ["--help"])
assert result.exit_code == 0
assert "Execute command to run tests" in result.output


def test_execute_remote_help(runner: CliRunner) -> None:
"""Test that execute remote --help works without argument conflicts."""
result = runner.invoke(execute, ["remote", "--help"])
assert result.exit_code == 0
assert "After displaying help" in result.output
# Verify no argparse conflicts with --chain-id
assert "conflicting option string" not in result.output


def test_execute_recover_help(runner: CliRunner) -> None:
"""Test that execute recover --help works without argument conflicts."""
result = runner.invoke(execute, ["recover", "--help"])
assert result.exit_code == 0
assert "After displaying help" in result.output
# Verify --chain-id is available
assert "--chain-id" in result.output
# Verify no argparse conflicts
assert "conflicting option string" not in result.output


def test_execute_hive_help(runner: CliRunner) -> None:
"""Test that execute hive --help works without errors."""
result = runner.invoke(execute, ["hive", "--help"])
assert result.exit_code == 0
assert "After displaying help" in result.output


def test_execute_eth_config_help(runner: CliRunner) -> None:
"""Test that execute eth-config --help works without errors."""
result = runner.invoke(execute, ["eth-config", "--help"])
assert result.exit_code == 0
assert "After displaying help" in result.output


def test_all_execute_subcommands_help_no_conflicts(runner: CliRunner) -> None:
"""Test that all execute subcommands --help work without argument conflicts.

This is a regression test for issue where --chain-id was defined in multiple
plugins, causing argparse.ArgumentError conflicts.
"""
subcommands = ["remote", "recover", "hive", "eth-config"]

for subcommand in subcommands:
result = runner.invoke(execute, [subcommand, "--help"])
assert result.exit_code == 0, (
f"execute {subcommand} --help failed with exit code {result.exit_code}\n"
f"Output: {result.output}"
)
# Ensure no argparse conflicts
assert "ArgumentError" not in result.output, (
f"execute {subcommand} --help has ArgumentError\n"
f"Output: {result.output}"
)
assert "conflicting option string" not in result.output, (
f"execute {subcommand} --help has conflicting option string\n"
f"Output: {result.output}"
)
2 changes: 1 addition & 1 deletion tests/benchmark/stateful/bloatnet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Create a JSON file (`stubs.json`) mapping test-specific stub names to deployed c
uv run execute remote \
--rpc-endpoint http://localhost:8545 \
--rpc-seed-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \
--rpc-chain-id 1337 \
--chain-id 1337 \
--address-stubs geth_stubs.json \
--fork Prague \
tests/benchmark/stateful/bloatnet/test_single_opcode.py::test_sload_empty_erc20_balanceof \
Expand Down
Loading