launch_anvil
Documentation for eth_defi.provider.anvil.launch_anvil function.
- launch_anvil(fork_url=None, unlocked_addresses=None, cmd='anvil', port=(19999, 29999, 25), block_time=0, launch_wait_seconds=20.0, attempts=3, hardfork='cancun', gas_limit=None, steps_tracing=False, test_request_timeout=3.0, fork_block_number=None, log_wait=False, code_size_limit=None, rpc_smoke_test=True, verbose=False, inherit_stdio=False, warm_up_block=False, archive=True, proxy_multiple_upstream=True)
Creates Anvil unit test backend or mainnet fork.
Anvil can be used as web3.py test backend instead of EthereumTester. Anvil offers faster execution and tracing - see
eth_defi.trace.Forking a mainnet is a common way to test against live deployments. This function invokes anvil command and tells it to fork a given JSON-RPC endpoint.
When called, a subprocess is started on the background. To stop this process, call
eth_defi.anvil.AnvilLaunch.close().This function waits launch_wait_seconds in order to anvil process to start and complete the chain fork.
Unit test backend:
See eth_defi.tests.enzyme.conftest for an example how to use Anvil in your Python based unit test suite
Mainnet fork: Here is an example that forks BNB chain mainnet and transfer 500 BUSD stablecoin to a test account we control:
from eth_defi.anvil import fork_network_anvil from eth_defi.chain import install_chain_middleware from eth_defi.gas import node_default_gas_price_strategy @pytest.fixture() def large_busd_holder() -> HexAddress: # An onchain address with BUSD balance # Binance Hot Wallet 6 return HexAddress(HexStr("0x8894E0a0c962CB723c1976a4421c95949bE2D4E3")) @pytest.fixture() def user_1() -> LocalAccount: # Create a test account return Account.create() @pytest.fixture() def anvil_bnb_chain_fork(request, large_busd_holder, user_1, user_2) -> str: # Create a testable fork of live BNB chain. mainnet_rpc = os.environ["BNB_CHAIN_JSON_RPC"] launch = fork_network_anvil(mainnet_rpc, unlocked_addresses=[large_busd_holder]) try: yield launch.json_rpc_url finally: # Wind down Anvil process after the test is complete launch.close(log_level=logging.ERROR) @pytest.fixture() def web3(anvil_bnb_chain_fork: str): # Set up a local unit testing blockchain # https://web3py.readthedocs.io/en/stable/examples.html#contract-unit-tests-in-python web3 = Web3(HTTPProvider(anvil_bnb_chain_fork)) # Anvil needs POA middlware if parent chain needs POA middleware install_chain_middleware(web3) web3.eth.set_gas_price_strategy(node_default_gas_price_strategy) return web3 def test_anvil_fork_transfer_busd(web3: Web3, large_busd_holder: HexAddress, user_1: LocalAccount): # Forks the BNB chain mainnet and transfers from USDC to the user. # BUSD deployment on BNB chain # https://bscscan.com/token/0xe9e7cea3dedca5984780bafc599bd69add087d56 busd_details = fetch_erc20_details(web3, "0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56") busd = busd_details.contract # Transfer 500 BUSD to the user 1 tx_hash = busd.functions.transfer(user_1.address, 500 * 10**18).transact({"from": large_busd_holder}) # Because Ganache has instamine turned on by default, we do not need to wait for the transaction receipt = web3.eth.get_transaction_receipt(tx_hash) assert receipt.status == 1, "BUSD transfer reverted" assert busd.functions.balanceOf(user_1.address).call() == 500 * 10**18
See the full example in tests source code.
If anvil refuses to terminate properly, you can kill a process by a port in your terminal:
# Kill any process listening to localhost:19999 kill -SIGKILL $(lsof -ti:19999)
See also
Note
Looks like we have some issues Anvil instance lingering around even after AnvilLaunch.close() if scoped pytest fixtures are used.
If you intentionally keep a fork alive across multiple tests, pair a module-scoped
launch_anvil()/fork_network_anvil()fixture withcreate_anvil_snapshot_state()andreset_anvil_snapshot()so you can reset state cheaply between tests.- Parameters
cmd – Override anvil command. If not given we look up from PATH.
HTTP JSON-RPC URL of the network we want to fork.
If not given launch an empty test backend.
unlocked_addresses (list[eth_typing.evm.HexAddress | str]) – List of addresses of which ownership we take to allow test code to transact as them
Localhost port we bind for Anvil JSON-RPC.
The tuple format is (min port, max port, opening attempts).
By default, takes a tuple range and tries to open a a random port in the range, until empty found. This allows to run multiple parallel Anvil’s during unit testing with
pytest -n auto.You can also specify an individual port.
launch_wait_seconds – How long we wait anvil to start until giving up
block_time –
How long Anvil takes to mine a block. Default is zero: Anvil is in automining mode and creates a new block for each new transaction.
Set to 1 or higher so that you can poll the transaction as you would do with a live JSON-RPC node.
attempts –
How many attempts we do to start anvil.
Anvil launch may fail without any output. This could be because the given JSON-RPC node is throttling your API requests. In this case we just try few more times again by killing the Anvil process and starting it again.
step_tracing –
Enable Anvil step tracing.
Needed to get structured logs.
Only needed on GoEthereum style tracing, not needed for Parity style tracing.
test_request_timeout – Set the timeout fro the JSON-RPC requests that attempt to determine if Anvil was successfully launched.
fork_block_number (Optional[int]) –
For at a specific block height of the parent chain.
If not given, fork at the latest block. Needs an archive node to work.
HyperEVM is a special case: if the caller does not supply an explicit fork block,
launch_anvil()automatically pins the fork a few blocks behind the tip. This avoids the recurring HyperEVM failure where Anvil aborts withError: failed to create genesisbecause the upstream RPC responds with{"message":"Unknown block","code":26}while resolvinglatestduring genesis creation.rpc_smoke_test – Check that the RPC is working before attempting to start Anvil
verbose –
Make Anvil the proces to dump a lot of stuff to stdout/stderr.
inherit_stdio (bool) –
If
True, let the Anvil subprocess inherit the parent process stdout/stderr instead of capturing them in pipes.This is useful in Docker and other supervised environments where you want Anvil logs to appear live in the container logs.
Warning
When
False(default), stdout/stderr are captured and only read when the process is shut down. If Anvil is very chatty, those pipe buffers can fill up and stall the subprocess.warm_up_block (bool) –
If
Trueand running in fork mode, eagerly calleth_getBlockByNumber(fork_block, true)against the freshly started local Anvil instance.This can move an expensive first fork hydration from an arbitrary later request to startup. It does not remove the cost, but it makes it happen once, predictably, before the caller starts using the node.
archive (bool) –
Check that the RPC endpoint provides archive node access.
When True (default) and
fork_block_numberis specified, performs a smoke test to verify the RPC can access historical blocks. If the RPC cannot access the requested block, raisesArchiveNodeRequiredwith HTTP response headers to help identify the problematic RPC provider.proxy_multiple_upstream (RPCProxy | RPCProxyConfig | bool) –
Controls how multiple upstream RPC providers in
fork_urlare handled.Background: Anvil accepts only a single
--fork-urland has no internal retry or failover logic. When the upstream is slow or rate-limited, Anvil hangs indefinitely. This parameter enables a transparent JSON-RPC proxy (RPCProxy) that sits between Anvil and multiple upstreams, providing automatic failover, per-request timeouts, and diagnostics.The proxy is only relevant when
fork_urlcontains multiple space-separated RPC URLs. With a single URL this parameter is ignored.Accepted values:
``True`` (default) — automatically start a proxy with default settings when multiple RPCs are detected. The proxy lifecycle is tied to
AnvilLaunch.close(): it starts before Anvil and shuts down (logging per-provider statistics) after Anvil exits.``False`` — disable the proxy entirely. Falls back to the legacy behaviour of picking one RPC in round-robin order per
launch_anvil()call, with no intra-session failover.An :py:class:`~eth_defi.provider.rpc_proxy.RPCProxyConfig` instance — automatically start a proxy with custom settings. Any fields not set explicitly use their dataclass defaults. Example:
from eth_defi.provider.rpc_proxy import RPCProxyConfig launch_anvil( fork_url="https://rpc-a.example.com https://rpc-b.example.com", proxy_multiple_upstream=RPCProxyConfig( timeout=15.0, retries=5, auto_switch_request_count=50, ), )An :py:class:`~eth_defi.provider.rpc_proxy.RPCProxy` instance — use a proxy that you created yourself via
start_rpc_proxy(). Useful when you need full control over the proxy lifecycle or want to share a single proxy across multiple Anvil instances. In this caselaunch_anvildoes not manage the proxy lifecycle — you must callclose()yourself.
See
eth_defi.provider.rpc_proxyfor the full proxy API.code_size_limit (int) –
- Parma code_size_limit
Max smart contract size
- Parma log_wait
Display info level logging while waiting for Anvil to start.
- Raises
ArchiveNodeRequired – When
archive=Trueand the RPC endpoint cannot access the requested historical block.- Return type