From 78d507b245b8cdb20533b1e2df10cce483b25688 Mon Sep 17 00:00:00 2001 From: Adrian Brink Date: Thu, 31 Aug 2017 14:01:29 +0200 Subject: [PATCH] Design for the future of Ethermint (#295) This document explains the ideal Ethermint architecture. The current design is similar but less modular. From this starting point, we will start an incremental refactor until we are at this design. The design itself is not perfect and will change over time. By splitting Ethermint up this way, we have the ability to add custom RPC endpoints. This allows the addition of special IBC endpoints which will be needed for IBC. This adds a description of a light client for ethermint which leverages the properties of tendermint to provide a fully secure EVM light client. A light client can keep of with the state and doesn't have to trust a single node. Furthermore, it can submit transactions. I've added a paragraph that explains how accounts are managed by an ethermint instance. This is the last missing piece as now ethermint provides all the functionality in a coherent way that we need it to. * Extend architecture with IBC and Rewards * Reason why we need this redesign * Explanation for accounts * Add time estimate * Simplify future design * More IBC explanations * Light client explanation --- docs/_static/.gitkeep | 0 docs/architecture.rst | 2 - docs/architecture/README.md | 51 --- docs/architecture/future-architecture.rst | 332 ++++++++++++++++++ docs/architecture/go-ethereum_flags.md | 239 ------------- docs/architecture/index.rst | 9 + ....md => inter-blockchain-communication.rst} | 8 +- docs/architecture/logging.md | 6 - .../{peg_zone.md => peg-zones.rst} | 51 ++- docs/assets/ethermint-logo.png | Bin 0 -> 70115 bytes docs/conf.py | 2 +- .../{ => getting-started}/getting-started.rst | 7 +- docs/getting-started/index.rst | 7 + docs/index.rst | 30 +- docs/installation.rst | 2 - docs/introduction.rst | 2 - docs/introduction/index.rst | 7 + docs/introduction/what-is-ethermint.rst | 7 + docs/peg-zone/contract_design.md | 19 - .../solidity/TendermintLightClient.sol | 22 -- .../solidity/contracts/ConvertLib.sol | 8 - docs/peg-zone/solidity/contracts/MetaCoin.sol | 34 -- .../solidity/contracts/Migrations.sol | 23 -- .../contracts/TendermintLightClientLib.sol | 9 - .../migrations/1_initial_migration.js | 5 - .../solidity/migrations/2_deploy_contracts.js | 8 - docs/peg-zone/solidity/test/TestMetacoin.sol | 25 -- docs/peg-zone/solidity/test/metacoin.js | 63 ---- docs/peg-zone/solidity/truffle.js | 9 - docs/testnets/index.rst | 7 + .../venus.rst} | 4 +- 31 files changed, 432 insertions(+), 566 deletions(-) create mode 100644 docs/_static/.gitkeep delete mode 100644 docs/architecture.rst delete mode 100644 docs/architecture/README.md create mode 100644 docs/architecture/future-architecture.rst delete mode 100644 docs/architecture/go-ethereum_flags.md create mode 100644 docs/architecture/index.rst rename docs/architecture/{ibc.md => inter-blockchain-communication.rst} (92%) delete mode 100644 docs/architecture/logging.md rename docs/architecture/{peg_zone.md => peg-zones.rst} (86%) create mode 100644 docs/assets/ethermint-logo.png rename docs/{ => getting-started}/getting-started.rst (99%) create mode 100644 docs/getting-started/index.rst delete mode 100644 docs/installation.rst delete mode 100644 docs/introduction.rst create mode 100644 docs/introduction/index.rst create mode 100644 docs/introduction/what-is-ethermint.rst delete mode 100644 docs/peg-zone/contract_design.md delete mode 100644 docs/peg-zone/solidity/TendermintLightClient.sol delete mode 100644 docs/peg-zone/solidity/contracts/ConvertLib.sol delete mode 100644 docs/peg-zone/solidity/contracts/MetaCoin.sol delete mode 100644 docs/peg-zone/solidity/contracts/Migrations.sol delete mode 100644 docs/peg-zone/solidity/contracts/TendermintLightClientLib.sol delete mode 100644 docs/peg-zone/solidity/migrations/1_initial_migration.js delete mode 100644 docs/peg-zone/solidity/migrations/2_deploy_contracts.js delete mode 100644 docs/peg-zone/solidity/test/TestMetacoin.sol delete mode 100644 docs/peg-zone/solidity/test/metacoin.js delete mode 100644 docs/peg-zone/solidity/truffle.js create mode 100644 docs/testnets/index.rst rename docs/{connecting-to-testnets.rst => testnets/venus.rst} (99%) diff --git a/docs/_static/.gitkeep b/docs/_static/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs/architecture.rst b/docs/architecture.rst deleted file mode 100644 index 3837742392..0000000000 --- a/docs/architecture.rst +++ /dev/null @@ -1,2 +0,0 @@ -Architecture -============ diff --git a/docs/architecture/README.md b/docs/architecture/README.md deleted file mode 100644 index 8bbe51782a..0000000000 --- a/docs/architecture/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# Current Design - -There are a few pieces: - -1. Setting up the ethereum stack -2. Forwarding txs received via ethereum rpc to tendermint rpc -3. Tendermint ABCI wrapper around ethereum stack - - ----- - - -1. The general design is to bind enough of the ethereum flags that we can -use its highest level object, the `go-ethereum/node.Node`, which is just a generic container for services -that run a p2p protocol and expose APIs over the RPC. -We mostly follow the logic in `go-ethereum/cmd/utils`. Then we create a custom service to register on the Node, -the `ethermint/ethereum.Backend`, which is inert on the p2p front but exposes only the APIs we want, or custom versions of them. -Many of the flags related to the node are irrelevant, since we don't use it for p2p. -But some, like for RPC, we need. -We should try to remove the dependence on the Node by setting up the Backend -and starting the RPC servers ourselves. This should reduce the number of ethereum flags we have to wrestle with. -Need to make sure there's nothing else we need from the Node that we can't set up and manage with low overhead ourselves. - -2. We need to listen for new txs received by the ethereum RPCs and forward them to -tendermint. Currently, we subscribe to the `TxPreEvent` in go-ethereum, and -forward any txs received to Tendermint's `/broadcast_tx_sync`. -One problem is the TxPreEvent is fired asynchronously by go-ethereum, -so we may receive txs out of order. We made a patch to fix this in tendermint/go-ethereum, -but it would be good to either fix this upstream or use a more robust approach. -Technically, we don't need the ethereum TxPool, but it is started automatically -with the Ethereum object and provides the simplest way to forward txs to tendermint. -It also buffers txs received out of order, waiting until they can be ordered properly -(but still fires the event asynchronously!) - -3. The simplest way to enable us to use all the web3 endpoints out of the box is to use the highest level -datastructures we can. So for the ABCI app, the application state consists of both the ethereum application state -and the ethereum blockchain. So even though we are building a chain of blocks of txs at the tendermint level, -for each tendermint block we also create and store an ethereum block to save in an ethereum blockchain managed -by the application. -For CheckTx, we replicate the code from `ethereum/core/tx_pool.go:validateTx`, but note we dont update any state -so this can only reliably process one tx per block right now! This is a big TODO! -For DeliverTx, we use our managed eth object, which provides a working state and env (config, header, gas) for applying transactions, -and slices for keeping track of all TXs, receipts and logs to be included in this block. - -NOTE: The ethereum APIs expect to be able to get the most current "pending" block, ie. the block a miner is working on. -The equivalent for us is a block that is in the midst of being processed by the ABCI app. -Typically, the TxPreEvent is listened to by the miner, who then goes and updates its state. -Instead, we want to bypass the miner and listen for the event ourselves, forwarding it to tendermint -and centralizing the pending state in the ABCI app. This is why we needed the patch on go-ethereum which bypasses -the miner using the `Pending` interface. That said, in 1.6.0 there may be an alternative solution since they support -a new consensus algorithm that doesnt use mining! diff --git a/docs/architecture/future-architecture.rst b/docs/architecture/future-architecture.rst new file mode 100644 index 0000000000..839c62c515 --- /dev/null +++ b/docs/architecture/future-architecture.rst @@ -0,0 +1,332 @@ +.. _future-architecture: + +Architecture +============ + +Motivation +---------- + +The current version of ethermint works and works well. It can already sustain more than 200 tx/s, offers +immediate finality and uses proof-of-stake instead of proof-of-work. However it is currently designed +to fit around go-ethereum which was never meant to be used as a library. Due to this the current +implementation is clunky and does not feel like the rest of the tendermint ecosystem. This starts with +the CLI and ends with the logging facilities. The problem with using go-ethereum stems from our choice +to use the highest level objects possible. Those objects where never intended to be consumed as a library +and hence are awkward to work with. However, the lower level packages such as RPC and State, were and are +used as libraries. + +The goal of the following architecture is to use the lower level components from go-ethereum and tendermint +to build a unique and coherent application that can also be used as a library. + +Goals +^^^^^ + +* a user can easily connect to the testnets, the live networks as well as run a private network locally + +* usability as a library - a developer can import the top level ethermint objects and quickly assemble a web3 compatible, EVM enabled and PoS based cryptocurrency that optionally supports IBC + +* full compatibility with all existing web3 tooling while enabling us to change endpoints based on the context of ethermint and to add new methods for IBC + +* developers can use ethermint as a library to develop beautiful light clients that take advantage of all the benefits of tendermint while also interacting with ethermint and smart contracts securely + +*NOTE: Ethermint supports a superset of Web3, since we are extending it with methods for IBC.* + + +Implementation Process +---------------------- + +This is not a rewrite from scratch. It is designed to be a second version that fixes some issues from the +past. The current estimate is that it will take 2 developers working on it full-time 6 weeks. A lot of the +ideas and current code can be used and packages will be replaces one by one. + +1. Implement the new CLI and logging in order to provide a similar experience as Tendermint. + +2. Implement the RPC package in order to provide a better user experience. + +3. Implement the accounts and rewards in order. + +4. Implement the ethereum object that reworks the internals. + +5. Implement ibc. + +6. Implement light. + + +The reason that we live ethereum towards the middle is that we cannot change the ethereum object without +having the previous packages. + + + +User Experience +--------------- + +The first entry point is installing ethermint. This is as easy as ``brew install ethermint``. It +installs the binaries for ethermint and tendermint in one step. Other platforms and package +managers such as apt-get or choco are also supported. + + +Supported commands +^^^^^^^^^^^^^^^^^^ + +* ``ethermint version`` - prints the version of ethermint and tendermint and is used to verify the installation + +* ``ethermint`` - initialises and runs ethermint and tendermint. It is used to connect to the live ethermint network. + * the initialisation files are included in the binary + * a reasonable home directory is assumed + * flags can be used to configure options such as RPC + +* ``ethermint testnet`` - initialises and runs ethermint and tendermint. It is used to connect to the test ethermint network. + * the bullet points from above apply + * flags can be used to configure which testnet to connect to + +* ``ethermint development`` - initialises and runs ethermint and tendermint. It is used to setup a local network. + * the bullet points from above apply + * private keys are included for the default account + * flags can be used to work with multiple local networks + + +Supported flags +^^^^^^^^^^^^^^^ + +* ``--home`` - defines the data directory for all files + +* ``--gasprice`` - sets to the minimal gasprice for a validating node to include a transaction. This flag is not consensus relevant and only applies to validating nodes. + +* ``--coinbase`` - defines the ethereum address which can receive the transaction fees and block rewards depending on the chosen reward strategy. This flag is not consensus relevant and only applies to validating nodes. + +* ``--gasfloor`` - sets the minimum number of gas that has to be expended in every block. This prevents empty blocks. This flag is not consensus relevant and only applies to validating nodes. + +* ``--gaslimit`` - sets the maximum amount of gas that can be in one ethereum block. This flag is consensus relevant and needs to be uniform in the same network. + +* all flags that Tendermint exposes + + +**TODO: Define all remaining flags, such as ``--rpc``, ``--config``, etc.** + + +Ethereum Developer Experience +----------------------------- + +A developer can easily switch from using Ethereum to using Ethermint for all his smart contracting +needs. Switching between the two platform is as easy as changing one RPC endpoint. We support all +modern Ethereum tooling such as Truffle as well as all UIs such as Mist. + +A developer has access to a superset of Web3. Our implementation also offers the ability to use IBC. + + +Go Developer Experience +----------------------- + +A developer chooses Ethermint as a library to build their own PoS backed, EVM enabled cryptocurrency. +He can choose his own reward strategy to distribute transaction fees and block rewards as well as his +own IBC strategy to define how his network interacts with the Cosmos hub. + +When a developer uses the Ethermint library he does not have to redefine all the commands and flags +and can rather just create a default CLI object that has to standard commands and flags already set. +He can then modify those and add more in order to fit his own needs. + +Every public API will have properly formatted ``godocs`` which enable new developers to easily use +Ethermint as a library. + +The documentation contains a subsection for developers that are using Ethermint as a library in Go. + + +Architecture Design +------------------- + +Ethermint is developed by the fine folks of the Cosmos team. As such it feels like any of our other +applications, such as Tendermint Core or the cosmos-sdk. It provides the functionality of the EVM +and Web3 and pairs it with PoS and IBC. The code base and architecture follows the Tendermint way +instead of the go-ethereum way. + +High Level Overview +^^^^^^^^^^^^^^^^^^^ + +We start by describing the high level packages that Ethermint has. The all live under +``github.com/tendermint/ethermint/``. + +* cmd - does not export anything. It only pulls in other packages to setup the ethermint node. + +* cli - bundles all commands and flags to provide a cli interface for an ethermint node. + +* ethermint - the highest level package. It implements ABCI, coordinates the starting and shutting down of a node and wires together all the independent components. + +* rpc - contains all RPC endpoints. It re-exposes a lot of the go-ethereum RPC endpoints, but also adds our own whenever necessary, such as for syncing. It does not have some endpoints such as mining but also adds new ones for IBC. + * heavily leans on ``github.com/ethereum/go-ethereum/rpc`` + +* account - provides key management and key storage. It also provides the code to use harware wallets. + +* reward - implements different types of strategies to reward validators. + +* ibc - provides the functionality to handle IBC packets. + +* light - bundles all functionality (also by re-exporting) to write secure ethermint light clients for mobile phones + * exposes a C API in order to be as language agnostic as possible + +* logging - unifies the logging for go-ethereum and tendermint. + + +Low Level Detail +^^^^^^^^^^^^^^^^ + +This section provides a package level description of the architecture. It, where applicable, also +includes description of the actual APIs. + +**TODO: The details will be filled in as it is being developed.** + + +cmd +""" + +The cmd package does not define new types, functions or methods. It is a user of the ethermint library. +It integrates all other packages into a coherent application. + + +cli +""" + +The cli package holds all the commands and flags. It allows a developer to create a new cli without +having to write his own flags. It exposes the features described above. + + +ethermint +""""""""" + +The ethermint package is responsible for wiring up all the different components into a working +application. It is the top level object. It takes a configuration struct, a logger, a reward object, +and an ibc object. Everything else is instantiated within the constructor. The goal is to keep the +outwards facing API very simple in the beginning. The ethermint object implements ``ABCIApplication`` +and ``BaseService``. It is responsible for mediating the communication with Tendermint Core and is +the entry point that starts all needed goroutines. + +Internally it instantiates an RPC server that serves the Web3 endpoints. It also instantiates an RPC +client that the RPC server uses to forward transaction from Web3 to Tendermint Core. It instantiates +an ethereum object which handles state management and execution. Lastly, it instantiates an account +object which handles private keys either on disk or on an HSM. + +Ethermint: +* Logger +* Reward +* Ibc + +* rpcServer - serves the web3 rpc server, depends on the config options +* rpcClient - sends transaction that where created over web3 to tendermint +* ethereum - manages and executes state +* account - an account manager that manages private keys stored under this ethermint node + +To start an ethermint instance Start() has to be called. This in turn starts all other goroutines, +such as for the rpcServer, the rpcClient and the account. + + +ethereum +"""""""" + +The ethereum package resides in the internal package. It is responsible for all state mangement and +execution. + +Ethereum: +* state for persistence and actual state +* checkState for ephemeral state +* logger +* reward strategy + +The ethereum object is responsible for validating ethereum transactions and running them against a state. +All VM, state and state transition logic is imported from go-ethereum. It handles tendermint messages +such as BeginBlock and EndBlock. An important function is be able to respond to Commit. +Ideally, ethereum should not build its own blockchain but should rather just provide a databse layer and +leave the blockchain to tendermint. However it seems that in the current implementation of go-ethereum +the state is tightly coupled to it being a blockchain state. This logic is not too different from +what we currently have. + +The ethereum object implements ``BaseService`` and can be started and stopped properly. + + +rpc +""" + +The rpc package has an RPC server as its main type. It is a wrapper around the RPC package from +go-ethereum. It provides the same functionality as ethereum, but adapts it to fit the needs of +ethermint. + +The RPC server implements ``BaseService`` which is an interface provided by tendermint. + +It takes a reference to an ethereum object in order to answer questions about the state. +It takes a reference to a rpcClient object in order to proxy ethereum transaction to Tendermint core. +It takes a reference to an account object in order to provide functionality related to accounts. + + +account +""""""" + +Accounts wraps a go-ethereum account manager and provides that functionality. Accounts cannot be unlocked +by default when starting ethermint as that is a security risk. They have to be unlocked through some GUI. +It stores the keys the same way that go-ethereum deals with it inside the ethermint directory. + + +reward +"""""" + +The reward strategy defines how to distribute rewards. It holds the address that should receive the +rewards (``coinbase``) and decides how much and when that address should be rewarded. It is passed in by +the user of the library. + + +ibc +""" + +See :ref:`inter-blockchain-communication` for details on IBC. + + +light +""""" + +Since we are implementing our own RPC package (which wraps go-ethereum RPC) to expose the correct +web3 endpoints that are needed for ethermint, we can implement a very efficient tendermint light +client. The LC connects to the underlying tendermint instance to keep up with the validator set +changes as well as with recent block hashes. This part is exactly the same as in basecoin. When +a light client wants to query the state though, it uses the Web3 endpoints of the full node and +does the data verification by looking at tendermint block which contains the relevant app hash. +It checks that the block is validly signed by a majority of the current validators. Then it checks +that the information it received from web3 is valid as well and is backed by the app_hash that is +within the tendermint block. + +This way we developers can write fully secure ethermint wallets that build on top of our RPC +package so that it offers exactly the same web3 endpoints that they would normally work with. +For example, you can write a phone wallet, which uses our light client package to securely +keep up with the state of the ethermint chain. + +We need to write a light-client package that unifies the tendermint and web3 connections and +does the proving for you. It should expose a web3 RPC interface or C functions so that other +languages can easily build on top of it. + +**TODO: Consult with Frey.** + + +logging +""""""" + +Implemented like the current logging package. + + +Tests +^^^^^ + +Every file has an associated test file that verifies the assumptions and invariants that are implicit +to the program and are not expressed by the type system. + +Every package has an associated test suite that uses the public API like an ordinary developer would. +This package not only ensures that the exposed API is reasonable, but it also ensures that the +package works in its entirety. + +The entire application has tests at the top level in order to ensure that all components work together +as expected. + +Integration tests for all RPC endpoints are run against a live network that is setup with docker +containers. + + +Dependencies +^^^^^^^^^^^^ + +Dependencies are well encapsulated and do not span multiple packages. + diff --git a/docs/architecture/go-ethereum_flags.md b/docs/architecture/go-ethereum_flags.md deleted file mode 100644 index e575112807..0000000000 --- a/docs/architecture/go-ethereum_flags.md +++ /dev/null @@ -1,239 +0,0 @@ -# Flags exposed by ethermint and why - -All unexposed flags will be set internally in ethermint to an appropriate default. - -## General settings -- [x] DataDirFlag - - used to control the directory where go-ethereum stores its files - -- [x] KeyStoreDirFlag - - depends on DataDirFlag - -- [x] NoUSBFlag - - disables monitoring for and managing of USB hardware wallets - -~~- [ ] EthashCacheDirFlag~~ - - mining and ethash should be turned off - -~~- [ ] EthashCachesInMemoryFlag~~ - -~~- [ ] EthashCachesOnDiskFlag~~ - -~~- [ ] EthashDatasetDirFlag~~ - -~~- [ ] EthashDatasetsInMemoryFlag~~ - -~~- [ ] EthashDatasetsOnDiskFlag~~ - -~~- [ ] NetworkIdFlag~~ - - used to set the network (frontier, morden, ropsten, rinkeby) - - ethermint should be agnostic as to what network it runs against, since - it will be determined by the configuration of the tendermint core node - -~~- [ ] TestnetFlag~~ - -~~- [ ] RinkebyFlag~~ - -~~- [ ] DevModeFlag~~ - -~~- [ ] IdentityFlag~~ - - allows to set a custom node name - - ethermint should never be directly exposed or network with other nodes - and hence the node name should not be settable - -- [ ] DocRootFlag - - What is this? - -~~- [ ] FastSyncFlag~~ - - ethermint should have no notion of fast sync as it is handled by - tendermint core - -~~- [ ] LightModeFlag~~ - - ethermint does not directly serve light clients - -~~- [ ] SyncModeFlag~~ - - the syncing part is handled by tendermint core - -~~- [ ] LightServFlag~~ - - ethermint does not serve light clients - -~~- [ ] LightPeersFlag~~ - -- [ ] LightKDFFlag - - What is this? - -- [x] CacheFlag - - Megabytes of memory allocated to internal cache - - allows for optimizations of ethermint - -- [x] TrieCacheGenFlag - - number of trie node generations to keep in memory - -~~- [ ] MiningEnabledFlag~~ - - ethermint does not allow go-ethereum to directly mine - -~~- [ ] MinerThreadsFlag~~ - -- [x] TargetGasLimitFlag - - this should be enabled to allow ethermint users to run economically - - not clear yet how it will work with tendermint core - -- [ ] EtherbaseFlag - - can be used by reward strategies - -- [ ] GasPriceFlag - - this should be enabled to allow ethermint users to run economically - - not clear yet how it will work with tendermint core - -~~- [ ] ExtraDataFlag~~ - - allows miners to attach data to blocks - - not used since tendermint core handles creation of blocks - -## Account settings -- [x] UnlockedAccountFlag - - allows the user to unlock accounts by default - -- [x] PasswordFileFlag - - password file to use for non-interactive password input - -- [x] VMEnableDebugFlag - - record information useful for VM and contract debugging - -## Logging and debug settings -- [ ] EthStatsURLFlag - - reporting URL of ethstats service - - Should this be exposed or does tendermint core handle it? - -- [ ] MetricsEnabledFlag - - collect metrics - - Should this be exposed or does tendermint core handle it? - -~~- [ ] FakePoWFlag~~ - - disable proof-of-work verification - - this is set internally - -- [x] NoCompactionFlag - - disables DB compaction after import - -## RPC settings -- [x] RPCEnabledFlag - -- [x] RPCListenAddrFlag - -- [x] RPCPortFlag - -- [x] RPCCORSDomainFlag - -- [x] RPCApiFlag - -- [x] IPCDisabledFlag - -- [x] IPCPathFlag - -- [x] WSEnabledFlag - -- [x] WSListenAddrFlag - -- [x] WSPortFlag - -- [x] WSApiFlag - -- [x] WSAllowedOriginsFlag - -~~- [ ] ExecFlag~~ - - JS capabilities aren't exposed by ethermint - -~~- [ ] PreloadJSFlag~~ - - preload JS files into console - - console isn't exposed by ethermint - -## Network settings -~~- [ ] MaxPeersFlag~~ - - max number of peers - - ethermint does not connect to peers and hence this is not exposed - -~~- [ ] MaxPendingPeersFlag~~ - -~~- [ ] ListenPortFlag~~ - -~~- [ ] BootnodesFlag~~ - -~~- [ ] BootnodesV4Flag~~ - -~~- [ ] BootnodesV5Flag~~ - -~~- [ ] NodeKeyFileFlag~~ - -~~- [ ] NodeKeyHexFlag~~ - -~~- [ ] NATFlag~~ - -~~- [ ] NoDiscoverFlag~~ - -~~- [ ] DiscoveryV5Flag~~ - -~~- [ ] NetrestrictFlag~~ - -- [ ] WhisperEnabledFlag - - What is this? - -~~- [ ] JSpathFlag~~ - - JS is not exposed by ethermint - -- [x] GpoBlocksFlag - - number of recent block to check for gas prices - -- [x] GpoPercentileFlag - - suggested gas price is the given percentile of a set of recent transactions - -## Debug Flags -This package is not exposed by go-ethereum and hence we have to replicate some of their flags. - -## Console Flags -It allows go-ethereum to expose an interpreted JavaScript console. In our use case -we expect users to run ```ethermint``` and then to the node using ```geth``` from -another process. - -## Custom Flags -- [x] TendermintAddrFlag - - address used by ethermint to connect to tendermint core for transaction broadcast - -- [x] ABCIAddrFlag - - address used by ethermint to listen for incoming messages from tendermint core - -- [x] ABCIProtocolFlag - - switches between grpc and socket as a communication protocol from tendermint core - to ethermint - -- [x] VerbosityFlag - - sets the level for the logger - -- [ ] VModuleFlag - - per module verbosity - -- [ ] BackTraceAtFlag - - request a stack trace at a specific logging statement - -- [ ] DebugFlag - - prepends log messages with call-site location - -- [ ] PProfFlag - - enables the pprof HTTP server - -- [ ] PProfPortFlag - - pprof HTTP server listening port - -- [ ] PProfAddrFlag - - pprof HTTP server listening interface - -- [ ] MemProfileRateFlag - - turns on memory profiling with the given rate - -- [ ] BlockProfileRateFlag - - turns on block profiling with the given rate - -- [ ] CpuProfileFlag - - write CPU profile to given file - -- [ ] TraceFlag - - write execution trace to the given file diff --git a/docs/architecture/index.rst b/docs/architecture/index.rst new file mode 100644 index 0000000000..31b3e70ada --- /dev/null +++ b/docs/architecture/index.rst @@ -0,0 +1,9 @@ +Architecture +============ + +.. toctree:: + :maxdepth: 2 + + future-architecture.rst + inter-blockchain-communication.rst + peg-zones.rst diff --git a/docs/architecture/ibc.md b/docs/architecture/inter-blockchain-communication.rst similarity index 92% rename from docs/architecture/ibc.md rename to docs/architecture/inter-blockchain-communication.rst index 4938690756..d766f67a42 100644 --- a/docs/architecture/ibc.md +++ b/docs/architecture/inter-blockchain-communication.rst @@ -1,6 +1,10 @@ -# IBC Support in Ethermint +.. _inter-blockchain-communication: + +IBC Support in Ethermint +======================== Goals: +------ - Ethermint can send and receive native and ERC20 tokens via IBC - No changes to native Ethereum transaction format @@ -8,6 +12,7 @@ Goals: Design: +------- - a native contract at address 0x00...000494243 (ie. "IBC") - contains its own independent merkle IAVL tree @@ -30,6 +35,7 @@ Design: Additional Notes: +----------------- We want to support more general extensions to Ethermint, for instance a native contract that handles validators. If we reuse cosmos-sdk libs, we may want to use just one IAVL tree for all extensions. diff --git a/docs/architecture/logging.md b/docs/architecture/logging.md deleted file mode 100644 index 1b0979381d..0000000000 --- a/docs/architecture/logging.md +++ /dev/null @@ -1,6 +0,0 @@ -# Logging - -Ethermint has to wrestle with two separate logging infrastructures. go-ethereum uses one type of logger -while the abci server uses a different logger. At the moment ethermint just instantiates two separate -logger objects and passes them to their respective users. In the future it would be great to have an -adapter that unifies both. diff --git a/docs/architecture/peg_zone.md b/docs/architecture/peg-zones.rst similarity index 86% rename from docs/architecture/peg_zone.md rename to docs/architecture/peg-zones.rst index 2afd8e1040..a0a5995c2d 100644 --- a/docs/architecture/peg_zone.md +++ b/docs/architecture/peg-zones.rst @@ -1,51 +1,70 @@ -# Ethereum Peg Zones +.. _peg-zones.rst: + +Ethereum Peg Zones +================== **It is paramount that every CETH is backed by an ETH because otherwise, speculators will immediately attack the peg.** The goal of the Ethereum peg zone is to provide a way for people to exchange ETH into CETH (COSMOS ETH) and vice versa. The implementation should happen within smart contracts written in solidity. Implementing the peg zone within the Ethermint codebase is dangerous because it will make it less flexible to future changes and will lead to greater divergence of the codebase from its upstream base. -## Process +Process +------- + +Sending Ether to Cether (Ethereum -> Ethermint) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -### Sending Ether to Cether (Ethereum -> Ethermint) To transfer money from ethereum to ethermint you have to send ether and a destination address to the exchange smart contract on ethereum. This smart contract will raise an event when the transfer function is invoked. Every validator that supports ethermint will also run a full ethereum node that is connected to the mainnet. This node will listen for events on the smart contract and send data of the event to ethermint. Ethermint will then receive the amount and destination address and will mint new CETH (through a reward strategy) for the specified destination address. -### Sending Cether to Ether (Ethermint -> Ethereum) -To transfer money from ethermint to ethereum you have to send cether and a destination address to the exchange smart contract on ethermint. This smart contract will raise an event when the transfer function is invoked. It will burn +Sending Cether to Ether (Ethermint -> Ethereum) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To transfer money from ethermint to ethereum you have to send cether and a destination address to the exchange smart contract on ethermint. This smart contract will raise an event when the transfer function is invoked. It will burn any CETH that it has received. Ethermint listens for these events. Once an event is received, ethermint will create, sign and broadcast a transaction that invokes the release function on the ethereum smart contract. In this function call it will include the proof and the signatures. The smart contract on ethereum will verify the proof and signatures and conditionally release money to the destination address. -## Design -Every validator runs tendermint, ethermint and an ethereum node. Ethermint has a `--peg` flag, which will cause it to also act as a pegzone. +Design +------ + +Every validator runs tendermint, ethermint and an ethereum node. Ethermint has a `--peg` flag, which will cause it to also act as a pegzone. The ethereum node is configured to send a notification to ethermint every time an event is raised by the exchange contract on ethereum. This notification causes ethermint to mint new CETH out of thin air through its reward strategy. The ethermint smart contract raises an event when it receives a deposit. After receiving a deposit it burns all deposited CETH. Ethermint listens for this event in a go-routine and after receiving the notification it will create, sign and broadcast a transaction which invokes the release function on the ethereum smart contract. The smart contract on ethereum then verifies the signatures and the proof and only then releases the ETH to the destination address. -## Components -### Ethereum Full Node +Components +---------- + +Ethereum Full Node +^^^^^^^^^^^^^^^^^^ + - sends notification to ethermint when an event is raised by a specified smart contract on ethereum -### Ethereum Smart Contract +Ethereum Smart Contract +^^^^^^^^^^^^^^^^^^^^^^^ *Tendermint light client implemented in Solidity* - locks up ETH - triggers event upon receiving ETH - is a light client for tendermint and verifies the calls to its release function -### Ethermint Smart Contract +Ethermint Smart Contract +^^^^^^^^^^^^^^^^^^^^^^^^ - burns CETH - triggers event upon receiving CETH -### Ethermint +Ethermint +^^^^^^^^^ - responds to notifications from ethereum full node by minting fresh CETH - sends transaction that invoke release function on ethereum -## Economic Incentive +Economic Incentive +------------------ Ethermint can take a percentage of the CETH is a transaction fee. Ethermint can take a percentage of the ETH when releasing them. -## Questions +Questions +--------- - How does a validator look that runs ethermint and basecoin at the same time? - Are the economic incentives good enough and can there be a market mechanism around establishing the correct percentage cut? - Is CETH used to pay for execution of the ethermint EVM? @@ -55,5 +74,7 @@ Ethermint can take a percentage of the ETH when releasing them. - Maybe there is none and the fee is set as a percentage by the COSMOS validators - How will IBC work in relation to ethermint? -## Invariants +Invariants +---------- - the amount of CETH in circulation is equal to the amount of ETH held by the smart contract on the Ethereum chain + diff --git a/docs/assets/ethermint-logo.png b/docs/assets/ethermint-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ebca411ae6275a841effd63678ae8c275b9a5231 GIT binary patch literal 70115 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 z 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%0D59uP4rBnZg`CQ)F>pAZIzVZ+n1SbLTH~z$ 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 THPYb^F!mICE@omu901*yQyh$Eyu99 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�X}POrXi4c*dMAW9RW+Voh*M>XEgC>RZIH+Wbsa$?ET+ zJ2r^9zoU@nxgUgJXIfE2kM5T)D;I;Lr3WDZImj*Jn)#0=vIln&kqO0~1QX)F!6pbF zT=4mv+Z&r_LQt_(YG&QuNAy~La@UOa<`P6=lJzeTN5`n%2uz0a=~gmZhr3h4b(v*Y z)r_qBNIF%c*$?@XYwKXGt`P`OY@|H^m8w`roa&a5j;J?wUlJ4mop1%dC9c{C_Zz;% zoNXLAn{o9?O%N>;|K;YEsJYKk2o<+-1~%ooj(s%zl0<_zBx^iary%YP2fDNyR46WN z?H)bdrD=W_M?Oi6Z{rTPQVep<=+#Vy$HyUu2#0L52cyow-z||S-|^S^y)Y;GROL-M zc%-ahdSq)R!kv;L?A%Bf5o^G_R?>STAp5tAfzE4O?bnGk5T?7jr&5S}mg z@voa4ctALma1g%FI{++ds#)`O^zv@;q@67j+M2RK&g^_0Tgkk=svGUY<#d{=N9?Z4>V|9FoHmV;>Ex)Hj0p8DX4s7X` z;ZAmVl{ceS``o+1T4%2)?yUkOK0oq??=r=t!dk(P0f=Byx;Ge8oLKI4Fjv;1D@|(R zY3{Wb{vtxzFIDKgGK22E@n{DlY|AQK1r9o@$xnh0z&~B0$XV+c2L)fdy`RLVPF@F6 zvgO9=ON*20@m8InPrh`zXwsc*wNO$LKDhVj$M*LQu2k84DOdawQ`K@+wT$bd+L{-q zu``as8JVs2(}601vlS@WVmmhZ_=k{m3}}du=C`Qs)fX?&^ik{_ygCcC7j5%yTq~5M zhX;Nn(z*8<9a08FtASCGg=DG1@!^HbRWOl4&SL~}AUkFe^hot0C>76EZU4(;@7=+! zpkMY$v8$PLj!Ws2Pr_f}$i zssS$mW5*7Kx8+%TRO{F>yYZy*vYgJ@`^C|cpTu{TTo&QjaKq6}?a)P2P&3~#a703c zq&=R{$&nbF9o#^%f8!477{(O~&hwLpW@0wVEid!+4eb5O&pnLP@Ek7YT|vQXxR`kk zvWRNxLS(CE+TwFAV0?8(YO9=#U$^XC{{$z)k$u4-J9Eplz~wy+tXHb0iY`ns0@1+6 z`N(3MZ+Fz2>%=Ui4p~rh=i|!90Q}F7#4bhH6xJ$x5vSPI^sVh49kpD_7<3kd`vEP0 z=|_LxLjtgyCDPG*L~*-)?ayR`AZeh4;6_|RCWgI7YZ5zcTWamXCDE;@93#<>Fzv44 z2aDCfmpoi*d?Lr9r(ybp5X1Fs^7ZYaiz_o9d2tZG_zXc824Yek@RS`MU{zSfAqEpD zokFSM#6K6lIJ#@|>5Cwz0+1n#ixL|1!|p{|v2ySCj^#I#GftX(<|1rr#_5$MszdSa zD?JxlYJGtVRVz{$n<-- z8e?Z%a9h9zcJ5B=+w=5jh=(6r3=^zm{0MRMRlTD$a`OWyP(m`p{j8#)tgJs_L z7^Ysg14M%or!3BUfm;jS@51zY&)!?9`Jar%M0#1(3`VN-dm5tReArtp`#@AaPjOJ0 zZEoOgc#Mf<#zao)^vxe^oY6|;MHca7WsX|!Wy+$^etLASL|s_RG%m{x5;RNc_6y9+ zw~fCUns|C^(O92B1W^h0=IgwXZT=xQ^&i)!AaL)CUv~&p;yro*6qtcO0l9X1LLkgR z${jz>8MsoRY&(_mz*}hFCA7cOEr0!a+bG2IhXc%3*zeGhuM_+o%I8yp znwzg5j7RB-G4c$F-de@14HdCAf5+P}dkG8tILGeSPX=;Tmxi(QLx>Ver}I?dehMlM zB|)RD@m{~%w#fog`c}M$!bWW3kq-Tvy7g*EasN}k^67GtZyeCK{mg707ME@LK}&yR zW!0#0$d9E{%d#73PTB#qA)~K&2cDZ^Mx>C#);=ET!GO@$5#ohT-PUVAzPPOzf8+^6 zx;?cMl9h%)9m>ymmQwp5`n^LkF0NF3kD8M+b7}e6a80S9Uk7<-;lHj+g7t(30bqsJp;YH*Pz2+YFs`R%=X#U^%eNgv#Y#kif|eBma$WZ*-3I{tG)WZj3} zWiBbFi`U~4squFm8a1^ol1;ihL034k3V8p;uaQV^SMiQ+=A5b)lJeSxU-cxTsU#2M zs_~cfGPxufrW;6#a4E)EkJ7{$FHGB{bMa?=}vt?@%n0+gI zqP#8Nl`)__%G2XuDJfkK*jyiM1Vd52iPU89gw#ER=PQ$Bl!bz_(o&a0))FPQLv- zh2-WOZPWCpl?R3{Ev!Ep#A7W2I{Za&!o^8$Ks|K$GsGVyJA@y)n`(f+GB8&CsIRnb zD_v)J?WTbYU+pXiQ5N2k086*A?M_ve=$7Dh?wH9Dh|Zxtn3+yGR4$=O3-_Va>rhQ< zDdaMNcSS#;)@;K_{XHVs?RL=!I-~g@6XTu&1vpHMPYy z#yn0)_nmZOdI=PIikXs#j%)U0&|f9naF&<@*{>LJ!TAvKMBII+ietk_i1 zK^hS~5S9%gEawVZLi-*^PQfEq3!<%en~ee_10#u)oe94Tr8q1W3!?9D!j;Iz_IyN# z)lc`|LYf`5Pvvz-#!gDb52ns8P&Bunu9VoA=8%m<+ox&6?o+;N*oSG(-IKGC`tnk_ zK~-de9!KE22>-@4Zhbv1i#Bv|9Rx5ZK|XWTH_By3Tzfv;uw3v(_T33oXpVlkr+lVS zuAvF7C0Qc}7<=O_i4GBIK7tC|jvl!=F9zs$LJ6c(HCI(Fk}YnGZpMiWA&I3!0<{BT z3D1i^;ZiDsO(E`9)9L3`o^KSIk7wCYXK=fC;ejH;q=W_uaN7$9>9IFeA+&4Ln0IlE zcj7W$oiQb(@5g(JjW%0_MhsePCI*<%ECiMGeB5L+dh71eb-TqlVR8|p_|(vrqY(Bphx?SCw#B*4Cz;EfT)oB)1Gaf31FIxR-H&ErpocsNdPU4+WmNh6?Y zbWNXaGrx3bfY?UU=14hV%qaQ-jUkX!U8>I&IHvinzVtEEroXfzu8Q&uQJtibN7R>h z5Y9c%Lx^Du93{&Y1+}hac_Z=@P$-1{bcHfjloeyx-^T^BCds@{K0m~!t#9qMOs%yF znxn|xO~AbNAB_RPM@}uv3@TN&7fZ`mJ`1-7kd#aVN_C>jEiOwxce{2^`;9$HJ$UBt zT*h<}`(YRb{-ZeQU}!_Ro5bohd!N-E>A7F28sDBAZ#|)h+4X+V8AmRU4LAX$x6cVt z5P45PdYjE-acfEQJ6HK_GYOf2U35${n_#tb6mv?EyXjZ>jY>XU5pr(u;KBsUx5g|D zdjV9IvkK>f(V2<~U4Rb;TIuEas@mmp*7bR!sXadj(h_CLwh)jSScR{{x_!-j7=(Vr zB;J%3Q{%kiwwoZjZ+@U!%(nKExj{yJ3^E==2u68&>K8$`>HGfyZJWiVLmEg`Ybm_; z+Q(*KPd;6QCz&}7HP8!6NULuO=+0!ec8A(a+IAN8P|7a%xBnUm6-yQ`zYdBL^?+4{ zEzh1rSoI?j1>3YTmY4vXt~S}~(!_*Gnf0@j7ZF%W69paUPAzIg!DHjQ9;vcezj)QP zD9E?SPdpse7XC$NINEM52Gi>Y2yz^?r}rbw7lSWzf7>>2glDjK4!0d|&pP?nRAjlO zFJEz`2}Zb+(xbtpZ-_^vBil(A>=+*039**>8cBp;`6Xr$%7LdGMa-DXb#ipz)Jo=1 zR3bS;Q&2m?PxFih`%}_e4h7dwiwYJcqOBiVkhlVU;Le@{Uhc?vQ4$Q0rUBN4^VcevO^3{ zdo+r`GpleZl@jM;I~Pel-YERcmw>8LF5bRG?Ux6!U#5)PZf{QS z?_ZjIw^WNoq~mSx-ULf;>Au+&<5xcz(Qp7E3NFRdjq54)$T1ArcC~6U^Q0E)?SwcR z&{#DplA9%_gWmoK0kl)hBB;@r#b4ZAfXKPU!_#NE%Lg?!PPkkPpA zzd%2Ch+?>wWM!NmUw$D2e`w3i29%clFK0O0owZ5!KfSgD0WN>XUT) zJwWo0D1USMoR#fPm%9hcBsL_EShv(R=ws{@fd`;_hqd)v3|Ed38A^Vq+dEMDY=Ome zpE`N?@_HLkFmg=;0>C=`a|i=f=0=YF_^7tzc(-*nk4P$j$}z=CV_6695_AhVvLI+g zmU{r&6`(x@@>_~z#1$PUk6%1(4(a?l875!#HMXue9!p>brVtC8-^J|#-LSDwwow>V zeEOYiOf}2T;XR&PTXkKK@}jBY9|bGoVOSit*Fkf{ne~;x{D*6dAz5M2<8>XzaS6FBnvqI~2z>oflC8!#BgJ=UvD^TBZxiL6>rVrLj* zRS5pvIXOGGyOHr>jpB`T7ZtJlItUS?Db_3lR1AQmJpVx3dy07LM|)KV za?i%V(C)Sidp7kZ3YTF}@!T7eHWMG=xUC^)yu_JRA&08?@Nu|)x0K36dlgnb5b}T& z)y;Nk#;|jgSfS(K%fusP-<}=)c1@PZ8MU>crLFhQ-L_abtarqRohcG5zyM8KfGld~# z#$mqMxJDv>A)D*h$eJfn&7VY%p|e330|M<>Qy`Lp5W|`%*Tq%Y{hp_Ax_*77%SSV!P7YM}@~30#^tL z_#wo%RL`4OWw%5ydVPOyK4*nam1vx*drPN+Pk(V<)`1<^;iAn!#qtlBkof5u_$`Me zqsTQ+M6+YY*ww?UnA`_Oj>52`SOAh?1e+eqq zZk})q%JKmH*|FOgi%Fy~;>32HFlgS!D_ko*Q9BQ`i?gp$A7e4XgLL>t)()HkLpaS$ zsZoYsY$?At#?9SEIb!XlX|g6)c_@Z5Nr%9MlODLC6v8T;N^{mbG2&!`v)qa^l5Z zMromQ0sxt8dmlnCe7eWU?|LbrEhV#bFn;tNVoXYP(5a$p9K7fjSe=SM(Ge`x7co(4 zsE3Mweq0SwiulzjW9N3A*|45e$ClcYEkISk;@!W8GEfx?QveNsmoWRn$X6Ov0!d8? ze4phl3Z)oUD>YejS!ri zkps=^MBDF#c^yQrTK6Qa$oM>Zdh3Az_uJx%6ANPPLrI&Uhz`F5*{mzmVJlk8FVYe3 zE*0Rk>V&{-$vcnGHn*S#1Z9=_-(|cjD?EZ$#h#%KCynREsUgAAad_zCXDruUJmX5V z^lytYQF44#b_{-B6(5V9b1^a7N=Jh)`IiRC^a`|=QD-# zHJd4VVaBgX)E<5=d#O^{jORpn#15FPkgxd~%b}le2<^)H3h+gAat8r^!n!N+z?=qo;53-JEwZX*Zup@TqPc5|iv zshn^oxqxm@&fw5tks<#kGE75wyyp=_ScDEQ0xHhZwO7PqzzL#*)@-ZfS*wl?IlZ(s zh68MFQl57eW23*C%Rb6G$bfF40YORtW}#(G*?;OA4TnSW0ef=NVzeb}CF#hjH8#oV=AeDvMh z8J+JJ0+#^M&N%KrG9Rx@Zkgv{Dn4vYQ3#iy$W26)l-W6ro2MtwjhN8 z60ZZ}(2C47rG0wK{L4ToKf{mbY0D`bAqrxv1snOr!|Te}w>WYGT%qjHduHreKBazF zb9%`?)b9?At(TOaa8It&lsdxtbCCCFP*VuzRftuBCs=#BuqQ^s@IE=;;BW2t-2blE zX=UX*(eS>|m*1JbiDr8aXt9338FrUdDCF8Ke-&v`e%zK8=GioQwn-U>ZUKz}LS3Ch zDMMoMU4+3s3Ec1gk*A@RTFj~1OSzR`d0D#8eI;Qg2%1E&sDlS|-TllQjV}Sszx(xG zhCu1j0y?XemliT1H}m<})(`Muq0Q+I3ZNqrSZW63AW6155^~9#aZ7PSV~Mt98dT&o zr#c1MLHPKtI!qpQW)<6(&cx2-w(ihF3_)Y%C`*}XVih7I2N*>a--*7r! zu!`53^Qf37X|)Q9sRZJ1J6+UI9y7QQ;)&TAG#tSVoo-heVrrzGBd;7{u<37}_Sp8_ zr`?3hTqmhu8dGT~i3J7bTOKr{(q&h;xU>eppI~end3Rz*;EqKN^(C z1G8+n;|0Ka% zUjDPo=(%(Q{GKz8^%=d_Zv1g^wfW*g2E8luuMcswJ)1!U5o4=4OoTwPy6JToXSq~7 zNEd!dYxZ*#nuTyFQo=3_NB#gF#8G~DKdpKIiWUZ}Ajq1T-0rzwD}Ph-JN4zutIRZW zkW~Y7I98a0ifq*OFBA`YzWzM>0K4M&_18-&s$w?7KNeLUS|5)&jP+_*h0)ZbI*X7S z(zlw9_3+J8GP2nU5Cakw<*tkkq)zQR-hjj;rDuWA0um{O=m>nOLGU=EE;BDMCrXuy(0}8$;FvGeO--x{=qjEgAX5 zgyC-i0d?lZ5*y5(T*q71BrqUGXcmQ9r@J`}!-_G8p$&I*v+VS}){|B)56rQAumuZt ze{}d2aJ$7lNob}6#tu%7WUaileV4&~*1U2V_wp@8wsxwclpulCcmz?@8ehO`qUkF_ zo`k38+nB_@;lX+SPg?icHpWj?^3+5TH*c^3<+HYK)I|V2j^a~i?~XwmFHttv%bdQO z!h0E|g{S$Mqbnv@bcf840@pI;)=E1<(tc^jOCiwoD*w&Z;OVh{W7G;!#nHF ze%Q~$ziGo9;=TLwTC%i0JA(EwQwR1}syB?a;ZXlQ$HAN)2!z0w4v$sg?_tc>Ss6LQT%u5^pL0Ho_-Dm66~8YZ6vXf z&~cLysN_i>f?%K`YEF*u0sQ&PYgbHs34{OMZBRI~Cj zSf-=jv?uV|<|+T%W&E%~!G5Et5LfCKoqksH`1U737W9}a{{QY(K|sI7b~e zdQ0dLx7~2LhJACfH{4`wzGVi@zic@lxewEzZR+=@t8;D3&%S2-d;`5$nN=m!Zv$X^ zcBF1&zp(k~541-Jd$|%1XDcszs4R4c)_TnW`Qkdi;8jD*frLEh0qRyKHPe*2wuS7c z>Cn(w@pk=BSDm#9=vRNJ2r^Px5Wwm=c)>2jJ6NB~rrBhgxF-w=yy^MUCA7LjXBOgv zM@y|x&6anr07+Tz&&4sv2>&q@>l?2nuSD0b_=URoE)C{1xrW9OsFe05IItpd z03XfX;YoXZ(_8p-86Zy_G*FNH&pPY}K2)M=lm4V#9!&&5QrsYKv#x;5rq^#i1HB<0 zoFd&eTA}!#jqDL7I1yJzBTi_-!A{=b6hMrm(9Co5_84OkEZAzucHr-K(Y}5q0=31z zLjQed|7!YQ^MFM7uOt2&J!m1}-#GnuBEw+&zsco4+4tWx{x9~R`2>Rf{};-mZtR#k XnO~E}C}WC)f9j{SPd+(ref9qV;#I%R literal 0 HcmV?d00001 diff --git a/docs/conf.py b/docs/conf.py index 0b5f45e6c5..e3a21c2f7c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -70,7 +70,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'architecture'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'to-sort'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' diff --git a/docs/getting-started.rst b/docs/getting-started/getting-started.rst similarity index 99% rename from docs/getting-started.rst rename to docs/getting-started/getting-started.rst index f0381977e0..cb6755879a 100644 --- a/docs/getting-started.rst +++ b/docs/getting-started/getting-started.rst @@ -1,13 +1,10 @@ +.. _getting-started: + Getting Started =============== Running Ethermint requires both ``ethermint`` and ``tendermint`` installed. Review the installation instructions below: -.. toctree:: - :maxdepth: 2 - - installation.rst - Setup Ethermint ------------------ diff --git a/docs/getting-started/index.rst b/docs/getting-started/index.rst new file mode 100644 index 0000000000..45333e953d --- /dev/null +++ b/docs/getting-started/index.rst @@ -0,0 +1,7 @@ +Getting Started +=============== + +.. toctree:: + :maxdepth: 2 + + getting-started.rst diff --git a/docs/index.rst b/docs/index.rst index 8d40ca7e73..5e5d266e67 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,24 +3,22 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to Ethermint's documentation! -===================================== +Ethermint +========= -Contents: +.. image:: assets/ethermint-logo.png + :height: 500px + :width: 500px + :align: center -.. toctree:: - :maxdepth: 4 - - introduction - installation - getting-started - connecting-to-testnets - architecture +Contents +======== -Indices and tables -================== +.. toctree:: + :maxdepth: 4 -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` + introduction/index.rst + getting-started/index.rst + testnets/index.rst + architecture/index.rst diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index 11e44375ed..0000000000 --- a/docs/installation.rst +++ /dev/null @@ -1,2 +0,0 @@ -Installation -============ diff --git a/docs/introduction.rst b/docs/introduction.rst deleted file mode 100644 index c516b33174..0000000000 --- a/docs/introduction.rst +++ /dev/null @@ -1,2 +0,0 @@ -Introduction -============ diff --git a/docs/introduction/index.rst b/docs/introduction/index.rst new file mode 100644 index 0000000000..bb522c7b3e --- /dev/null +++ b/docs/introduction/index.rst @@ -0,0 +1,7 @@ +Introduction +============ + +.. toctree:: + :maxdepth: 2 + + what-is-ethermint.rst diff --git a/docs/introduction/what-is-ethermint.rst b/docs/introduction/what-is-ethermint.rst new file mode 100644 index 0000000000..b70262cec0 --- /dev/null +++ b/docs/introduction/what-is-ethermint.rst @@ -0,0 +1,7 @@ +.. _what-is-ethermint: + +################################################################################ +What is Ethereum? +################################################################################ + +Ethermint is a blazing fast PoS blockchain that is fully compatible with Ethereum. diff --git a/docs/peg-zone/contract_design.md b/docs/peg-zone/contract_design.md deleted file mode 100644 index 80534526fa..0000000000 --- a/docs/peg-zone/contract_design.md +++ /dev/null @@ -1,19 +0,0 @@ -# Tendermint Light Client in Solidity -At a very basic level the light client needs to implement the same logic implemented in -tmcli. Running a light client revolves around the basic idea of tracking changes to a -validator set given a trusted genesis state. - -## contract TendermintLightClient -- chainID -- []currentValidator -- latestHeight -- mapping(blockHeight => []Validators) - - trusted validator set at blockHeight - - 0 index maps to the original validator set -- initialise(chainID, originalValidators) - - assign the chainID and the originalVals -- update(Commit, Header, []Validators) - - reject all updates where the Block is lower than latestHeight - - validate consistency of block against chainID - - actual verification([]currentValidator, []newValidators, chainID, commit, height) - - need to verify that precommits and check that more than 2/3 of old vals did precommit for the block with the new validator set diff --git a/docs/peg-zone/solidity/TendermintLightClient.sol b/docs/peg-zone/solidity/TendermintLightClient.sol deleted file mode 100644 index a8ef82fe4d..0000000000 --- a/docs/peg-zone/solidity/TendermintLightClient.sol +++ /dev/null @@ -1,22 +0,0 @@ -pragma solidity ^0.4.4; - -library TendermintLightClientLib { - struct Validator { - address addr; - bytes32 pubKey; - uint votingPower; - } -} - -contract TendermintLightClient { - using TendermintLightClientLib for TendermintLightClientLib.Validator; - - // blockHeight => ValidatorSet - mapping (uint => TendermintLightClientLib.Validator[]) trustedValidators; - string chainID; - - function TendermintLightClient(Validator[] validatorSet, string chainID) { - - - } -} diff --git a/docs/peg-zone/solidity/contracts/ConvertLib.sol b/docs/peg-zone/solidity/contracts/ConvertLib.sol deleted file mode 100644 index b97c88d7b6..0000000000 --- a/docs/peg-zone/solidity/contracts/ConvertLib.sol +++ /dev/null @@ -1,8 +0,0 @@ -pragma solidity ^0.4.4; - -library ConvertLib{ - function convert(uint amount,uint conversionRate) returns (uint convertedAmount) - { - return amount * conversionRate; - } -} diff --git a/docs/peg-zone/solidity/contracts/MetaCoin.sol b/docs/peg-zone/solidity/contracts/MetaCoin.sol deleted file mode 100644 index 46069a939d..0000000000 --- a/docs/peg-zone/solidity/contracts/MetaCoin.sol +++ /dev/null @@ -1,34 +0,0 @@ -pragma solidity ^0.4.4; - -import "./ConvertLib.sol"; - -// This is just a simple example of a coin-like contract. -// It is not standards compatible and cannot be expected to talk to other -// coin/token contracts. If you want to create a standards-compliant -// token, see: https://github.com/ConsenSys/Tokens. Cheers! - -contract MetaCoin { - mapping (address => uint) balances; - - event Transfer(address indexed _from, address indexed _to, uint256 _value); - - function MetaCoin() { - balances[tx.origin] = 200000; - } - - function sendCoin(address receiver, uint amount) returns(bool sufficient) { - if (balances[msg.sender] < amount) return false; - balances[msg.sender] -= amount; - balances[receiver] += amount; - Transfer(msg.sender, receiver, amount); - return true; - } - - function getBalanceInEth(address addr) returns(uint){ - return ConvertLib.convert(getBalance(addr),2); - } - - function getBalance(address addr) returns(uint) { - return balances[addr]; - } -} diff --git a/docs/peg-zone/solidity/contracts/Migrations.sol b/docs/peg-zone/solidity/contracts/Migrations.sol deleted file mode 100644 index 7e7fe8d472..0000000000 --- a/docs/peg-zone/solidity/contracts/Migrations.sol +++ /dev/null @@ -1,23 +0,0 @@ -pragma solidity ^0.4.4; - -contract Migrations { - address public owner; - uint public last_completed_migration; - - modifier restricted() { - if (msg.sender == owner) _; - } - - function Migrations() { - owner = msg.sender; - } - - function setCompleted(uint completed) restricted { - last_completed_migration = completed; - } - - function upgrade(address new_address) restricted { - Migrations upgraded = Migrations(new_address); - upgraded.setCompleted(last_completed_migration); - } -} diff --git a/docs/peg-zone/solidity/contracts/TendermintLightClientLib.sol b/docs/peg-zone/solidity/contracts/TendermintLightClientLib.sol deleted file mode 100644 index 3a0b1553a2..0000000000 --- a/docs/peg-zone/solidity/contracts/TendermintLightClientLib.sol +++ /dev/null @@ -1,9 +0,0 @@ -pragma solidity ^0.4.4; - -library TendermintLightClientLib { - struct Validator { - address addr; - bytes32 pubKey; - uint votingPower; - } -} diff --git a/docs/peg-zone/solidity/migrations/1_initial_migration.js b/docs/peg-zone/solidity/migrations/1_initial_migration.js deleted file mode 100644 index 4d5f3f9b02..0000000000 --- a/docs/peg-zone/solidity/migrations/1_initial_migration.js +++ /dev/null @@ -1,5 +0,0 @@ -var Migrations = artifacts.require("./Migrations.sol"); - -module.exports = function(deployer) { - deployer.deploy(Migrations); -}; diff --git a/docs/peg-zone/solidity/migrations/2_deploy_contracts.js b/docs/peg-zone/solidity/migrations/2_deploy_contracts.js deleted file mode 100644 index b3dc3e9065..0000000000 --- a/docs/peg-zone/solidity/migrations/2_deploy_contracts.js +++ /dev/null @@ -1,8 +0,0 @@ -var ConvertLib = artifacts.require("./ConvertLib.sol"); -var MetaCoin = artifacts.require("./MetaCoin.sol"); - -module.exports = function(deployer) { - deployer.deploy(ConvertLib); - deployer.link(ConvertLib, MetaCoin); - deployer.deploy(MetaCoin); -}; diff --git a/docs/peg-zone/solidity/test/TestMetacoin.sol b/docs/peg-zone/solidity/test/TestMetacoin.sol deleted file mode 100644 index 96ccc1e229..0000000000 --- a/docs/peg-zone/solidity/test/TestMetacoin.sol +++ /dev/null @@ -1,25 +0,0 @@ -pragma solidity ^0.4.2; - -import "truffle/Assert.sol"; -import "truffle/DeployedAddresses.sol"; -import "../contracts/MetaCoin.sol"; - -contract TestMetacoin { - - function testInitialBalanceUsingDeployedContract() { - MetaCoin meta = MetaCoin(DeployedAddresses.MetaCoin()); - - uint expected = 10000; - - Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially"); - } - - function testInitialBalanceWithNewMetaCoin() { - MetaCoin meta = new MetaCoin(); - - uint expected = 10000; - - Assert.equal(meta.getBalance(tx.origin), expected, "Owner should have 10000 MetaCoin initially"); - } - -} diff --git a/docs/peg-zone/solidity/test/metacoin.js b/docs/peg-zone/solidity/test/metacoin.js deleted file mode 100644 index c61c0937d5..0000000000 --- a/docs/peg-zone/solidity/test/metacoin.js +++ /dev/null @@ -1,63 +0,0 @@ -var MetaCoin = artifacts.require("./MetaCoin.sol"); - -contract('MetaCoin', function(accounts) { - it("should put 10000 MetaCoin in the first account", function() { - return MetaCoin.deployed().then(function(instance) { - return instance.getBalance.call(accounts[0]); - }).then(function(balance) { - assert.equal(balance.valueOf(), 10000, "10000 wasn't in the first account"); - }); - }); - it("should call a function that depends on a linked library", function() { - var meta; - var metaCoinBalance; - var metaCoinEthBalance; - - return MetaCoin.deployed().then(function(instance) { - meta = instance; - return meta.getBalance.call(accounts[0]); - }).then(function(outCoinBalance) { - metaCoinBalance = outCoinBalance.toNumber(); - return meta.getBalanceInEth.call(accounts[0]); - }).then(function(outCoinBalanceEth) { - metaCoinEthBalance = outCoinBalanceEth.toNumber(); - }).then(function() { - assert.equal(metaCoinEthBalance, 2 * metaCoinBalance, "Library function returned unexpected function, linkage may be broken"); - }); - }); - it("should send coin correctly", function() { - var meta; - - // Get initial balances of first and second account. - var account_one = accounts[0]; - var account_two = accounts[1]; - - var account_one_starting_balance; - var account_two_starting_balance; - var account_one_ending_balance; - var account_two_ending_balance; - - var amount = 10; - - return MetaCoin.deployed().then(function(instance) { - meta = instance; - return meta.getBalance.call(account_one); - }).then(function(balance) { - account_one_starting_balance = balance.toNumber(); - return meta.getBalance.call(account_two); - }).then(function(balance) { - account_two_starting_balance = balance.toNumber(); - return meta.sendCoin(account_two, amount, {from: account_one}); - }).then(function() { - return meta.getBalance.call(account_one); - }).then(function(balance) { - account_one_ending_balance = balance.toNumber(); - return meta.getBalance.call(account_two); - }).then(function(balance) { - account_two_ending_balance = balance.toNumber(); - - assert.equal(account_one_ending_balance, account_one_starting_balance - amount, "Amount wasn't correctly taken from the sender"); - assert.equal(account_two_ending_balance, account_two_starting_balance + amount, "Amount wasn't correctly sent to the receiver"); - }); - }); -}); diff --git a/docs/peg-zone/solidity/truffle.js b/docs/peg-zone/solidity/truffle.js deleted file mode 100644 index c63ce22792..0000000000 --- a/docs/peg-zone/solidity/truffle.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - networks: { - development: { - host: "localhost", - port: 8545, - network_id: "default" // Match any network id - } - } -}; diff --git a/docs/testnets/index.rst b/docs/testnets/index.rst new file mode 100644 index 0000000000..487d00f0f5 --- /dev/null +++ b/docs/testnets/index.rst @@ -0,0 +1,7 @@ +Testnets +======== + +.. toctree:: + :maxdepth: 2 + + venus.rst diff --git a/docs/connecting-to-testnets.rst b/docs/testnets/venus.rst similarity index 99% rename from docs/connecting-to-testnets.rst rename to docs/testnets/venus.rst index 0c28e0c190..f9da804bd8 100644 --- a/docs/connecting-to-testnets.rst +++ b/docs/testnets/venus.rst @@ -1,10 +1,12 @@ +.. _venus.rst: + Connect to a testnet ==================== Join the ethermint testnet with a few commands. This guide is based on the `original Medium article `_. Pre-requisites -------------- +-------------- You'll need the ``ethermint`` and ``tendermint`` binaries installed with the correct version. Ensure you are using compatible versions (how?). See their respective repos for install instructions.