Skip to content
A lean Ethereum node with interchangeable consensus
Branch: master
Clone or download
jonknight73 Merge pull request #10 from mosaicnetworks/bytecode
Amend call to common.ToHex to hexutil.Encode as ToHex() is deprecated.
Latest commit 200edcc May 15, 2019


A lean Ethereum node with interchangeable consensus.

We took the Go-Ethereum implementation (Geth) and extracted the EVM and Trie components to create a lean and modular version with interchangeable consensus.

The EVM is a virtual machine specifically designed to run untrusted code on a network of computers. Every transaction applied to the EVM modifies the State which is persisted in a Merkle Patricia tree. This data structure allows to simply check if a given transaction was actually applied to the VM and can reduce the entire State to a single hash (merkle root) rather analogous to a fingerprint.

The EVM is meant to be used in conjunction with a system that broadcasts transactions across network participants and ensures that everyone executes the same transactions in the same order. Ethereum uses a Blockchain and a Proof of Work consensus algorithm. EVM-Lite makes it easy to use any consensus system, including Babble .


+----------+    |  +-------------+         +-------------+  |       
|          |    |  | Service     |         | State       |  |
|  Client  <-----> |             | <------ |             |  |
|          |    |  | -API        |         | -EVM        |  |
+----------+    |  | -Keystore   |         | -Trie       |  |
                |  |             |         | -Database   |  |
                |  +-------------+         +-------------+  |
                |         |                       ^         |     
                |         v                       |         |
                |  +-------------------------------------+  |
                |  | Engine                              |  |
                |  |                                     |  |
                |  |       +----------------------+      |  |
                |  |       | Consensus            |      |  |
                |  |       +----------------------+      |  |
                |  |                                     |  |
                |  +-------------------------------------+  |
                |                                           |

Consensus Implementations:

  • SOLO: No Consensus. Transactions are relayed directly from Service to State.

  • BABBLE: Inmemory Babble node. EVM-Lite does not support Babble's FastSync and Dynamic Membership protocols yet, so it is important to set the --store flag, and a high --sync-limit value.

  • RAFT: Hashicorp implementation of Raft (limited).

more to come...


Each consensus has its own subcommand evml [consensus], and its own configuration flags.

EVM-Lite node

  evml [command]

Available Commands:
  babble      Run the evm-lite node with Babble consensus
  help        Help about any command
  raft        Run the evm-lite node with Raft consensus
  solo        Run the evm-lite node with Solo consensus (no consensus)
  version     Show version info

  -d, --datadir string        Top-level directory for configuration and data (default "/home/user/.evm-lite")
      --eth.cache int         Megabytes of memory allocated to internal caching (min 16MB / database forced) (default 128)
      --eth.db string         Eth database file (default "/home/user/.evm-lite/eth/chaindata")
      --eth.genesis string    Location of genesis file (default "/home/user/.evm-lite/eth/genesis.json")
      --eth.keystore string   Location of Ethereum account keys (default "/home/user/.evm-lite/eth/keystore")
      --eth.listen string     Address of HTTP API service (default ":8080")
      --eth.pwd string        Password file to unlock accounts (default "/home/user/.evm-lite/eth/pwd.txt")
  -h, --help                  help for evml
      --log string            debug, info, warn, error, fatal, panic (default "debug")

Use "evml [command] --help" for more information about a command.

Options can also be specified in a evml.toml file in the datadir.

ex (evml.toml):

db = "/eth.db"


The application writes data and reads configuration from the directory specified by the --datadir flag. The directory structure must respect the following stucture:

host:~/.evm-lite$ tree
├── babble
│   ├── peers.json
│   └── priv_key.pem
├── eth
│   ├── genesis.json
│   ├── keystore
│   │   └── UTC--2018-10-14T11-12-24.412349157Z--633139fa62d5c27f454259ba59fc34773bd19457
│   └── pwd.txt
└── evml.toml

The above example shows a babble folder, but the general idea is that consensus configuration goes in a separate folder from the Ethereum configuration.

The Ethereum genesis file defines Ethereum accounts and is stripped of all
the Ethereum POW stuff. This file is useful to predefine a set of accounts
that own all the initial Ether at the inception of the network.

Example Ethereum genesis.json defining two account:

   "alloc": {
        "629007eb99ff5c3539ada8a5800847eacfc25727": {
            "balance": "1337000000000000000000"
        "e32e14de8b81d8d3aedacb1868619c74a68feab0": {
            "balance": "1337000000000000000000"

It is possible to enable evm-lite to control certain accounts by providing a
list of encrypted private keys in the keystore directory. With these private keys, evm-lite will be able to sign transactions on behalf of the accounts associated with the keys.

host:~/.evm-lite/eth/keystore$ tree
├── UTC--2016-02-01T16-52-27.910165812Z--629007eb99ff5c3539ada8a5800847eacfc25727
├── UTC--2016-02-01T16-52-28.021010343Z--e32e14de8b81d8d3aedacb1868619c74a68feab0

These keys are protected by a password. Use the eth.pwd flag to specify the location of the password file.

Needless to say you should not reuse these addresses and private keys


EVM-Lite will use a LevelDB database to persist state objects. The file of the
database can be specified with the eth.db flag which defaults to <datadir>/eth/chaindata.


The Service exposes an API at the address specified by the --eth.listen flag for clients to interact with Ethereum.

Get controlled accounts

This endpoint returns all the accounts that are controlled by the evm-lite instance. These are the accounts whose private keys are present in the keystore.


host:~$ curl http://[api_addr]/accounts -s | json_pp
   "accounts" : [
         "address" : "0x629007eb99ff5c3539ada8a5800847eacfc25727",
         "balance" : 1337000000000000000000,
         "nonce": 0
         "address" : "0xe32e14de8b81d8d3aedacb1868619c74a68feab0",
         "balance" : 1337000000000000000000,
         "nonce": 0

Get any account

This method allows retrieving the information about any account, not just the ones whose keys are included in the keystore.

host:~$ curl http://[api_addr]/account/0x629007eb99ff5c3539ada8a5800847eacfc25727 -s | json_pp

Send transactions from controlled accounts

Send a transaction from an account controlled by the evm-lite instance. The transaction will be signed by the service since the corresponding private key is present in the keystore.

example: Send Ether between accounts

host:~$ curl -X POST http://[api_addr]/tx -d '{"from":"0x629007eb99ff5c3539ada8a5800847eacfc25727","to":"0xe32e14de8b81d8d3aedacb1868619c74a68feab0","value":6666}' -s | json_pp
   "txHash" : "0xeeeed34877502baa305442e3a72df094cfbb0b928a7c53447745ff35d50020bf"

Get Transaction receipt


host:~$ curl http://[api_addr]/tx/0xeeeed34877502baa305442e3a72df094cfbb0b928a7c53447745ff35d50020bf -s | json_pp
   "to" : "0xe32e14de8b81d8d3aedacb1868619c74a68feab0",
   "root" : "0xc8f90911c9280651a0cd84116826d31773e902e48cb9a15b7bb1e7a6abc850c5",
   "gasUsed" : "0x5208",
   "from" : "0x629007eb99ff5c3539ada8a5800847eacfc25727",
   "transactionHash" : "0xeeeed34877502baa305442e3a72df094cfbb0b928a7c53447745ff35d50020bf",
   "logs" : [],
   "cumulativeGasUsed" : "0x5208",
   "contractAddress" : null,
   "logsBloom" : "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

Then check accounts again to see that the balances have changed:

   "accounts" : [
         "address" : "0x629007eb99ff5c3539ada8a5800847eacfc25727",
         "balance" : 1336999999999999993334,
         "address" : "0xe32e14de8b81d8d3aedacb1868619c74a68feab0",
         "balance" : 1337000000000000006666,

Send raw signed transactions

Most of the time, one will require to send transactions from accounts that are not controlled by the evm-lite instance. The transaction will be assembled, signed and encoded on the client side. The resulting raw signed transaction bytes can be submitted to evm-lite through the /rawtx endpoint.


host:~$ curl -X POST http://[api_addr]/rawtx -d '0xf8628080830f424094564686380e267d1572ee409368e1d42081562a8e8201f48026a022b4f68bfbd4f4c309524ebdbf4bac858e0ad65fd06108c934b45a6da88b92f7a046433c388997fd7b02eb7128f4d2401ef2d10d574c42edf15875a43ee51a1993' -s | json_pp

Get consensus info

The /info endpoint exposes a map of information provided by the consensus system.

example (with Babble consensus):

host:-$ curl http://[api_addr]/info | json_pp
   "rounds_per_second" : "0.00",
   "type" : "babble",
   "consensus_transactions" : "10",
   "num_peers" : "4",
   "consensus_events" : "10",
   "sync_rate" : "1.00",
   "transaction_pool" : "0",
   "state" : "Babbling",
   "events_per_second" : "0.00",
   "undetermined_events" : "22",
   "id" : "1785923847",
   "last_consensus_round" : "1",
   "last_block_index" : "0",
   "round_events" : "0"


Please refer to EVM-Lite Client for Javascript utilities and a CLI to interact with the API.



We use glide to manage dependencies:

[...]/evm-lite$ curl | sh
[...]/evm-lite$ glide install

This will download all dependencies and put them in the vendor folder; it could take a few minutes.


To add a new consensus system:

  • implement the consensus interface (consensus/consensus.go)
  • add a property to the the global configuration object (config/config.go)
  • create the corresponding CLI subcommand in cmd/evml/commands/
  • register that command to the root command


We provide a set of scripts to automate the deployment of testnets. This requires terraform and docker.

Support for AWS is also available (cf. deploy/)

You can’t perform that action at this time.