The 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
- "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!
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.
docker-compose up
docker-compose -f docker-compose.yml -f docker-compose-non-mac.yml up
curl localhost:5000/get_contract
You can view the running containers via docker ps
If service start up is unsuccessful, containers can be left hanging which impacts the start of services on the future attempts of docker-compose up
.
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
.
Follow the guide to install the child chain server and watcher. Then use the guide in manual service startup to stand up.
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 OBSOLETE
demos.
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
- see
apps/omg_child_chain/lib/omg_child_chain/application.ex
for 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 persistenceomg_eth
- wrapper around the Ethereum RPC clientomg_rpc
- an HTTP-RPC server being the gateway toomg_child_chain
omg_performance
- performance tester for the child chain serveromg_watcher
- the Watcher
See application architecture for more details.
:omg_child_chain
is the Elixir app which runs the child chain server, whose API is exposed by :omg_rpc
.
For the responsibilities and design of the child chain server see Tesuji Plasma Blockchain Design document.
The child chain server is listening on port 9656
by default.
HTTP-RPC requests are served up on the port specified in omg_rpc
's config
(:omg_rpc, OMG.RPC.Web.Endpoint, http: [port: ...]
).
The available RPC calls are defined by omg_child_chain
in api.ex
- paths follow RPC convention e.g. block.get
, transaction.submit
.
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.
TODO other sections
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.
Since 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.
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.
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
where
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 :omg_child_chain, :child_block_submit_period
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)
Example
Assuming:
- 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 forRootChain.sol
at this revision. C.f. here)
we get
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.
The watcher is listening on port 7434
by default.
For API documentation see: https://omisego.github.io/elixir-omg
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.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 apps/<app>/config/config.exs
.
NOTE: all margins are denominated in Ethereum blocks
-
deposit_finality_margin
- the margin that is waited after aDepositCreated
event 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 inomg_child_chain
andomg_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 theRootChainCoordinator
. Affects how quick the services reading Ethereum events realize there's a new block.
-
submission_finality_margin
- the margin waited before mined block submissions are purged fromBlockQueue
's memory -
block_queue_eth_height_check_interval_ms
- polling interval for checking whether the root chain had progressed for theBlockQueue
exclusively -
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_path
- 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
-
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 byOMG.Watcher.BlockGetter
when 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 theMix.Tasks.Xomg.Watcher.Start
with the appropriate flag.
-
leveldb_path
- path to the directory holding the LevelDB data store -
server_module
- the module to use when talking to theOMG.DB
-
server_name
- the named process to refer to when talking to theOMG.DB
All binary entries are expected in hex-encoded, 0x
-prefixed.
-
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:debug
level logs. If you set this to false, remember to set the logging level to:debug
to see the logs -
child_block_interval
- mirror of contract configurationuint256 constant public CHILD_BLOCK_INTERVAL
fromRootChain.sol
-
exit_period_seconds
- mirror of contract configurationuint256 public minExitPeriod
-
ethereum_client_warning_time_ms
- queries for event logs made to the Ethereum node lasting more than this will emit a:warn
-level log
OMG network uses contract code from the contracts repo.
Code from a particular branch in that repo is used, see one of mix.exs
configuration files for details.
Contract code is downloaded automatically when getting dependencies of the Mix application with mix deps.get
.
You can find the downloaded version of that code under deps/plasma_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
Quick test (no integration tests):
mix test
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 geth
):
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
This repo contains gh-pages
branch intended to host Swagger-based API specification.
Branch gh-pages
is totally diseparated from other development branches and contains just Slate generated page's files.
See gh-pages README for more details.