elixir-omg repository contains OmiseGO's Elixir implementation of Plasma and forms the basis for the OMG Network.
IMPORTANT NOTICE: Heavily WIP, expect anything
Table of Contents
- Getting Started
- elixir-omg applications
- Child chain server
- mix configuration parameters
- "geth" | "parity"
- Testing & development
- Working with API Spec's
The first release of the OMG Network is based upon Tesuji Plasma, an iterative design step over Plasma MVP. The diagram below illustrates the relationship between the wallet provider and how wallet providers connect to Tesuji Plasma.
See the Tesuji Plasma design document for a full description for the Child Chain Server and Watcher. NOTE not all parts of that design have been implemented!
A public testnet for the OMG Network is coming soon. However, if you are brave and want to test being a Tesuji Plasma chain operator, read on!
Service start up using Docker Compose
This is the recommended method of starting the blockchain services, with the auxiliary services automatically provisioned through Docker. Before attempting the start up please ensure that you are not running any services that are listening on the following TCP ports: 9656, 7434, 5000, 8545, 5432, 5433. All commands should be run from the root of the repo.
NOTE known to work with
docker-compose version 1.24.0, build 0aa59064, version
1.17 has had problems
docker-compose -f docker-compose.yml -f docker-compose-non-mac.yml up
Get the deployed contract details
You can view the running containers via
If service start up is unsuccessful, containers can be left hanging which impacts the start of services on the future attempts of
You can stop all running containers via
docker kill $(docker ps -q).
If the blockchain services are not already present on the host, docker-compose will attempt to build the image with the tag
elixir-omg:dockercompose and continue to use that.
If you want Docker to use the latest commit from
elixir-omg you can trigger a fresh build by passing the
--build flag to
docker-compose up --build.
Install on a Linux host & manual start up
Follow the demos
After starting the child chain server and/or Watcher as above, you may follow the steps in the demo scripts. Note that some steps should be performed in the Elixir shell (iex) and some in the shell directly.
To start a configured instance of the
iex REPL, from the
elixir-omg root directory inside the container do:
iex -S mix run --no-start --config ~/config.exs
Follow one of the scripts in the docs directory. Don't pick any
Solutions to common problems may be found in the troubleshooting document.
elixir-omg is an umbrella app comprising of several Elixir applications:
The general idea of the apps responsibilities is:
omg_child_chain- child chain server
- tracks Ethereum for things happening in the root chain contract (deposits/exits)
- gathers transactions, decides on validity, forms blocks, persists
- submits blocks to the root chain contract
apps/omg_child_chain/lib/omg_child_chain/application.exfor a rundown of children processes involved
omg_db- wrapper around the child chain server's database to store the UTXO set and blocks necessary for state persistence
omg_eth- wrapper around the Ethereum RPC client
omg_child_chain_rpc- an HTTP-RPC server being the gateway to
omg_performance- performance tester for the child chain server
omg_watcher- the Watcher
See application architecture for more details.
Child chain server
:omg_child_chain is the Elixir app which runs the child chain server, whose API is exposed by
For the responsibilities and design of the child chain server see Tesuji Plasma Blockchain Design document.
Using the child chain server's API
The child chain server is listening on port
9656 by default.
HTTP-RPC requests are served up on the port specified in
:omg_child_chain_rpc, OMG.RPC.Web.Endpoint, http: [port: ...]).
The available RPC calls are defined by
api.ex - paths follow RPC convention e.g.
All requests shall be POST with parameters provided in the request body in JSON object.
Object's properties names correspond to the names of parameters. Binary values shall be hex-encoded strings.
For API documentation see: https://omisego.github.io/elixir-omg.
Running a child chain in practice
TODO other sections
Ethereum private key management
Currently, the child chain server assumes that the authority account is unlocked or otherwise available on the Ethereum node. This might change in the future.
parity doesn't support indefinite unlocking of the account, handling of such key is yet to be solved.
Currently (an unsafely) such private key is read from a secret system environment variable and handed to
parity for signing.
Specifying the fees required
The child chain server will require the incoming transactions to satisfy the fee requirement. The fee requirement reads that at least one token being inputted in a transaction must cover the fee as specified. In particular, note that the required fee must be paid in one token in its entirety.
The fees are configured in the config entries for
omg_child_chain see config secion.
Managing the operator address
The Ethereum address which the operator uses to submit blocks to the root chain is a special address which must be managed accordingly to ensure liveness and security.
The reorg protection mechanism enforces there to be a strict relation between the
submitBlock transactions and block numbers.
Child block number
1000 uses Ethereum nonce
1, child block number
2000 uses Ethereum nonce
This provides a simple mechanism to avoid submitted blocks getting reordered in the root chain.
This restriction is respected by the child chain server (
OMG.ChildChain.BlockQueue), whereby the Ethereum nonce is simply derived from the child block number.
As a consequence, the operator address must never send any other transactions, if it intends to continue submitting blocks. (Workarounds to this limitation are available, if there's such requirement.)
NOTE Ethereum nonce
0 is necessary to call the
RootChain.init function, which must be called by the operator address.
This means that the operator address must be a fresh address for every child chain brought to life.
Funding the operator address
The address that is running the child chain server and submitting blocks needs to be funded with Ether. At the current stage this is designed as a manual process, i.e. we assume that every gas reserve checkpoint interval, someone will ensure that gas reserve worth of Ether is available for transactions.
Gas reserve must be enough to cover the gas reserve checkpoint interval of submitting blocks, assuming the most pessimistic scenario of gas price.
Calculate the gas reserve as follows:
gas_reserve = child_blocks_per_day * days_in_interval * gas_per_submission * highest_gas_price
child_blocks_per_day = ethereum_blocks_per_day / submit_period
Submit period is the number of Ethereum blocks per a single child block submission) - configured in
Highest gas price is the maximum gas price which the operator allows for when trying to have the block submission mined (operator always tries to pay less than that maximum, but has to adapt to Ethereum traffic) - configured in (TODO when doing OMG-47 task)
- submission of a child block every Ethereum block
- 15 second block interval on Ethereum, on average
- weekly cadence of funding, i.e.
days_in_interval == 7
- allowing gas price up to 40 Gwei
gas_per_submission == 71505(checked for
RootChain.solat this revision. C.f. here)
gas_reserve ~= (4 * 60 * 24 / 1) * 7 * 71505 * (40 / 10**9) ~= 115 ETH
NOTE that the above calculation doesn't imply this is what is going to be used within a week, just a pessimistic scenario to calculate an adequate reserve. If one assumes an average gas price of 4 Gwei, the amount is immediately reduced to ~11.5 ETH weekly.
The Watcher is an observing node that connects to Ethereum and the child chain server's API. It ensures that the child chain is valid and notifies otherwise. It exposes the information it gathers via an HTTP-RPC interface (driven by Phoenix). It provides a secure proxy to the child chain server's API and to Ethereum, ensuring that sensitive requests are only sent to a valid chain.
For more on the responsibilities and design of the Watcher see Tesuji Plasma Blockchain Design document.
Using the watcher
The watcher is listening on port
7434 by default.
For API documentation see: https://omisego.github.io/elixir-omg
Ethereum private key management
Watcher doesn't hold or manage user's keys. All signatures are assumed to be done outside. A planned exception may be to allow Watcher to sign challenges, but using a non-sensitive/low-funded Ethereum account.
mix configuration parameters
Mix.Config is currently used to configure all the parameters required to set the child chain server and watcher up.
Per usual practice, the default values are defined in
NOTE: all margins are denominated in Ethereum blocks
Generic configuration -
deposit_finality_margin- the margin that is waited after a
DepositCreatedevent in the root chain contract. Only after this margin had passed:
- the child chain will allow spending the deposit
- the watcher will consider a transaction spending this deposit a valid transaction
It is important that for a given child chain, the child chain server and watchers use the same value of this margin.
NOTE: This entry is defined in
omg, despite not being accessed there, only in
omg_watcher. The reason here is to minimize risk of Child Chain server's and Watcher's configuration entries diverging.
ethereum_events_check_interval_ms- polling interval for pulling Ethereum events (logs) from the Ethereum client.
coordinator_eth_height_check_interval_ms- polling interval for checking whether the root chain had progressed for the
RootChainCoordinator. Affects how quick the services reading Ethereum events realize there's a new block.
Child chain server configuration -
submission_finality_margin- the margin waited before mined block submissions are purged from
block_queue_eth_height_check_interval_ms- polling interval for checking whether the root chain had progressed for the
child_block_minimal_enqueue_gap- how many new Ethereum blocks must be mined, since previous submission attempt, before another block is going to be formed and submitted.
fee_specs_file_name- path to file which defines fee requirements, see fee_specs.json for an example.
ignore_fees- boolean option allowing to turn off fee charging altogether
Watcher configuration -
exit_processor_sla_margin- the margin to define the notion of a "late", invalid exit. After this margin passes, every invalid exit is deemed a critical failure of the child chain (
unchallenged_exit). Such event will prompt a mass exit and stop processing new blocks. See exit validation documentation for details.
maximum_block_withholding_time_ms- for how long the Watcher will tolerate failures to get a submitted child chain block, before reporting a block withholding attack and stopping
block_getter_loops_interval_ms- polling interval for checking new child chain blocks submissions being mined on the root chain
maximum_number_of_unapplied_blocks- the maximum number of downloaded and statelessly validated child chain blocks to hold in queue for applying
exit_finality_margin- the margin waited before an exit-related event is considered final enough to pull and process
block_getter_reorg_margin- the margin considered by
OMG.Watcher.BlockGetterwhen searching for recent child chain block submission events. This is driving the process of determining the height and particular event related to the submission of a particular child chain block
convenience_api_mode- whether Convenience API should be started for the Watcher. This setting is usually set by running the
Mix.Tasks.Xomg.Watcher.Startwith the appropriate flag.
OMG.DB configuration -
path- path to the directory holding the LevelDB data store
server_module- the module to use when talking to the
server_name- the named process to refer to when talking to the
OMG.Eth configuration -
All binary entries are expected in hex-encoded,
contract_addr- the address of the root chain contract
authority_addr- the address used by the operator to submit blocks
txhash_contract- the Ethereum-transaction hash holding the deployment of the root chain contract
eth_node- the Ethereum client which is used:
"geth" | "parity".
node_logging_in_debug- whether the output of the Ethereum node being run in integration test should be printed to
:debuglevel logs. If you set this to false, remember to set the logging level to
:debugto see the logs
child_block_interval- mirror of contract configuration
uint256 constant public CHILD_BLOCK_INTERVALfrom
exit_period_seconds- mirror of contract configuration
uint256 public minExitPeriod
ethereum_client_warning_time_ms- queries for event logs made to the Ethereum node lasting more than this will emit a
Contract code is downloaded automatically when getting dependencies of the Mix application with
You can find the downloaded version of that code under
Installing dependencies and compiling contracts
To install dependencies:
sudo apt-get install libssl-dev solc
Contracts will compile automatically as a regular mix dependency. To compile contracts manually:
mix deps.compile plasma_contracts
Testing & development
Quick test (no integration tests):
Longer-running integration tests (requires compiling contracts):
mix test --only integration
To run these tests with
parity as a backend, set it via
ETH_NODE environmental variable (default is
ETH_NODE=parity mix test --only integration
For other kinds of checks, refer to the CI/CD pipeline (https://circleci.com/gh/omisego/workflows/elixir-omg).
To run a development
iex REPL with all code loaded:
iex -S mix run --no-start
Working with API Spec's
This repo contains
gh-pages branch intended to host Swagger-based API specification.
gh-pages is totally diseparated from other development branches and contains just Slate generated page's files.
See gh-pages README for more details.