Running Etherwall with a private chain
Table of Contents
In april/june 2021 I found myself struggling to run Etherwall with a private blockchain. It turned out to be way more tricky than expected and I decided to describe the actions I had to perform to get it work.
1 Requirements
Here I used Devuan GNU/Linux with a self-compiled Etherwall and Geth from the Ethereum PPA. I shall go into detail of installing the necessary software in another article, here I assume you are already running some GNU/Linux (or at least POSIX) system with Etherwall and Geth ready for use. You might need some basic knowledge of UNIX command line to be able to follow.
The tested versions of Etherwall and Geth are 3.0.2 and 1.10.3-stable, respectively.
2 Prepare Geth directories
We're going to have 3 instances of Geth running simultaneously. The first will be a miner and will be periodically signing new blocks. The second one will also be a full node, synced with the first one, and will be serving clients through a websocket. Please note Geth does not allow a single node to be a miner (which requires an unlocked account on it) and have websocket service enabled at the same time, hence the need for 2 separate nodes. The third node will be started automatically by Etherwall and will not connect to any other node.
Geth normally uses the ~/.ethereum/
directory to store its data. Here, we'll
configure the 3 nodes to use directories ~/.ethereum1/
, ~/.ethereum2/
and
~/.ethereum3/
instead. This means you can follow this guide without removing
or modifying your mainnet Ethereum data that sits in ~/.ethereum/
.
$ mkdir ~/.ethereum1 ~/.ethereum2 ~/.ethereum3
2.1 Create accounts
We are going to create 1 account for the first (miner) node and 2 accounts
for the third (Etherwall) node. The geth account new
command can be used
for that. When run, it lets you choose a password for the account and prints
some information.
$ geth --datadir ~/.ethereum1/ account new INFO [06-10|13:11:07.341] Maximum peer count ETH=50 LES=0 total=50 Your new account is locked with a password. Please give a password. Do not forget this password. Password: <you type in your chosen password> Repeat password: <you re-type your chosen password> Your new key was generated Public address of the key: 0xA3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E Path of the secret key file: /home/urz/.ethereum1/keystore/UTC--2021-06-10T11-11-32.383412301Z--a3bed543dc5de03da9eb8cebdb885439db1c2c1e - You can share your public address with anyone. Others need it to interact with you. - You must NEVER share the secret key with anyone! The key controls access to your funds! - You must BACKUP your key file! Without the key, it's impossible to access account funds! - You must REMEMBER your password! Without the password, it's impossible to decrypt the key!
So, I just created a miner account with address
0xA3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E
. I also created 2 other accounts
analogously by running geth --datadir ~/.ethereum3/ account new
twice.
Their addresses are 0x1268439f636479F527e2bE7512928f77AF2078d4
and
0x3fE005F3f85895100459cdcDf39648B5E5176e83
.
It might prove useful to know that accounts data is normally kept under the
keystore/
subdirectory of Ethereum data directory, one file for one
account. You can easily transfer accounts between nodes by simply copying
them over. You can even use the same account on different Ethereum
blockchains (e.g. mainnet, rinkeby testnet and your private chain).
2.2 Configure the genesis block
As we'll be running a private chain, we need to supply a custom genesis block from which it will start. Geth allows us to specify this custom block's configuration in a json file. Here is the one I prepared:
{ "config": { "chainId": 15, "homesteadBlock": 0, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "istanbulBlock": 0, "berlinBlock": 0, "clique": { "period": 30, "epoch": 30000 } }, "difficulty": "1", "gasLimit": "8000000", "extradata": "0x0000000000000000000000000000000000000000000000000000000000000000A3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "alloc": { "1268439f636479F527e2bE7512928f77AF2078d4": { "balance": "100000000000000000000" }, "3fE005F3f85895100459cdcDf39648B5E5176e83": { "balance": "10000000000000000000" } } }
Some of the relevant options are:
2.2.1 chainId
"chainId": 15,
Every Ethereum blockchain has its id. It prevents Ethereum nodes running on different blockchains from connecting with each other and allows transactions from other blockchains to be recognized as such and excluded from being mined. Mainnet uses id 1, we should use something else. Fortunately, as long as we are only running our private chain on a single machine, we don't have to worry about id collisions with other networks and almost any id will suffice.
2.2.2 fork blocks
"homesteadBlock": 0, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "istanbulBlock": 0, "berlinBlock": 0,
From time to time, a change is being introduced to the Ethereum network that changes something in the protocol. Such change requires a so-called fork of the blockchain, where starting from some specific block every participating node starts respecting the new version of the protocol. When running a private chain, we can decide at which blocks certain forks will happen. A common approach is to set most fork blocks numbers to 0, so that all fetures introduced since the launch of Ethereum are immediately available.
2.2.3 difficulty
This field determines the initial difficulty of mining for proof-of-work networks. In our case it is of no interest.
2.2.4 clique
"clique": { "period": 30, "epoch": 30000 }
On Ethereum mainnet, blocks are mined through proof-of-work, with
proof-of-stake in plans. This allows the blockchain to remain decentralized.
If we're running a private chain, we're probably doing so for test purposes
and we don't mind the control over it being centralized. Hence, we can
replace the resource-intensive proof-of-work with a scheme where a group of
pre-defined accounts is allowed to sign new blocks. That's what the clique
key does. The period
subkey determines the minimal time between subsequent
blocks.
2.2.5 gasLimit
"gasLimit": "8000000",
Gas limit indirectly limits the number of transactions and smart contract executions that can happen in one block. On Ethereum mainnet, miners periodically vote on gas limit. Here, our miner also has the ability to adjust it after chain's launch, but we can nonetheless specify some intial value and that's how we do it.
2.2.6 extradata
"extradata": "0x0000000000000000000000000000000000000000000000000000000000000000A3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
Here, we use extradata to specify the account(s) that will be allowed to sign new blocks in the clique scheme. This field's value consists of:
- 32 zero bytes (64 `0' chars)
- all signer addresses (in our case there's only one)
- 65 zero bytes (130 `0' chars)
2.2.7 alloc
"alloc": { "1268439f636479F527e2bE7512928f77AF2078d4": { "balance": "100000000000000000000" }, "3fE005F3f85895100459cdcDf39648B5E5176e83": { "balance": "10000000000000000000" } }
Using this key we can assign initial ETH balances to certain accounts. Here,
I gave 100 ETH to account 0x1268439f636479F527e2bE7512928f77AF2078d4
and
10 ETH to 0x3fE005F3f85895100459cdcDf39648B5E5176e83
.
2.3 Initialize the private chain
I saved the json configuration under ~/genesis.json
and initialized
the chain in ~/.ethereum1/
. Geth printed some information in the process.
$ geth --datadir ~/.ethereum1/ init ~/genesis.json INFO [06-10|14:17:53.124] Maximum peer count ETH=50 LES=0 total=50 INFO [06-10|14:17:53.128] Set global gas cap cap=25,000,000 INFO [06-10|14:17:53.128] Allocated cache and file handles database=/home/urz/.ethereum1/geth/chaindata cache=16.00MiB handles=16 INFO [06-10|14:17:53.159] Writing custom genesis block INFO [06-10|14:17:53.163] Persisted trie from memory database nodes=3 size=408.00B time=1.927914ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [06-10|14:17:53.164] Successfully wrote genesis state database=chaindata hash=c8fa7d..b1dae2 INFO [06-10|14:17:53.164] Allocated cache and file handles database=/home/urz/.ethereum1/geth/lightchaindata cache=16.00MiB handles=16 INFO [06-10|14:17:53.197] Writing custom genesis block INFO [06-10|14:17:53.200] Persisted trie from memory database nodes=3 size=408.00B time=1.695456ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B INFO [06-10|14:17:53.200] Successfully wrote genesis state database=lightchaindata hash=c8fa7d..b1dae2
I then initialized the remaining 2 chains with
geth --datadir ~/.ethereum2/ init ~/genesis.json
and
geth --datadir ~/.ethereum3/ init ~/genesis.json
.
3 Run Geth
Before Launching Etherwall, we'll run the first 2 Geth nodes, starting with the miner.
For miner I used the command:
$ geth --datadir ~/.ethereum1/ --netrestrict 127.0.0.1/32 --unlock 0xA3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E --mine --miner.threads=1 --miner.etherbase=0xA3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E --miner.gasprice 44000000000 --miner.gastarget 12000000 --light.serve 90 --port 30304
Geth outputted some information and asked me for miner account password:
INFO [06-10|14:29:19.973] Starting Geth on Ethereum mainnet... INFO [06-10|14:29:19.974] Bumping default cache on mainnet provided=1024 updated=4096 INFO [06-10|14:29:19.980] Maximum peer count ETH=50 LES=100 total=150 WARN [06-10|14:29:19.984] LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited WARN [06-10|14:29:19.985] Sanitizing cache to Go's GC limits provided=4096 updated=1285 INFO [06-10|14:29:19.987] Set global gas cap cap=25,000,000 INFO [06-10|14:29:19.988] Allocated trie memory caches clean=192.00MiB dirty=321.00MiB INFO [06-10|14:29:19.988] Allocated cache and file handles database=/home/urz/.ethereum1/geth/chaindata cache=641.00MiB handles=2048 INFO [06-10|14:29:20.100] Opened ancient database database=/home/urz/.ethereum1/geth/chaindata/ancient readonly=false INFO [06-10|14:29:20.104] Initialised chain configuration config="{ChainID: 15 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: 0 EIP155: 0 EIP158: 0 Byzantium: 0 Constantinople: 0 Petersburg: 0 Istanbul: 0, Muir Glacier: <nil>, Berlin: 0, YOLO v3: <nil>, Engine: clique}" INFO [06-10|14:29:20.107] Initialising Ethereum protocol network=1 dbversion=<nil> INFO [06-10|14:29:20.111] Loaded most recent local header number=0 hash=c8fa7d..b1dae2 td=1 age=52y2mo1w INFO [06-10|14:29:20.111] Loaded most recent local full block number=0 hash=c8fa7d..b1dae2 td=1 age=52y2mo1w INFO [06-10|14:29:20.111] Loaded most recent local fast block number=0 hash=c8fa7d..b1dae2 td=1 age=52y2mo1w WARN [06-10|14:29:20.112] Failed to load snapshot, regenerating err="missing or corrupted snapshot" INFO [06-10|14:29:20.112] Rebuilding state snapshot INFO [06-10|14:29:20.114] Resuming state snapshot generation root=24ab88..bf5381 accounts=0 slots=0 storage=0.00B elapsed=1.582ms INFO [06-10|14:29:20.114] Regenerated local transaction journal transactions=0 accounts=0 INFO [06-10|14:29:20.117] Generated state snapshot accounts=2 slots=0 storage=93.00B elapsed=5.096ms INFO [06-10|14:29:20.142] Allocated fast sync bloom size=641.00MiB INFO [06-10|14:29:20.144] Initialized state bloom items=3 errorrate=0.000 elapsed="698.832µs" WARN [06-10|14:29:20.146] Error reading unclean shutdown markers error="leveldb: not found" INFO [06-10|14:29:20.147] Allocated cache and file handles database=/home/urz/.ethereum1/geth/les.server cache=16.00MiB handles=16 INFO [06-10|14:29:20.148] Stored checkpoint snapshot to disk number=0 hash=c8fa7d..b1dae2 INFO [06-10|14:29:20.177] Checkpoint oracle is not enabled INFO [06-10|14:29:20.179] Starting peer-to-peer node instance=Geth/v1.10.3-stable-991384a7/linux-arm64/go1.16.3 INFO [06-10|14:29:20.218] New local node record seq=1 id=c6c4f5d163aa6c68 ip=127.0.0.1 udp=30304 tcp=30304 INFO [06-10|14:29:20.223] Started P2P networking self=enode://79ea9e26dad94ebca4540f1cf3c56b0222686c28773f36eaee0eb38730b6ed81a5d42383628e6c0e0b3bec4672cf773a0e5c35b1cf3192520d8b5877fde5db71@127.0.0.1:30304 INFO [06-10|14:29:20.229] IPC endpoint opened url=/home/urz/.ethereum1/geth.ipc Unlocking account 0xA3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E | Attempt 1/3 Password: <typed in the password> INFO [06-10|14:29:29.025] Unlocked account address=0xA3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E INFO [06-10|14:29:29.025] Transaction pool price threshold updated price=44,000,000,000 INFO [06-10|14:29:29.025] Transaction pool price threshold updated price=44,000,000,000
It then started continously generating its usual output:
INFO [06-10|14:29:29.025] Commit new mining work number=1 sealhash=251a29..1ed516 uncles=0 txs=0 gas=0 fees=0 elapsed="233.916µs" INFO [06-10|14:29:29.029] Successfully sealed new block number=1 sealhash=251a29..1ed516 hash=54289c..d3c946 elapsed=3.852ms INFO [06-10|14:29:29.029] 🔨 mined potential block number=1 hash=54289c..d3c946 INFO [06-10|14:29:29.030] Commit new mining work number=2 sealhash=2d5d76..efb7af uncles=0 txs=0 gas=0 fees=0 elapsed="829.498µs" INFO [06-10|14:29:30.465] Looking for peers peercount=0 tried=0 static=0 INFO [06-10|14:29:35.647] New local node record seq=2 id=c6c4f5d163aa6c68 ip=149.156.124.3 udp=30304 tcp=30304 INFO [06-10|14:29:40.697] Looking for peers peercount=0 tried=0 static=0 INFO [06-10|14:29:50.994] Looking for peers peercount=0 tried=0 static=0 INFO [06-10|14:29:59.002] Successfully sealed new block number=2 sealhash=2d5d76..efb7af hash=9359fc..9d8af8 elapsed=29.972s INFO [06-10|14:29:59.003] 🔨 mined potential block number=2 hash=9359fc..9d8af8
One line of output worth noting is the following:
INFO [06-10|14:29:20.223] Started P2P networking self=enode://79ea9e26dad94ebca4540f1cf3c56b0222686c28773f36eaee0eb38730b6ed81a5d42383628e6c0e0b3bec4672cf773a0e5c35b1cf3192520d8b5877fde5db71@127.0.0.1:30304
The `enode://' part can be used to tell other nodes how to connect to this one.
For second node, I issued:
geth --datadir ~/.ethereum2/ --syncmode=fast --port 30306 --bootnodes enode://79ea9e26dad94ebca4540f1cf3c56b0222686c28773f36eaee0eb38730b6ed81a5d42383628e6c0e0b3bec4672cf773a0e5c35b1cf3192520d8b5877fde5db71@127.0.0.1:30304 --netrestrict 127.0.0.1/32 --ws --ws.port 8546 --ws.api eth,net,web3 --ws.origins '*' --light.serve 90
And got some output:
INFO [06-10|14:37:05.213] Starting Geth on Ethereum mainnet... INFO [06-10|14:37:05.213] Bumping default cache on mainnet provided=1024 updated=4096 INFO [06-10|14:37:05.214] Maximum peer count ETH=50 LES=100 total=150 WARN [06-10|14:37:05.217] LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited WARN [06-10|14:37:05.217] Sanitizing cache to Go's GC limits provided=4096 updated=1285 INFO [06-10|14:37:05.218] Set global gas cap cap=25,000,000 INFO [06-10|14:37:05.218] Allocated trie memory caches clean=192.00MiB dirty=321.00MiB INFO [06-10|14:37:05.218] Allocated cache and file handles database=/home/urz/.ethereum2/geth/chaindata cache=641.00MiB handles=2048 INFO [06-10|14:37:05.307] Opened ancient database database=/home/urz/.ethereum2/geth/chaindata/ancient readonly=false INFO [06-10|14:37:05.309] Initialised chain configuration config="{ChainID: 15 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: 0 EIP155: 0 EIP158: 0 Byzantium: 0 Constantinople: 0 Petersburg: 0 Istanbul: 0, Muir Glacier: <nil>, Berlin: 0, YOLO v3: <nil>, Engine: clique}" INFO [06-10|14:37:05.312] Initialising Ethereum protocol network=1 dbversion=<nil> INFO [06-10|14:37:05.315] Loaded most recent local header number=0 hash=c8fa7d..b1dae2 td=1 age=52y2mo1w INFO [06-10|14:37:05.316] Loaded most recent local full block number=0 hash=c8fa7d..b1dae2 td=1 age=52y2mo1w INFO [06-10|14:37:05.316] Loaded most recent local fast block number=0 hash=c8fa7d..b1dae2 td=1 age=52y2mo1w WARN [06-10|14:37:05.316] Failed to load snapshot, regenerating err="missing or corrupted snapshot" INFO [06-10|14:37:05.317] Rebuilding state snapshot INFO [06-10|14:37:05.318] Resuming state snapshot generation root=24ab88..bf5381 accounts=0 slots=0 storage=0.00B elapsed=1.836ms INFO [06-10|14:37:05.319] Regenerated local transaction journal transactions=0 accounts=0 INFO [06-10|14:37:05.347] Allocated fast sync bloom size=641.00MiB WARN [06-10|14:37:05.350] Error reading unclean shutdown markers error="leveldb: not found" INFO [06-10|14:37:05.350] Allocated cache and file handles database=/home/urz/.ethereum2/geth/les.server cache=16.00MiB handles=16 INFO [06-10|14:37:05.350] Initialized state bloom items=3 errorrate=0.000 elapsed=1.009ms INFO [06-10|14:37:05.352] Generated state snapshot accounts=2 slots=0 storage=93.00B elapsed=34.923ms INFO [06-10|14:37:05.352] Stored checkpoint snapshot to disk number=0 hash=c8fa7d..b1dae2 INFO [06-10|14:37:05.391] Checkpoint oracle is not enabled INFO [06-10|14:37:05.392] Starting peer-to-peer node instance=Geth/v1.10.3-stable-991384a7/linux-arm64/go1.16.3 INFO [06-10|14:37:05.425] New local node record seq=1 id=6f0172b8174a0bc7 ip=127.0.0.1 udp=30306 tcp=30306 INFO [06-10|14:37:05.429] Started P2P networking self=enode://1777be824c12e9c1af0b2362311f00c2418ab3e6ad9b2384bb99ea6c9a146f788e58e748d98f4ffd738498d0ee68581c3acae403809b37725aa46f61769dd0a8@127.0.0.1:30306 INFO [06-10|14:37:05.430] IPC endpoint opened url=/home/urz/.ethereum2/geth.ipc INFO [06-10|14:37:05.431] WebSocket enabled url=ws://127.0.0.1:8546 INFO [06-10|14:37:15.432] Block synchronisation started INFO [06-10|14:37:15.477] Imported new block headers count=16 elapsed=20.515ms number=16 hash=eb84ec..bd3d14 INFO [06-10|14:37:15.479] Downloader queue stats receiptTasks=0 blockTasks=0 itemSize=522.22B throttle=8192 INFO [06-10|14:37:15.492] Imported new chain segment blocks=16 txs=0 mgas=0.000 elapsed=12.101ms mgasps=0.000 number=16 hash=eb84ec..bd3d14 dirty=0.00B INFO [06-10|14:37:15.492] Fast sync complete, auto disabling INFO [06-10|14:37:19.852] Looking for peers peercount=1 tried=1 static=0
Now, I should probably explain what each command-line option does. Here we go:
3.1 –datadir
--datadir ~/.ethereum1/
Rather obvious, we tell Geth instance to use the specific directory to store data to and load it from.
3.2 –netrestrict
--netrestrict 127.0.0.1/32
This tells Geth to only accept connections from the specified subnet. Useful if we don't need to connect nodes over the internet and we want to eliminate the possibility of external nodes from other chains accidently interfering with ours.
3.3 –unlock
--unlock 0xA3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E
This tells Geth to unlock an account when starting. In this case we unlock the miner account because it is needed for mining in clique scheme.
3.4 –mine
--mine
This tells Geth to mine new blocks for the chain.
3.5 –miner.threads
--miner.threads=1
This tells Geth to only use a single thread for mining (that's more than enough in case of a private chain).
3.6 –miner.etherbase
--miner.etherbase=0xA3bEd543dc5DE03dA9EB8Cebdb885439DB1c2c1E
With this option we specify what account the mined ETH should go to. Here, I chose the miner account.
3.7 –miner.gasprice
--miner.gasprice 44000000000
Given in wei, this option specifies the minimum gas price at which our miner will accept transactions.
3.8 –miner.gastarget
--miner.gastarget 12000000
As our miner works, it adjusts the gas limit. This option specifies the target gas limit it aims for.
3.9 –light.serve
--light.serve 90
This tells Geth to start serving light clients and to spend at most 90% of the tim doing so. Actually, this option is not needed in this setup as we don't have any nodes working in light mode - it's just a leftover from my earlier experiments ;)
3.10 –port
--port 30304
This tells Geth to listen for connections on port 30304. By default it would listen on port 30303. When running multiple instances simultaneously we need to use this option to make them all use different ports.
3.11 –syncmode
--syncmode=fast
This option specifies that a node, when syncing with chain, should not validate all of it, but instead only some number of topmost blocks. This is not really needed here, since out private chain very small.
3.12 –bootnodes
--bootnodes enode://79ea9e26dad94ebca4540f1cf3c56b0222686c28773f36eaee0eb38730b6ed81a5d42383628e6c0e0b3bec4672cf773a0e5c35b1cf3192520d8b5877fde5db71@127.0.0.1:30304
Here we copied the `enode://' value over from node 1's output. This way we instruct node 2 to connect to node 1.
3.13 –ws
--ws
Tells Geth o enable the websocket RPC server (this cannot be used on a node that has an account unlocked).
3.14 –ws.port
--ws.port 8546
With this option we explicitly specify the websocket listening port. The default would be the same I gave here, 8546.
3.15 –ws.api
--ws.api eth,net,web3
Tells Geth what Ethereum APIs to provide over websocket.
3.16 –ws.origins
--ws.origins '*'
Tells Geth what addresses to accept websocket connections from. In this case we allow connections from everywhere (There's nothing sensitive here anyway, it's just a test network).
4 Run Etherwall
We now need to properly configue Etherwall. While it is possible to do it
through GUI, I prefer to just edit the configuration file,
~/.config/Etherdyne/Etherwall.conf
.
4.1 Initial default configuration
Initially, my Etherwall instance filled its configuration file with the following:
[QQControlsFileDialog] favoriteFolders=@Invalid() height=0 sidebarSplit=104.62500000000001 sidebarVisible=true sidebarWidth=80 width=0 [geth] args="--syncmode=fast --cache 512" datadir=/home/urz/.ethereum logsize=99 path=/usr/bin/geth [node] geth\download_link=https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.10.3-991384a7.tar.gz geth\lastrun=1623334160 geth\latest_tag=v1.10.3 geth\latest_version=110003 [program] v2firstrun=@DateTime(\0\0\0\x10\0\0\0\0\0\0%\x86\xf0\x3w\x91\xc5\0) window\height=623 window\width=890
If you've run Etherwall before and already have a configuration file, it might be a good idea to back it up now.
$ cp ~/.config/Etherdyne/Etherwall.conf ~/.config/Etherdyne/Etherwall.conf.back
4.2 Config file modifications
Now, let's look at what modifications we need to make to the file. All of
them are under [geth]
.
4.2.1 args
This field specifies what custom command line arguments Ethereum should add to Geth invocation.
We change
args="--syncmode=fast --cache 512"
to
args=
In addition to that, Etherwall will add some options on its own. One will tell Geth to use the right data directory, other ones will cause it not to try connecting to other nodes. This was probably the trickiest part to figure out. Initially I didn't realize Etherwall (in thin mode) uses the local node only to sign transactions and I though Geth needs to be passed options that would allow it to find other nodes. And so, I unnecessarily tried adding `–bootnodes' and `–syncmode=light' arguments, etc. Those are not needed.
Another pitfall is the `–networkid' option Geth documentation describes.
I thought I should add it here, together with the id previously chosen in
genesis.json
. It turns out I was wrong, the presence of initialized chain
in Ethereum data directory is enough for Geth to learn the chain's id.
Right now it is probably not entirely obvious why we even need to initialize the custom chain in the third node's data directory. That node will not connect to others and will not be verifying blocks, right? That's true. We still need the node to know it is using custom chain, though, because it will be used to sign transactions and transactions from chain with a different id would be incompatible and would result in an invalid sender error when sent.
One thing worth mentioning is we don't really have to have Eherwall spawn
a Geth instance. We could run it manually in a terminal tab, with
~/ethereum3/
as data directory and then start Etherwall. The wallet
application would then notice a geth.ipc
socket file under that data
directory and connect to it instead of spawning a new Geth process.
4.2.2 custom
The `custom' field is needed to tell Etherwall to use a custom node for blockchain interaction. By default, in thin client mode, it would be using a public RPC service over websocket, which is obviously not going to work for our private chain.
We add the following line:
custom=true
4.2.3 datadir
We need to inform Etherwall about non-standard data directory location.
We change the default datadir line to:
datadir=~/.ethereum3/
4.2.4 remoteURL
We now need to tell Geth how to contact our custom node that bridges us to the blockchain. You remember we configured our second node to serve RPC APIs over websocket on port 8546 of localhost?
We add:
remoteURL=ws://127.0.0.1:8546
4.3 Final configuration
That's what the desired configuration looks like (keep in mind [geth]
part
is the relevant one):
[QQControlsFileDialog] favoriteFolders=@Invalid() height=0 sidebarSplit=104.62500000000001 sidebarVisible=true sidebarWidth=80 width=0 [geth] args= custom=true datadir=/home/urz/.ethereum3/ logsize=99 path=/usr/bin/geth remoteURL=ws://127.0.0.1:8546 [node] geth\download_link=https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.10.3-991384a7.tar.gz geth\lastrun=1623334160 geth\latest_tag=v1.10.3 geth\latest_version=110003 [program] v2firstrun=@DateTime(\0\0\0\x10\0\0\0\0\0\0%\x86\xf0\x3w\x91\xc5\0) window\height=623 window\width=890
4.4 Start the application
First 2 Geth nodes are running, Etherwall is configured, we can now start the game. As you might guess, I prefer running Etherwall from the command line, so:
$ Etherwall
If we did everything correctly, Etherwall should quickly spawn node 3, connect to 2 and 3 and finally show our 2 accounts with their balances of 100 and 10 ETH respectively.
Now we can use Etherwall just as we would when running on Ethereum mainnet.
5 Troubleshooting
Some errors might be obvious. Sometimes useful information can be found by looking at the Logs tab in Etherwall. Below are 2 problems that occured to me and were not obvious at all.
5.1 Etherwall hangs on Connecting to node…
That might indicate some error in the configuration. This thing seems to be
fragile. Try resetting your Etherwall config to the good one (Etherwall might
have modified it by itself) and re-initializing your Ethereum data directory
with our non-mainnet genesis.json
before trying again. Also, if you want
Etherwall to spawn its own Geth instance, make sure there isn't any leftover
old instance running in the data directory you want to use.
5.2 Etherwall reported Invalid sender when I was trying to send a transaction
That's most likely due to chain id mismatch. Ensure all Geth nodes are using the same genesis block.
6 Sources
I browsed zillions of web pages trying to figure out how to configure Etherwall and Geth to do what I want them to. I even tried changing the source of Etherwall. Still, if you simply want to get a better understanding of what is happening here and how to customize the configuration, your best bet is the official Geth documentation.
7 Copyright notice
This article is made available under the Creative Commons Zero license.