This tutorial describes how to set up a single host, multi-node testnet on EOS. We will set up two nodes on your local computer and have them communicate with each other. The examples in this section rely on three command-line applications, nodeos , keosd , and cleos . The following diagram depicts the desired testnet configuration.

It is assumed that keosd , cleos , and nodeos have been installed in your path, or that you know how to start these applications from the location in the file system.

Open 4 “terminal” windows to perform the steps in this tutorial.

1. Start the Wallet Manager

In the 1st terminal window, start keosd , the wallet management application:

$ keosd --http-server-address 127.0.0.1:8899

If successful, keosd will display some information, starting with:

2493323ms thread-0 wallet_plugin.cpp:39 plugin_initialize ] initializing wallet plugin

2493323ms thread-0 http_plugin.cpp:141 plugin_initialize ] host: 127.0.0.1 port: 8899

2493323ms thread-0 http_plugin.cpp:144 plugin_initialize ] configured http to listen on 127.0.0.1:8899

2493323ms thread-0 http_plugin.cpp:213 plugin_startup ] start listening for http requests

2493324ms thread-0 wallet_api_plugin.cpp:70 plugin_startup ] starting wallet_api_plugin

Look for a line saying the wallet is listening on 127.0.0.1:8899. This will indicate that keosd started correctly and is listening on the correct port. If you see anything else, or you see some error report prior to "starting wallet_api_plugin", then you need to diagnose the issue and restart.

When keosd is running correctly, leave that window open with the wallet app running and move to the 2nd terminal window.

2. Create a Default Wallet

In the 2nd terminal window, use cleos , the command-line utility, to create the default wallet.

$ cleos --wallet-url http://localhost:8899 wallet create

Creating wallet: default

Save password to use in the future to unlock this wallet.

Without password imported keys will not be retrievable.

"PW5Jn3GFZzerJTVz4XDN4W8QfGpvwiyLEucEvVxseKdbEZdSKV8bK"

We will continue to use this 2nd window for subsequent cleos commands.

3. Start the First Producer Node

We can now start the first producer node. In the 3rd terminal window run:

$ nodeos --enable-stale-production --producer-name eosio --plugin eosio::chain_api_plugin --plugin eosio::net_api_plugin

This creates a special producer, known as the “bios” producer.

4. Start the Second Producer Node

The following commands assume that you are running this tutorial from your ${EOSIO_SOURCE} directory, from which you ran ./eosio_build.sh

To start additional nodes, you must first load the eosio.bios contract. This contract enables you to have direct control over the resource allocation of other accounts and to access other privileged API calls. Return to the second terminal window and run the following command to load the contract:

$ cleos --wallet-url http://localhost:8899 set contract eosio build/contracts/eosio.bios

Reading WAST/WASM from build/contracts/eosio.bios/eosio.bios.wast...

Assembling WASM...

Publishing contract...

executed transaction: 808599e85909b5793819a6f303c499d776fede9c9cc2cc1dc9776d3877c60e87 3280 bytes 2200576 cycles

# eosio <= eosio::setcode {"account":"eosio","vmtype":0,"vmversion":0,"code":"0061736d0100000001581060037f7e7f0060057f7e7e7e7e...

# eosio <= eosio::setabi {"account":"eosio","abi":{"types":[],"structs":[{"name":"set_account_limits","base":"","fields":[{"n...

We will create an account to become a producer, using the account name inita . To create the account, we need to generate keys to associate with the account, and import those into our wallet.

$ cleos create key

Private key: 5HvbXnMVLLQEQRR3He7fu4rj7JziCiCcmWgAVkyhWbatBNFw8sw

Public key: EOS7J9pSmsJLQuHwQ5NZAH1V3MKKGgZtwZ92GqmAfbJqdUXDehiCE

Now import the private key portion into your wallet.

$ cleos --wallet-url http://localhost:8899 wallet import 5HvbXnMVLLQEQRR3He7fu4rj7JziCiCcmWgAVkyhWbatBNFw8sw

imported private key for: EOS7J9pSmsJLQuHwQ5NZAH1V3MKKGgZtwZ92GqmAfbJqdUXDehiCE

Create the inita account that we will use to become a producer.

$ cleos --wallet-url http://localhost:8899 create account eosio inita EOS7J9pSmsJLQuHwQ5NZAH1V3MKKGgZtwZ92GqmAfbJqdUXDehiCE EOS7J9pSmsJLQuHwQ5NZAH1V3MKKGgZtwZ92GqmAfbJqdUXDehiCE

executed transaction: 03d801831dc30fe43a355b2a5e1ff553c5081f6fc8a89a93c86fdffcbb4c891c 352 bytes 102400 cycles

# eosio <= eosio::newaccount {"creator":"eosio","name":"inita","owner":{"threshold":1,"keys":[{"key":"EOS7J9pSmsJLQuHwQ5NZAH1V3MK...

In the 4th terminal window, start a second nodeos instance.

$ nodeos --producer-name inita --plugin eosio::chain_api_plugin --plugin eosio::net_api_plugin --http-server-address 127.0.0.1:8889 --p2p-listen-endpoint 127.0.0.1:9877 --p2p-peer-address 127.0.0.1:9876 --config-dir node2 --data-dir node2 --private-key [\"EOS7J9pSmsJLQuHwQ5NZAH1V3MKKGgZtwZ92GqmAfbJqdUXDehiCE\",\"5HvbXnMVLLQEQRR3He7fu4rj7JziCiCcmWgAVkyhWbatBNFw8sw\"]

At this point, the second nodeos is an idle producer. To turn it into an active producer, inita needs to be registered as a producer with the bios node, and the bios node needs to perform an action to update the producer schedule.

$ cleos --wallet-url http://localhost:8899 push action eosio setprods "{ \"version\": 1, \"producers\": [{\"producer_name\": \"inita\",\"block_signing_key\": \"EOS7J9pSmsJLQuHwQ5NZAH1V3MKKGgZtwZ92GqmAfbJqdUXDehiCE\"}]}" -p eosio@active

executed transaction: 95baf281e32f1e54686518c85a1317f4e387977b6f16d2b74061cec605f22238 272 bytes 105472 cycles

# eosio <= eosio::setprods {"version":1,"producers":[{"producer_name":"inita","block_signing_key":"EOS7J9pSmsJLQuHwQ5NZAH1V3MKK...

Congratulations, you have now configured a two-node testnet! You can see that the original node is no longer producing blocks but it is receiving them. You can verify this by running the get info commmand against each node.

5. Verify the blockchain

Get info about the first node:

$ cleos get info

{

"server_version": "f537bc50",

"head_block_num": 28063,

"last_irreversible_block_num": 28062,

"head_block_id": "00006d9f87bcdee47f67eee56b861f118734794fed4a5ebeebb5c341ee1c3cd5",

"head_block_time": "2018-05-04T03:33:09",

"head_block_producer": "inita"

}

Now for the second node: