Set up a Localnet (mxpy)
This guide describes how to set up a local mini-testnet - also known as localnet - using mxpy. The purpose of a localnet is to allow developers experiment with and test their Smart Contracts, in addition to writing unit and integration tests.
The localnet contains:
- Validator Nodes (two, by default)
- Observer Nodes (zero, by default)
- A Seednode
- A MultiversX Proxy
If not specified otherwise, the localnet starts with two shards plus the metachain (each with one validator).
Prerequisites: mxpy
In order to install mxpy, follow these instructions.
This guide assumes you are using mxpy v7
or newer.
The easy way to start a localnet
You can simply setup and start a localnet in a workspace (folder) of your choice by following the steps below.
Create a new folder (workspace) and navigate to it:
mkdir -p ~/my-first-localnet && cd ~/my-first-localnet
Create, build and configure a localnet (in one go):
mxpy localnet setup
Then, start the localnet:
mxpy localnet start
Above, the command mxpy localnet setup
performs the following sub-commands under the hood, in one go (so you don't have to run them individually):
mxpy localnet new
mxpy localnet prerequisites
mxpy localnet build
mxpy localnet config
If everything goes well, in the terminal you should see logs coming from the nodes and proxy:
INFO:cli.localnet:Starting localnet...
...
INFO:localnet:Starting process ['./seednode', ...
...
INFO:localnet:Starting process ['./node', ...
...
INFO:localnet:Starting process ['./proxy', ...
[PID=...] DEBUG[...] [process/block] started committing block ...
The logs from all processes of the localnet can also be found in ~/my-first-localnet/localnet
. Simply look for *.log
files.
Note that the proxy starts with a delay of about 30 seconds.
Halting and resuming the localnet
In order to halt the localnet, press Ctrl+C
in the terminal. This will stop all the processes (nodes, proxy etc.). The localnet can be resumed at any time by running again the command mxpy localnet start
(from within your workspace).
Removing the localnet
In order to remove the localnet, run the command (from within your workspace):
mxpy localnet clean
This will delete the ~/my-first-localnet/localnet
folder. Note that the configuration file (e.g. localnet.toml
) will not be deleted automatically.
Gaining more control over the localnet
Perform setup steps individually
If you want to have more control over the localnet, you can run the setup sub-commands individually, as described below.
First, let's create a separate workspace (for the sake of this guide):
mkdir -p ~/my-second-localnet && cd ~/my-second-localnet
Then, create a new configuration file for the localnet, as follows:
mxpy localnet new
Upon running this command, a new file called localnet.toml
will be added in the current directory. This file contains the default configuration of the localnet. Make sure to open the file and inspect its content. You should see something like this:
[general]
...
rounds_per_epoch = 100
round_duration_milliseconds = 6000
[metashard]
...
num_validators = 1
[shards]
num_shards = 2
...
[networking]
...
port_proxy = 7950
port_first_validator_rest_api = 10200
[software.mx_chain_go]
resolution = "remote"
archive_url = "https://github.com/multiversx/mx-chain-go/archive/refs/heads/master.zip"
...
[software.mx_chain_proxy_go]
resolution = "remote"
archive_url = "https://github.com/multiversx/mx-chain-proxy-go/archive/refs/heads/master.zip"
...
Generally speaking, it's a good idea to only alter the localnet.toml
before first starting a localnet. Once the localnet is started, the configuration file should not be modified anymore (e.g. when halting and resuming the localnet).
Now, the following command will fetch the software prerequisites - mx-chain-go, mx-chain-proxy-go etc. - into ~/multiversx-sdk
:
mxpy localnet prerequisites
The prerequisites
step is only necessary when the localnet depends on remote source code archives - i.e. at least one software prerequisite has resolution = remote
in localnet.toml
. This is actually the default, and it's the easiest way to get started with the localnet. Later on, we'll see how to create the localnet from local source code (for advanced use-cases).
Once the software prerequisites (source code) are fetched, we can build them:
mxpy localnet build
The actual build takes place within the download folders of the software prerequisites which, by default, are children of ~/multiversx-sdk/localnet_software_remote
.
Now let's configure (prepare) the localnet:
mxpy localnet config
It is only upon running this command that the localnet subfolders are created. Make sure to inspect them:
tree -L 3 ~/my-second-localnet
Example output:
├── localnet
│ ├── proxy
│ │ ├── config
│ │ └── proxy
│ ├── seednode
│ │ ├── config
│ │ ├── libwasmer_linux_amd64.so
│ | ├── ...
│ │ └── seednode
│ ├── validator00
│ │ ├── config
│ │ ├── libwasmer_linux_amd64.so
│ | ├── ...
│ │ └── node
│ ├── validator01
│ │ ├── config
│ │ ├── libwasmer_linux_amd64.so
│ | ├── ...
│ │ └── node
│ └── validator02
│ ├── config
│ ├── libwasmer_linux_amd64.so
│ ├── ...
│ └── node
└── localnet.toml
We can then start, halt and resume the localnet as previously described.
Altering chronology parameters
Let's create a new localnet workspace:
mkdir -p ~/my-localnet-with-altered-chronology && cd ~/my-localnet-with-altered-chronology
mxpy localnet new
Before first starting a localnet, you can alter the chronology parameters in localnet.toml
. For example, let's have shorter epochs and shorter rounds:
[general]
rounds_per_epoch = 50
round_duration_milliseconds = 4000
Then, setup and start the localnet as previously described.
mxpy localnet setup
mxpy localnet start
Altering sharding configuration
Let's create a new localnet workspace:
mkdir -p ~/my-localnet-with-altered-sharding && cd ~/my-localnet-with-altered-sharding
mxpy localnet new
Before first starting a localnet, you can alter the sharding configuration in localnet.toml
. For example, let's have 3 shards, each with 2 validators and 1 observer (thus, 9 nodes, without the metachain ones):
[shards]
num_shards = 3
consensus_size = 2
num_observers_per_shard = 1
num_validators_per_shard = 2
Then, setup and start the localnet as previously described.
mxpy localnet setup
mxpy localnet start
Building from local source code
Let's create a new localnet workspace:
mkdir -p ~/my-localnet-from-local-src && cd ~/my-localnet-from-local-src
mxpy localnet new
In order to build the node or the proxy from local source code (instead of fetching the source code from a remote archive), you can set resolution = local
in localnet.toml
. For example, let's build both the node and the proxy from local source code:
[software.mx_chain_go]
resolution = "local"
local_path = "~/Desktop/workspace/mx-chain-go"
[software.mx_chain_proxy_go]
resolution = "local"
local_path = "~/Desktop/workspace/mx-chain-proxy-go"
Then, setup and start the localnet as previously described.
mxpy localnet setup
mxpy localnet start
Test (development) wallets
The development wallets are minted at the genesis of the localnet and their keys (both PEM files and Wallet JSON files) can be found in ~/multiversx-sdk/testwallets/latest/users
.
These wallets (Alice, Bob, Carol, ..., Mike) are publicly known - they should only be used for development and testing purpose.
Interacting with our localnet
Sending transactions
Let's send a simple transaction using mxpy:
mxpy tx new --recall-nonce --data="Hello, World" --gas-limit=70000 \
--receiver=erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx \
--pem=~/multiversx-sdk/testwallets/latest/users/alice.pem \
--chain=localnet --proxy=http://localhost:7950 \
--send
You should see the prepared transaction and the transaction hash in the stdout
(or in the --outfile
of your choice). Using the transaction hash, you can query the status of the transaction against the Proxy:
curl http://localhost:7950/transaction/8b2cd8e61c12d6f02148537bdef40579c6cbff7ff0aba996f294d34a31992ba4 | jq
Deploying and interacting with Smart Contracts
Let's deploy a Smart Contract using mxpy.
mxpy --verbose contract deploy --bytecode=./contract.wasm \
--recall-nonce --gas-limit=5000000 \
--pem=~/multiversx-sdk/testwallets/latest/users/alice.pem \
--outfile=contract.json \
--chain=localnet --proxy=http://localhost:7950 \
--send
Upon deployment, you can check the status of the transaction and the existence of the Smart Contract:
curl http://localhost:7950/transaction/4c5bd51ca0a051397bd6b0c89add2a5375106562b005c839f7e9bb113e2a8ce4 | jq
curl http://localhost:7950/address/erd1qqqqqqqqqqqqqpgqj5zftf3ef3gqm3gklcetpmxwg43rh8z2d8ss2e49aq | jq
If everything is fine (transaction status is executed
and the code
property of the address is set), you can interact with the deployed contract:
mxpy --verbose contract call erd1qqqqqqqqqqqqqpgqj5zftf3ef3gqm3gklcetpmxwg43rh8z2d8ss2e49aq \
--recall-nonce --gas-limit=1000000 --function=increment \
--pem=~/multiversx-sdk/testwallets/latest/users/alice.pem --outfile=myCall.json \
--chain=localnet --proxy=http://localhost:7950 \
--send
In order to perform queries against the contract using mxpy
, do as follows:
mxpy --verbose contract query erd1qqqqqqqqqqqqqpgqj5zftf3ef3gqm3gklcetpmxwg43rh8z2d8ss2e49aq --function=get --proxy=http://localhost:7950
Simulating transactions
At times, you can simulate transactions instead of broadcasting them, by replacing the flag --send
with the flag --simulate
. For example:
# Simulate: Call Contract
mxpy contract call erd1qqqqqqqqqqqqqpgqj5zftf3ef3gqm3gklcetpmxwg43rh8z2d8ss2e49aq \
--recall-nonce --gas-limit=1000000 --function=increment \
--pem=~/multiversx-sdk/testwallets/latest/users/alice.pem \
--chain=localnet --proxy=http://localhost:7950 \
--simulate
# Simulate: Simple Transfer
mxpy tx new --recall-nonce --data="Hello, World" --gas-limit=70000 \
--receiver=erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx \
--pem=~/multiversx-sdk/testwallets/latest/users/alice.pem \
--chain=localnet --proxy=http://localhost:7950 \
--simulate