In-Memory Node
This section provides instructions on setting up and using the In-Memory Node, era_test_node
, for local testing.
It covers installation, network forking, transaction details viewing, replaying transactions, and testing local bootloader and system contracts.
era-test-node
is still in its alpha stage,
some features might not be fully supported yet and may not work as fully intended.
It is open-sourced and contributions are welcomed.Understand the In-Memory Node
The In-Memory Node uses an in-memory database for storing state information and simplified hashmaps for tracking blocks and transactions. In fork mode, it retrieves missing storage data from a remote source when not available locally. Moreover it also uses the remote server (openchain) to resolve the ABI and topics to human readable names.
You can visit the era-test-node
repository to learn more.
Run actions with zksync-cli
You can setup the In-Memory Node quickly with zksync-cli dev start
.
If you don't have zksync-cli
setup, see the Overview guide.
Note: at the moment this method won't allow you to use additional features like forking networks or replaying transactions.
Install and set up era_test_node
- Download
era_test_node
from latest Release. - Extract the binary and mark as executable:
tar xz -f /path/to/downloaded/binary/era_test_node.tar.gz -C /usr/local/bin/ chmod +x /usr/local/bin/era_test_node
- Start the node:
era_test_node run
The expected output will be as follows:
12:34:56 [INFO] Starting network with chain id: L2ChainId(260)
12:34:56 [INFO] Rich Accounts
12:34:56 [INFO] =============
12:34:56 [INFO] Account #0: 0x36615Cf349d7F6344891B1e7CA7C72883F5dc049 (1_000_000_000_000 ETH)
12:34:56 [INFO] Private Key: 0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110
12:34:56 [INFO]
12:34:56 [INFO] Account #1: 0xa61464658AfeAf65CccaaFD3a512b69A83B77618 (1_000_000_000_000 ETH)
12:34:56 [INFO] Private Key: 0xac1e735be8536c6534bb4f17f06f6afc73b2b5ba84ac2cfb12f7461b20c0bbe3
...
12:34:56 [INFO] Account #9: 0xE90E12261CCb0F3F7976Ae611A29e84a6A85f424 (1_000_000_000_000 ETH)
12:34:56 [INFO] Private Key: 0x3eb15da85647edd9a1159a4a13b9e7c56877c4eb33f614546d4db06a51868b1c
12:34:56 [INFO]
12:34:56 [INFO] ========================================
12:34:56 [INFO] Node is ready at 127.0.0.1:8011
12:34:56 [INFO] ========================================
era_test_node
with MetaMask, it's essential to note that any restart of the in-memory node
will necessitate a reset of MetaMask's cached account data (nonce, etc).
In the MetaMask app, navigate to 'Settings', then 'Advanced', and finally, select 'Clear activity tab data'.Network details
The era_test_node
has the following default network configurations:
- L2 RPC:
http://localhost:8011
- Network Id: 260
These can be configured to your preference.
Pre-configured rich wallets
In-Memory node includes pre-configured "rich" accounts for testing:
Debug Transactions & Smart Contracts
The default configuration of era_test_node
displays minimal data in the terminal to keep the output clean.
However, if you are having issues with your smart contracts and need more details why a transaction is failing, try enabling --debug-mode
(or just -d
).
era_test_node -d
This will:
- Show the full call stack and each call's output for transactions
- Show more details about the breakdown of gas cost per transaction
- Resolve known hashes into human-readable strings
Fork a network
To fork the mainnet, use the following command, replacing [network]
with either mainnet
or sepolia-testnet
:
era_test_node fork [network]
This command starts the node, forked at the current head of the selected network.
You also have the option to specify a custom http endpoint and a custom forking height:
era_test_node fork --fork-at 7000000 mainnet http://172.17.0.3:3060
Replay remote transactions locally
If you wish to replay a remote transaction locally for deep debugging, use the following command:
era_test_node replay_tx sepolia-testnet 0x7119045573862797257e4441ff48bf5a3bc4d133a00d167c18dc955eda12cfac
For more detailed transaction information, such as call traces, add the --show-calls
flag.
If you want to see ABI names, add the --resolve-hashes
flag:
era_test_node --show-calls=user \
--resolve-hashes replay_tx sepolia-testnet \
0x7119045573862797257e4441ff48bf5a3bc4d133a00d167c18dc955eda12cfac
Alternatively (if your node is already running) you can use config_setShowCalls
and config_setResolveHashes
RPC endpoints
to configure these values:
# era_test_node already running...
# Set show-calls to User
curl --request POST \
--url http://localhost:8011/ \
--header 'content-type: application/json' \
--data '{"jsonrpc": "2.0","id": "1","method": "config_setShowCalls","params": ["user"]}'
# Enable resolve-hashes
curl --request POST \
--url http://localhost:8011/ \
--header 'content-type: application/json' \
--data '{"jsonrpc": "2.0","id": "1","method": "config_setResolveHashes","params": [true]}'
Here's an example of what you should expect to see when show-calls
and resolve-hashes
are configured:
Send network calls
You can send network calls against a running era_test_node
.
Launch the local in-memory node:
era_test_node fork sepolia-testnet
- Use curl to send a network call:
curl --request POST \ --url http://localhost:8011 \ --header 'Content-Type: application/json' \ --data '{ "jsonrpc": "2.0", "id": 1, "method": "eth_call", "params": [ { "to":"0xe1134444211593Cfda9fc9eCc7B43208615556E2", "data":"0x313ce567" }, "latest" ] }'
- Use foundry-zksync.
Make sure to install and configure
foundry-zksync
before proceeding (for installation instructions, please see Foundry with ZKsync Era):cast call 0xe1134444211593Cfda9fc9eCc7B43208615556E2 \ "name()(string)" \ --rpc-url http://localhost:8011
Retrieve the balance of a particular contract:cast call 0x40609141Db628BeEE3BfAB8034Fc2D8278D0Cc78 \ "balanceOf(address)(uint256)" \ 0x40609141Db628BeEE3BfAB8034Fc2D8278D0Cc78 \ --rpc-url http://localhost:8011
Deploy contracts
For the deployment of your contracts, you have the flexibility to choose between two preferred methods:
either by using Hardhat with the @matter-labs/hardhat-zksync
plugin, or via foundry-zksync
.
The following example will detail the process using foundry-zksync
.
Before proceeding, ensure that you've compiled your contracts using forge build --zksync
.
forge create contracts/Greeter.sol:Greeter \
--constructor-args "ZKsync and Foundry" \
--private-key 7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110 \
--rpc-url http://localhost:8011 \
--chain 260 \
--zksync
Test bootloader and system contracts
In-memory node allows testing of the currently compiled bootloader and system contracts. This makes it possible to examine the effects of changes on already deployed contracts.
$ZKSYNC_HOME
in your shell profile file
(e.g. ~/.bash_profile, ~/.zshrc) to target your local copy of era_test_node
.
For instance,export ZKSYNC_HOME=/path/to/era_test_node
export PATH=$ZKSYNC_HOME/bin:$PATH
- Preprocess and compile the contracts:
cd etc/system-contracts yarn preprocess && yarn hardhat run ./scripts/compile-yul.ts
- To use the locally compiled bootloader and system contracts, run:
RUST_LOG=vm=trace era_test_node --dev-use-local-contracts fork sepolia-testnet
Writing and running tests locally
This section demonstrates how to author and execute tests locally against era_test_node
using the mocha
and chai
testing frameworks with Hardhat.
Project configuration
- Start by creating a new Hardhat project. If you need guidance, follow the getting started guide.
- To incorporate the test libraries, execute:
yarn add -D mocha chai @types/mocha @types/chai
- Add the following lines to your
package.json
in the root folder:package.json"scripts": { "test": "NODE_ENV=test hardhat test" }
This script makes it possible to run tests in a Hardhat environment with the NODE_ENV
env variable set as test
.
Configure tests
Adjust hardhat.config.ts
to use the local node for testing:
era_test_node
is running in another process before executing the test command.import "@matterlabs/hardhat-zksync";
module.exports = {
zksolc: {
version: "latest",
settings: {},
},
defaultNetwork: "zkSyncTestnet",
networks: {
hardhat: {
zksync: true,
},
zkSyncTestnet: {
url: "http://localhost:8011",
ethNetwork: "http://localhost:8545",
zksync: true,
},
},
solidity: {
version: "0.8.17",
},
};
Write test scripts
Construct a test/main.test.ts
file with the following code:
import { expect } from "chai";
import { Wallet, Provider, Contract } from "zksync-ethers";
import * as hre from "hardhat";
import { Deployer } from "@matterlabs/hardhat-zksync";
const RICH_WALLET_PK = "0x7726827caac94a7f9e1b160f7ea819f172f7b6f9d2a97f992c38edeab82d4110";
describe("Greeter", function () {
it("Should return the new greeting once it's changed", async function () {
const provider = Provider.getDefaultProvider();
const wallet = new Wallet(RICH_WALLET_PK, provider);
const deployer = new Deployer(hre, wallet);
const artifact = await deployer.loadArtifact("Greeter");
const greeter = await deployer.deploy(artifact, ["Hi"]);
expect(await greeter.greet()).to.eq("Hi");
const setGreetingTx = await greeter.setGreeting("Hola, mundo!");
// wait until the transaction is mined
await setGreetingTx.wait();
expect(await greeter.greet()).to.equal("Hola, mundo!");
});
});
To run the test file, execute:
npm test
Well done! You've successfully run your first local tests with ZKsync Era and era_test_node
.
Troubleshooting
If running era_test_node run
provides the following error:
“era_test_node” can’t be opened because Apple cannot check it for malicious software.
This software needs to be updated. Contact the developer for more information.
You may require the use of sudo
. On macOS, the binary may need to have its quarantine attribute cleared:
xattr -d com.apple.quarantine /usr/local/bin/era_test_node