diff --git a/docs/design/bootstrapping.md b/docs/design/bootstrapping.md new file mode 100644 index 000000000..7259d59bb --- /dev/null +++ b/docs/design/bootstrapping.md @@ -0,0 +1,22 @@ +# Bootstrapping + +This document describes the bootstrapping process for the Gravity bridge. + +We assume the act of upgrading the Cosmos-based binary to have gravity module is already complete, +as approaches to that are discussed in many other places. Here we focus on the _activation_ step. + +The [Gravity.sol](/solidity/contracts/Gravity.sol) contract can be initialized with the validator set from an active chain or from a Genesis file. + +In a potentially contentious deployment scenario there may be an unlimited number of Gravity contracts deployed on Ethereum, each attempting to present themselves as the 'actual contract'. + +In order to decide which contract is valid a governance vote setting the [bridge_ethereum_address](/docs/design/paramaters.md##bridge_ethereum_address) should be held. Once again in a contentious deployment scenario there may be many such votes going on in parallel. + +During the voting process the validator set on the chain in question may change significantly. During the voting phase validators must run their `Ethereum Signer` but not their `Ethereum oracle` as there is no defined contract to relay events from. + +It is the responsibility of each contract deployer to run at least one `relayer` directed at their contract. This will take the signatures produced by the `Ethereum Signer` and keep the validator set up to date during the voting period. + +The `Ethereum oracle` implementation in this repo _should_, but does not currently (May 4th 2021), refer to the `bridge_ethereum_address` governance parameter and disable the `Ethereum oracle` functionality automatically until it is set. + +It is very important that validators must run their `Ethereum Signer` from the moment the chain starts, as the Gravity module will be producing validator set updates and they will be subject to [slashing](/spec/slashing-spec.md) immediately. + +Once the voting process is complete and the definitive Gravity contract address is set as a parameter bootstrapping is complete. diff --git a/docs/design/ethereum-signing.md b/docs/design/ethereum-signing.md new file mode 100644 index 000000000..017f7274d --- /dev/null +++ b/docs/design/ethereum-signing.md @@ -0,0 +1,26 @@ +# Ethereum signing + +As outlined in the [overview](/docs/design/overview.md) the [Gravity.sol](/solidity/contracts/Gravity.sol) contract acts as a weighted powers multisig for the funds sorted in the bridge. Effectively producing a situation where the validator set of the Cosmos chain owns all the funds in the bridge in a multisig that replicates their stake weighted voting power on Cosmos. + +## Delegate Addresses + +This document outlines the Ethereum signatures, all contract calls on [Gravity.sol](/solidity/contracts/Gravity.sol) accept an array of signatures provided by a validator set stored in the contract. + +Validators make these signatures with their `Delegate Ethereum address` this is an Ethereum address set by the validator using the [SetOrchestratorAddress](/docs/design/messages.md/###SetOrchestratorAddress) message. The validator signs over this Ethereum address, as well as a Cosmos address for [oracle](/docs/design/oracle.md) operations and submits it to the chain to register these addresses for use in the Ethereum signer and oracle subsystems. + +The `Delegate Ethereum address` then represents that validator on the Ethereum blockchain and will be added as a signing member of the multisig with a weighted voting power as close as possible to the Cosmos voting power. + +## Signing flow + +Validators run an external process called an `Ethereum Signer` this process is required because we can not yet insert this sort of simple signature logic into CosmosSdk based chains without significant modification to Tendermint. This may be possible in the future with [modifications to Tendermint](https://github.com/tendermint/tendermint/issues/6066). + +It should be noted that both [GRAVSLASH-02](/spec/slashing-spec.md) and [GRAVSLASH-03](/spec/slashing-spec.md) could be eliminated with no loss of security if it where possible to perform the Ethereum signatures inside the consensus code. This is a pretty limited feature addition to Tendermint that would make Gravity far less prone to slashing. + +Until such a change is provided the signing flow works as follows. + +1. The Gravity module produces a `ValidatorSetRequest`, `BatchRequest`, or `LogicCallRequest`. These requests are placed into the store and act as coordination points for signatures +1. `Ethereum Signer` processes query these requests and perform a signature with the `Delegate Ethereum Address` +1. The `Ethereum Signer` submits the signature as a [transaction](/docs/design/ethereum-signing.md##Ethereum-Signer-Message) +1. The Gravity module verifies that the signature is made with the correct key and over the correct data before storing it +1. `Relayers` now query these signatures and assemble them into an Ethereum contract call to submit to [Gravity.sol](/solidity/contracts/Gravity.sol) +1. The message is submitted and executed on the Ethereum chain diff --git a/docs/design/incentives.md b/docs/design/incentives.md new file mode 100644 index 000000000..8f828b2bb --- /dev/null +++ b/docs/design/incentives.md @@ -0,0 +1,23 @@ +# Incentives + +This document covers all the incentivization systems in Gravity bridge. + +## Validators + +Currently validators in Gravity have only one carrot. The extra activity brought to the chain by a functioning bridge. + +There are on the other hand a lot of negative incentives (sticks) that the validators must watch out for. These are outlined in the [slashing spec](/spec/slashing-spec.md). + +One negative incentive that is not covered under slashing is the cost of submitting oracle submissions and signatures. Currently these operations are not incentivized, but still cost the validators fees to submit. This isn't an issue considering the low activity on most Cosmos based chains at the moment. But an active Ethereum bridge and dex may change that issue very quickly. + +Some positive incentives for correctly participating in the operation of the bridge should be under consideration. In addition to eliminating the fees for mandatory submissions. + +## Relaying rewards + +Relaying rewards cover all messages that need to be submitted to Ethereum from Cosmos. This includes Validator set updates, transaction batches, and arbitrary logic calls. Keep in mind that these messages cost a variable amount of money based on wildly changing Ethereum gas prices and it's not unreasonable for a single batch to cost over a million gas. + +A major design decision for our relayer rewards was to always issue them on the Ethereum chain. This has downsides, namely some strange behavior in the case of validator set update rewards. + +But the upsides are undeniable, because the Ethereum messages pay `msg.sender` any existing bot in the Ethereum ecosystem will pick them up and try to submit them. This makes the relaying market much more competitive and less prone to cabal like behavior. + +For a detailed look at how exactly all rewards are paid out see the [minting and locking](/docs/design/mint-lock.md##Relaying-rewards) design documentation. diff --git a/docs/design/messages.md b/docs/design/messages.md new file mode 100644 index 000000000..353f53d73 --- /dev/null +++ b/docs/design/messages.md @@ -0,0 +1,89 @@ +# Gravity messages + +This is a reference document for Gravity message types. For code reference and exact +arguments see the [proto definitions](/module/proto/gravity/v1/msgs.proto) + +## User messages + +These are messages sent on the Cosmos side of the bridge by users. See [minting and locking](/docs/design/mint-lock.md) for a more +detailed summary of the entire deposit and withdraw process. + +### SendToEth + +SendToEth allows the user to specify a Ethereum destination, a token to send to Ethereum and a fee denominated in that same token +to pay the relayer. Note that this transaction will contain two fees. One fee amount to submit to the Cosmos chain, that can be paid +in any token and one fee amount for the Ethereum relayer that must be paid in the same token that is being bridged. + +### CancelSendToEth + +CancelSendToEth allows a user to retrieve a transaction that is in the batch pool but has not yet been packaged into a transaction batch +by a relayer running [RequestBatch](/docs/design/messages.md/###RequestBatch). For more details on this process see the [batch creation spec](/spec/batch-creation-spec.md) + +## Relayer Messages + +These are messages run by relayers. Relayers are unpermissioned and simply work to move things from Cosmos to Ethereum. + +### RequestBatch + +Relayers use `QueryPendingSendToEth` in [query.proto](/module/proto/gravity/v1/query.proto) to query the potential fees for a batch of each +token type. When they find a batch that they wish to relay they send in a RequestBatch message and the Gravity module creates a batch. + +This then triggers the Ethereum Signers to send in ConfirmBatch messages, which the signatures required to submit the batch to the Ethereum chain. + +At this point any relayer can package these signatures up into a transaction and send them to Ethereum. + +As noted above this message is unpermissioned and it is safe to allow anyone to call this message at any time thanks to the rules described in the [batch creation spec](/spec/batch-creation-spec.md) + +## Oracle Messages + +All validators run two processes in addition to their Cosmos node. An Ethereum oracle and Ethereum signer, these are bundled into a single Orchestrator binary for ease of use. +for further reference on this process see the [design overview](/docs/design/overview.md), [oracle design](/docs/design/oracle.md), and [minting and locking](/docs/design/mint-lock.md) + +The oracle observes the Ethereum chain for events from the [Gravity.sol](/solidity/contracts/Gravity.sol) contract before submitting them as messages to the Cosmos chain. + +### DepositClaim + +claim representing a `SendToCosmosEvent` from [Gravity.sol](/solidity/contracts/Gravity.sol). When this passes the oracle vote tokens will be issued to a Cosmos account. + +### WithdrawClaim + +claim representing a `TransactionBatchExecutedEvent` from [Gravity.sol](/solidity/contracts/Gravity.sol). When this passes the oracle vote the batch in state is cleaned up and tokens are burned/locked. + +### ValsetUpdateClaim + +claim representing a `ValsetUpdatedEvent` from [Gravity.sol](/solidity/contracts/Gravity.sol). When this passes the oracle vote reward amounts are tallied and minted. + +### ERC20DeployedClaim + +claim representing a `ERC20DeployedEvent` from [Gravity.sol](/solidity/contracts/Gravity.sol). When this passes the oracle vote it is checked for accuracy and adopted or rejected as the ERC20 representation of a Cosmos asset + +### LogicCallExecutedClaim + +claim representing a `LogicCallEvent` from [Gravity.sol](/solidity/contracts/Gravity.sol). When this passes the oracle vote the logic call in state is cleaned up and tokens are burned/locked. + +## Ethereum Signer messages + +All validators run two processes in addition to their Cosmos node. An Ethereum oracle and Ethereum signer, these are bundled into a single Orchestrator binary for ease of use. +for further reference on this process see the [design overview](/docs/design/overview.md), [eth signer design](/docs/design/ethereum-signing.md), and [minting and locking](/docs/design/mint-lock.md) + +The Ethereum signer watches several [query endpoints](/module/proto/gravity/v1/query.proto) and it's only job is to submit a signature for anything that appears on those endpoints. For this reason the validator must provide a secure RPC to a Cosmos node following chain consensus. Or they risk being tricked into signing the wrong thing. + +### ConfirmBatch + +Submits an Ethereum signature over a batche appearing in the `LastPendingBatchRequestByAddr` query + +### ConfirmLogicCall + +Submits an Ethereum signature over a batche appearing in the `LastPendingLogicCallByAddr` query + +### ValsetConfirm + +Submits an Ethereum signature over a batche appearing in the `LastPendingValsetRequestByAddr` query + +## Validator Messages + +These are messages sent directly using the validators message key. + +### SetOrchestratorAddress + +This message sets the Orchestrator delegate keys described in the [design overview](/docs/design/overview.md) diff --git a/docs/design/mint-lock.md b/docs/design/mint-lock.md new file mode 100644 index 000000000..2c80ddc19 --- /dev/null +++ b/docs/design/mint-lock.md @@ -0,0 +1,101 @@ +# Minting and burning in Gravity + +This document covers when, where, and how tokens are locked, unlocked and held in Gravity. +The task of any blockchain bridge is to hold tokens on one chain and issue representative +assets on the other chain. Unlocking the assets at some point in the future when they are +sent back across the bridge. + +Since Gravity is a bi-directional bridge that handles two asset sources, Cosmos and Ethereum +tokens may be held on Ethereum or held on Cosmos based on where they originated. Likewise tokens +are minted on both sides as well, to represent the assets from the other chain. + +## Ethereum based assets + +### Ethereum -> Cosmos + +An Ethereum asset implementing the ERC20 standard is deposited into the [Gravity.sol](/solidity/contracts/Gravity.sol) contract using the Solidity function call `sendToCosmos`. This locks the ERC20 asset in the Gravity.sol contract where it will remain until it is withdrawn at some undetermined point in the future. + +At the send of the `sendToCosmos` function call an Ethereum event `SendToCosmosEvent` executes. This event contains the amount and type of tokes, as well as a destination address on Cosmos for the funds. + +The validators all run their oracle processes which submit `MsgDepositClaim` messages describing the deposit they have observed. Once more than 66% of all voting power has submitted a claim for this specific deposit representative tokens are minted and issued to the Cosmos address that the sender requested. + +For further details on oracle operation see [oracle](/docs/design/oracle.md) + +### Cosmos -> Ethereum + +The Cosmos representation of the Ethereum ERC20 token, hereafter called a `voucher`, has been used and exchanged on the Cosmos chain for some time. Eventually some owner wishes to cash in the `voucher` and withdraw the actual asset on Ethereum. + +To do this they send a `MsgSendToEth` on the Cosmos chain. This removes the `voucher` from the users account and places a transaction into a transaction pool of `MsgSendToEth` messages for that same ERC20 token type. + +As part of `MsgSendToEth` the user specifies a fee, there is no mandatory minimum fee. But this fee must be paid in the same ERC20 asset they are returning to Ethereum (for the reasoning view the [transaction batch rewards](/docs/design/mint-and-lock.md/###transaction-batch-rewards)). + +At some point in the future a relayer will determine that the pool contains enough transactions to bother executing a batch of that type and relay it to Ethereum. For a discussion of edge cases here see the [batch creation spec](/spec/batch-creation-spec.md) + +When the batch transaction executes on the Ethereum chain the ERC20 token will be sent out the bridge to the Ethereum destination specified by the user in `MsgSendToEth`. An Ethereum event `TransactionBatchExecutedEvent` will be fired and picked up by the validators oracle processes. Once the resulting `MsgWithdrawClaim` has passed the `voucher` will finally be burned. + +Note that batching logic reduces costs dramatically, over 75%, but at the cost of latency and implementation complexity. If a user wishes to withdraw quickly they will have to pay a much higher fee. But this fee will be about the same as the fee every withdraw from the bridge would require in a non-batching system. + +## Cosmos based assets + +### Cosmos -> Ethereum + +A Cosmos asset first must be represented on Ethereum before it's possible to bridge it. To do this the [Gravity.sol](/solidity/contracts/Gravity.sol) contract contains an endpoint called `deployERC20`. + +This endpoint is not permissioned. It is possible for anyone to pay for the creation of a new ERC20 representing a Cosmos asset, but it is up to the validators and the Gravity Cosmos module to declare any given ERC20 as the representation of a given asset. + +When a user on Ethereum calls `deployERC20` they pass arguments describing the desired asset. [Gravity.sol](/solidity/contracts/Gravity.sol) uses an ERC20 factory to deploy the actual ERC20 contract using a known good code and assigns ownership of the entire balance of the new token to itself before firing a `ERC20DeployedEvent` + +The validators oracle processes observe this event and decide if a Cosmos asset has been accurately represented (correct decimals, correct name, no existing representation). If this is the case the ERC20 contract address is adopted and stored as the definitive representation of that Cosmos asset on Ethereum. + +For further details on oracle operation see [oracle](/docs/design/oracle.md) + +From this point on the process is nearly identical to the Cosmos -> Ethereum process for Ethereum originated assets. + +The user sends a `MsgSendToEth` that specifies a fee denominated in the token they are sending across the bridge. (for the +reasoning view the [transaction batch rewards](/docs/design/mint-and-lock.md/###transaction-batch-rewards)) + +At some point in the future a relayer will determine that the pool contains enough transactions to bother executing a batch of that type and relay it to Ethereum. For a discussion of edge cases here see the [batch creation spec](/spec/batch-creation-spec.md) + +When the batch transaction executes on the Ethereum chain the ERC20 token will be sent out the bridge to the Ethereum destination specified by the user in `MsgSendToEth`. An Ethereum event `TransactionBatchExecutedEvent` will be fired and picked up by the validators oracle processes. Once the resulting `MsgWithdrawClaim` has passed the Cosmos asset will be locked in the Gravity module to later be unlocked once it is returned to Cosmos. + +The tl;dr of this process is that the 'minting' of Cosmos assets on Ethereum is done all at once and the total balance simply exists in the [Gravity.sol](/solidity/contracts/Gravity.sol) contract at all times, which 'mints' them by sending them out and 'burns' them by locking them up again. + +As a related consequence this means that the supply of a given Ethereum asset on Cosmos is correct, but the supply of a given Cosmos asset on Ethereum is the total number of tokens minus the number in the Gravity bridge address. + +### Ethereum -> Cosmos + +This is identical to Ethereum -> Cosmos for Ethereum based assets. Please see that section and refer to the above section for details on how the overall process differs for Cosmos assets. + +## Relaying rewards + +### Validator set update rewards + +Validator set rewards are an optional chain [parameter](/docs/design/parameters.md). By default no reward is issued, it's important to maintain this behavior as the [Gravity.sol](/solidity/contracts/Gravity.sol) is not deployed containing any assets. + +At some point in the future a governance vote may select some Cosmos originated asset to use as a reward for submitting `valsetUpdate` transactions. From that point onward the specified amount of ERC20 tokens representing a Cosmos asset will be sent to `msg.sender` when submitting the `valsetUpdate` transaction to [Gravity.sol](/solidity/contracts/Gravity.sol) (see [incentives](/design/incentives.md##relaying-rewards) documentation for reasoning). + +Only Cosmos originated assets are allowed. So the ERC20 deployment process described in [Cosmos -> Ethereum](<(/docs/design/mint-lock.md##cosmos-based-assets)>) must occur first. + +By using a Cosmos originated asset we can effectively mint it on Ethereum indefinitely. After each `valsetUpdate` an Ethereum event `ValsetUpdateEvent` is fired, observed by the validators oracle process, and used to increment the total supply of that asset appropriately, locking the newly issued tokens in the Gravity module for later unlock. + +Minting tokens on another chain is not unusual for a bridge. The unusual part of this design is that we don't know exactly how many tokens we will end up minting. Relayers are free to submit every validator set, or only the latest if the voting power hasn't changed by a large amount. + +This is why we do not allow Ethereum originated assets to be used in this way. Maintaining the balance of the chosen Ethereum asset in the Gravity module bank would become an active effort and if the balance became insufficient validator set updates would fail, potentially causing the validators to lose control of the chain. + +### Transaction Batch rewards + +Transaction batch rewards are the sum of all `MsgSendToEth` fees for the transactions in a given batch. These fees are paid out directly to `msg.sender` on the Ethereum chain (see [incentives](/docs/design/incentives.md##relaying-rewards) documentation for reasoning). + +Currently [Gravity.sol](/solidity/contracts/Gravity.sol) is hardcoded to only accept batches with a single token type and only pay rewards in that same token type. This is logically very simple. + +[Arbitrary logic calls](/docs/design/mint-lock.md###arbitrary-logic-call-rewards) provide a way to structure a multi-token batch or even simply a multi-reward batch that future versions of Gravity may use. + +### Arbitrary Logic call rewards + +Arbitrary logic calls do exactly what their name implies. Allow for the execution of arbitrary ethereum code passed in as a bytes payload and target contract. + +Rewards for arbitrary logic calls are set on creation, like batches. But unlike batches arbitrary logic calls accept a list of ERC20 tokens and amounts to pay out as fees. Allowing for the relayer to potentially be paid many different types of tokens at the same time as a reward. + +Note that just because you can pay out an arbitrary number of tokens as a reward for a single TX does not mean you should. Each different type of reward token is an additional ERC20 transfer fee and if each reward is low enough it's possible that relayers will decide against relaying as no reward is worth more than the gas it costs to sell. + +Currently arbitrary logic is only used by Cosmos modules outside of Gravity that want to interact with Ethereum. Although user callable arbitrary logic is being considered from a security perspective. diff --git a/docs/design/oracle.md b/docs/design/oracle.md new file mode 100644 index 000000000..db6ab5827 --- /dev/null +++ b/docs/design/oracle.md @@ -0,0 +1,7 @@ +# ETH to Cosmos Oracle + +All `Operators` run an `Oracle` binary. This separate process monitors an Ethereum node for new events involving the `Gravity Contract` on the Ethereum chain. Every event that `Oracle` monitors has an event nonce. This nonce is a unique coordinating value for a `Claim`. Since every event that may need to be observed by the `Oracle` has a unique event nonce `Claims` can always refer to a unique event by specifying the event nonce. + +- An `Oracle` observes an event on the Ethereum chain, it packages this event into a `Claim` and submits this claim to the cosmos chain as an [Oracle message](/docs/design/messages.md##Oracle-messages) +- Within the Gravity Cosmos module this `Claim` either creates or is added to an existing `Attestation` that matches the details of the `Claim` once more than 66% of the active `Validator` set has made a `Claim` that matches the given `Attestation` the `Attestation` is executed. This may mint tokens, burn tokens, or whatever is appropriate for this particular event. +- In the event that the validators can not agree >66% on a single `Attestation` the oracle is halted. This means no new events will be relayed from Ethereum until some of the validators change their votes. There is no slashing condition for this, with reasoning outlined in the [slashing spec](/spec/slashing-spec.md) diff --git a/docs/design/overview.md b/docs/design/overview.md index 44a9934db..7b20be31a 100644 --- a/docs/design/overview.md +++ b/docs/design/overview.md @@ -1,8 +1,37 @@ # Design Overview -This will walk through all the details of the technical design. [`notes.md`](../notes.md) is probably a better reference -to get an overview. We will attempt to describe the entire technical design here and break out separate documents -for the details message formats, etc. +This document covers a general overview of the Gravity bridge design process, more detailed documents for specific +things are listed below. + +### Design docs + +[design overview](/docs/design/overview.md) + +[Bootstrapping the bridge](/docs/design/bootstrapping.md) + +[Minting and locking tokens in Gravity](/docs/design/mint-lock.md) + +[Oracle design](/docs/design/oracle.md) + +[Ethereum signing](/docs/design/ethereum-signing.md) + +[Messages](/docs/design/messages.md) + +[Parameters](/docs/design/parameters.md) + +[Incentives](/docs/design/incentives.md) + +[arbitrary logic](/docs/design/arbitrary-logic.md) + +[relaying semantics](/docs/design/relaying-semantics.md) + +### Specs + +[slashing-spec](/spec/slashing-spec.md) + +[batch-creation-spec](/spec/batch-creation-spec.md) + +[valset-creation-spec](/spec/valset-creation-spec.md) ## Workflow @@ -11,7 +40,7 @@ The high-level workflow is: Activation Steps: - Bootstrap Cosmos SDK chain -- Install Ethereum contract +- Deploy Ethereum contract Token Transfer Steps: @@ -53,11 +82,12 @@ Key concepts that we mention below will be defined here: - `Delegate keys` - when an `Operator` sets up the `Eth Signer` and `Oracle` they assign `Delegate Keys` by sending a message containing these keys using their `Validator` address. There is one delegate Ethereum key, used for signing messages on Ethereum and representing this `Validator` on Ethereum and one delegate Cosmos key that is used to submit `Oracle` messages. - `Gravity Contract` - The `Gravity Contract` is the Ethereum contract that holds all of the Gravity bridge bunds on the Ethereum side. It contains a representation of the cosmos validator set using `Delegate Keys` and normalized powers. For example if a validator has 5% of the Cosmos chain validator power, their delegate key will have 5% of the voting power in the `Gravity Contract` these value are regularly updated to keep the Cosmos and Ethereum chain validator sets in sync. -The _Operator_ is the key unit of trust here. Each operator is responsible for maintaining 3 secure processes: +The _Operator_ is the key unit of trust here. Each operator is responsible for maintaining 4 secure processes: 1. Cosmos SDK Validator - signing blocks 1. Fully synced Ethereum Full Node -1. `Eth Signer`, which signs things with the `Operator's` Eth keys +1. `Eth Signer`, which signs things with the `Operator's` Eth keys and submits using [messages](/design/messages.md##Ethereum-Signer-messages) additional documentation [ethereum signing](/design/ethereum-signing.md) +1. `Eth Oracle`, which observes events from Ethereum full nodes and relays them using [messages](/design/messages##Oracle-messages) additional documentation [oracle](/design/oracle.md) ## Security Concerns @@ -77,49 +107,4 @@ Thus, to avoid censorship attacks/inactivity, we should also update this everyti in the Validator Set (eg. > 3-5%). If we maintain those two conditions, the MultiSig Set should offer a similar level of security as the Validator Set. -There are now 3 conditions that can be slashed for any validator: Double-signing a block with the tendermint key from the -**Validator Set**, signing an invalid/malicious event from Ethereum with the Cosmos SDK key held by its _Eth Signer_, or -signing an invalid/malicious Ethereum transaction with the Ethereum key held by its _Eth Signer_. If all conditions of misbehavior can -be attributed to a signature from one of these sets, and proven **on the Cosmos chain**, then we can argue that Gravity offers -a security level equal to the minimum of the Peg-Zone Validator Set, or reorganizing the Ethereum Chain 50 blocks. -And provide a security equivalent to or greater than IBC. - -## Bootstrapping - -We assume the act of upgrading the Cosmos-based binary to have gravity module is already complete, -as approaches to that are discussed in many other places. Here we focus on the _activation_ step. - -1. Each `Operator` generates an Ethereum and Cosmos private key for their `EthSigner`. These addresses are signed and submitted by the Operators valoper key in a MsgRegisterEthSigner. The `EthSigner` is now free to use these delegated keys for all Gravity messages. -1. A governance vote is held on bridge parameters including `Gravity ID`, `Allowed validator set delta`, `start threshold`, and `Gravity contract code hash` -1. Anyone deploys a Gravity contract using a known codehash and the current validator set of the Cosmos zone to an Ethereum compatible blockchain. -1. Each `Operator` may or may not configure their `Eth Signer` with the above Gravity contract address -1. If configured with an address the `Eth Signer` checks the provided address. If the contract passes validation the `Eth Signer` signs and submits a MsgProposeGravityContract. Validation is defined as finding the correct `Gravity contract code hash` and a validator set matching the current set within `Allowed validator set delta`. -1. A contract address is considered adopted when voting power exceeding the `start threshold` has sent a MsgProposeGravityContract with the same Ethereum address. -1. Because validator sets change quickly, `Eth Signers` not configured with a contract address observe the Cosmos blockchain for submissions. When an address is submitted they validate it and approve it themselves if it passes. This results in a workflow where once a valid contract is proposed it will be ratified in a matter of a few seconds. -1. It is possible for the adoption process to fail if a race condition is intentionally created resulting in less than 66% of the validator power approving more than one valid Gravity Ethereum contract. In this case the Orchestrator will check the contract address with the majority of the power (or at random in the case of a perfect tie) and switch it's vote. This leaves only the possible edge case of >33% of `Operators` intentionally selecting a different contract address. This would be a consensus failure and the bridge can not progress. -1. The bridge ratification process is complete, the contract address is now placed in the store to be referenced and other operations are allowed to move forward. - -At this point, we know we have a contract on Ethereum with the proper _MultiSig Set_, that > `start threshold` of the _Orchestrator Set_ is online and agrees with this contract, and that the Cosmos chain has stored this contract address. Only then can we begin to accept transactions to transfer tokens - -Note: `start threshold` is some security factor for bootstrapping. 67% is sufficient to release, but we don't want to start until there is a margin of error online (not to fall off with a small change of voting power). This may be 70, 80, 90, or even 95% depending on how much assurances we want that all _Orchestrators_ are operational before starting. - -## ETH to Cosmos Oracle - -All `Operators` run an `Oracle` binary. This separate process monitors an Ethereum node for new events involving the `Gravity Contract` on the Ethereum chain. Every event that `Oracle` monitors has an event nonce. This nonce is a unique coordinating value for a `Claim`. Since every event that may need to be observed by the `Oracle` has a unique event nonce `Claims` can always refer to a unique event by specifying the event nonce. - -- An `Oracle` observes an event on the Ethereum chain, it packages this event into a `Claim` and submits this claim to the cosmos chain -- Within the Gravity Cosmos module this `Claim` either creates or is added to an existing `Attestation` that matches the details of the `Claim` once more than 66% of the active `Validator` set has made a `Claim` that matches the given `Attestation` the `Attestation` is executed. This may mint tokens, burn tokens, or whatever is appropriate for this particular event. -- In the event that the validators can not agree >66% on a single `Attestation` the oracle is halted. This means no new events will be relayed from Ethereum until some of the validators change their votes. There is no slashing condition for this, because having one would risk the liveness of the chain itself if there was an expected Ethereum fork. - -## Relaying Cosmos to ETH - -- A user sends a MsgSendToEth when they want to transfer tokens across to Ethereum. This debits the tokens from their account, and places a transaction in the `Gravity Tx Pool` -- Someone (permissionlessly) sends a MsgRequestBatch, this produces a new `Transaction batch` in the `Gravity Batch pool`. The creation of this batch occurs in CosmosSDK and is entirely deterministic, and should create the most profitable batch possible out of transactions in the `Gravity Tx Pool`. - - The `TransactionBatch` includes a batch nonce. - - It also includes the latest `Valset` - - The transactions in this batch are removed from the `Gravity Tx Pool`, and cannot be included in a new batch. -- Batches in the `Gravity Batch Pool` are signed over by the `Validator Set`'s `Eth Signers`. - - `Relayers` may now attempt to submit these batches to the Gravity contract. If a batch has enough signatures (2/3+1 of the `Multisig Set`), it's submission will succeed. The decision whether or not to attempt a batch submission is entirely up to a given `Relayer`. -- Once a batch is `Observed` to have been successfully submitted to Ethereum (this takes at least as long as the `EthBlockDelay`), any batches in the `Gravity Batch Pool` which have a lower nonce, and have not yet been successfully submitted have their transactions returned to the `Gravity Tx Pool` to be tried in a new batch. This is safe because we know that these batches cannot possibly be submitted any more since their nonces are too low. - -- When a new MsgRequestBatch comes in a new batch will not be produced unless it is more profitable than any batch currently in the `Gravity Batch Pool`. This means that when there is a batch backlog batches _must_ become progressively more profitable to submit. +Slashing is documented in the [slashing spec](/spec/slashing-spec.md) diff --git a/docs/design/parameters.md b/docs/design/parameters.md new file mode 100644 index 000000000..a47d942e3 --- /dev/null +++ b/docs/design/parameters.md @@ -0,0 +1,81 @@ +# Gravity parameters + +This document describes and advises chain operators on configuring Gravity's parameters +the default parameters can be found in [genesis.go](/module/x/gravity/keeper/genesis.go) + +## gravity_id + +a random 32 byte value to prevent signature reuse, for example if the +cosmos validators decided to use the same Ethereum keys for another chain +also running Gravity we would not want it to be possible to play a deposit +from chain A back on chain B's Gravity. This value IS USED ON ETHEREUM so +it must be set in your genesis.json before launch and not changed after +deploying Gravity. Changing this value after deploying Gravity will result +in the bridge being non-functional. To recover just set it back to the original +value the contract was deployed with. + +## contract_hash + +the code hash of a known good version of the Gravity contract +solidity code. This can be used to verify the correct version +of the contract has been deployed. This is a reference value for +governance action only it is never read by any Gravity code + +## bridge_ethereum_address + +is address of the bridge contract on the Ethereum side, this is a +reference value for governance only and is not actually used by any +Gravity code. + +In the future the relayer may attempt to use this value rather than require +the user to set this value themselves in the settings. + +## bridge_chain_id + +the unique identifier of the Ethereum chain, this is a reference value +only and is not actually used by any Gravity code + +These reference values may be used by future Gravity client implementations +to allow for consistency checks. + +## Signing windows + +signed_valsets_window +signed_batches_window +signed_claims_window + +These values represent the time in blocks that a validator has to submit +a signature for a batch or valset, or to submit a claim for a particular +attestation nonce. + +In the case of attestations this clock starts when the +attestation is created, but only allows for slashing once the event has passed. +Note that that claims slashing is not currently enabled see [slashing spec](/spec/slashing-spec.md) + +## target_batch_timeout + +This is the 'target' value for when batches time out, this is a target because +Ethereum is a probabilistic chain and you can't say for sure what the block +frequency is ahead of time. + +## Ethereum timing + +average_block_time +average_ethereum_block_time + +These values are the average Cosmos block time and Ethereum block time respectively +and they are used to compute what the target batch timeout is. It is important that +governance updates these in case of any major, prolonged change in the time it takes +to produce a block + +## Slash fractions + +slash_fraction_valset +slash_fraction_batch +slash_fraction_claim +slash_fraction_conflicting_claim + +The slashing fractions for the various gravity related slashing conditions. The first three +refer to not submitting a particular message, the third for failing to submit a claim and the last for submitting a different claim than other validators. + +Note that claim slashing is currently disabled as outlined in the [slashing spec](/spec/slashing-spec.md) diff --git a/docs/design/relaying-semantics.md b/docs/design/relaying-semantics.md index 7ca33d80d..03cbd37f3 100644 --- a/docs/design/relaying-semantics.md +++ b/docs/design/relaying-semantics.md @@ -2,7 +2,7 @@ This document is designed to assist developers in implementing alternate Gravity relayers. The two major components of the Orchestrator which interact with Ethereum. The Gravity bridge has been designed for increased efficiency, not for ease of use. This means there are many implicit requirements of these external binaries which this document does it's best to make explicit. -The Gravity `orchestrator` is described in [overview.md](overview.md) it's a combination of three distinct roles that need to be performed by external binaries in the Gravity bridge. This document highlights the requirements of the `relayer` which is one of those roles included in the `orchestrator`. +The Gravity `orchestrator` is described in [overview.md](/docs/design/overview.md) it's a combination of three distinct roles that need to be performed by external binaries in the Gravity bridge. This document highlights the requirements of the `relayer` which is one of those roles included in the `orchestrator`. ## Semantics for Validator set update relaying @@ -12,7 +12,7 @@ When updating the validator set in the Gravity contract you must provide a copy Providing the old validator set is part of a storage optimization, instead of storing the entire validator set in Ethereum storage it is instead provided by each caller and stored in the much cheaper Ethereum event queue. No sorting of any kind is performed in the Gravity contract, meaning the list of validators and their new signatures must be submitted in exactly the same order as the last call. -For the purpose of normal operation this requirement can be shortened to 'sort the validators by descending power, and by Eth address bytes where power is equal'. Since the Cosmos module produces the validator sets they should always come in order. But a flaw in this sorting method that caused an unsorted validator set to make it's way into the chain would halt valset updates and essentially decouple the bridge unless your implementation is smart enough to take a look at the last submitted order rather than blindly following sorting. +For the purpose of normal operation this requirement can be shortened to 'sort the validators by descending power, and by Eth address bytes where power is equal'. Since the Cosmos module produces the validator sets they should always come in order. It is not possible for the relayer to change this order since it is part of the signature. But a change in this sorting method on the Gravity module side would halt valset updates and essentially decouple the bridge unless your implementation is smart enough to take a look at the last submitted order rather than blindly following sorting. ### Deciding what Validator set to relay diff --git a/module/proto/gravity/v1/genesis.proto b/module/proto/gravity/v1/genesis.proto index 44e8540d4..3b7c3963e 100644 --- a/module/proto/gravity/v1/genesis.proto +++ b/module/proto/gravity/v1/genesis.proto @@ -17,55 +17,55 @@ option go_package = "github.com/cosmos/gravity-bridge/module/x/gravity/types"; // from chain A back on chain B's Gravity. This value IS USED ON ETHEREUM so // it must be set in your genesis.json before launch and not changed after // deploying Gravity -// + // contract_hash: // the code hash of a known good version of the Gravity contract // solidity code. This can be used to verify the correct version // of the contract has been deployed. This is a reference value for // goernance action only it is never read by any Gravity code -// + // bridge_ethereum_address: // is address of the bridge contract on the Ethereum side, this is a // reference value for governance only and is not actually used by any // Gravity code -// + // bridge_chain_id: // the unique identifier of the Ethereum chain, this is a reference value // only and is not actually used by any Gravity code -// + // These reference values may be used by future Gravity client implemetnations // to allow for saftey features or convenience features like the Gravity address // in your relayer. A relayer would require a configured Gravity address if // governance had not set the address on the chain it was relaying for. -// + // signed_valsets_window // signed_batches_window // signed_claims_window -// + // These values represent the time in blocks that a validator has to submit // a signature for a batch or valset, or to submit a claim for a particular // attestation nonce. In the case of attestations this clock starts when the // attestation is created, but only allows for slashing once the event has passed -// + // target_batch_timeout: -// + // This is the 'target' value for when batches time out, this is a target becuase // Ethereum is a probabalistic chain and you can't say for sure what the block // frequency is ahead of time. -// + // average_block_time // average_ethereum_block_time -// + // These values are the average Cosmos block time and Ethereum block time repsectively -// and they are used to copute what the target batch timeout is. It is important that +// and they are used to compute what the target batch timeout is. It is important that // governance updates these in case of any major, prolonged change in the time it takes // to produce a block -// + // slash_fraction_valset // slash_fraction_batch // slash_fraction_claim // slash_fraction_conflicting_claim -// + // The slashing fractions for the various gravity related slashing conditions. The first three // refer to not submitting a particular message, the third for submitting a different claim // for the same Ethereum event diff --git a/notes.md b/notes.md deleted file mode 100644 index 7ce02b3e6..000000000 --- a/notes.md +++ /dev/null @@ -1,123 +0,0 @@ -# Installing Gravity on a Cosmos chain - -## Installing Gravity on an unstarted chain - -0. The deployed contract address is stored in the gentx's that validators generate - - Validators generate an Ethereum keypair and submit it as part of their gentx - - Validators also sign over the gentx validator state with their ethereum keypair -1. Once Gentx signing is complete the Ethereum signatures are collected and used to submit a valset update to the already deployed Ethereum contract -2. The chain starts, the validators all observe the Ethereum contract state and find that it matches their current validator state, proceed with updates as normal - -## Installing Gravity on a live Cosmos chain - -0. There is a governance resolution accepting the gravity code into the full node codebase - - Once gravity starts running on a validator, it generates an Ethereum keypair. - - We may get this from config temporarily - - Gravity publishes a validator's Ethereum address every single block. - - This is most likely just going to mean putting it in the gravity keeper, but maybe there needs to be some kind of greater tie in with the rest of the validator set information - - see staking/keeper/keeper.go for an example of getting individual and all validators - - A gravityId is chosen at this step. - - This may be hardcoded for now - - The source code hash of the gravity Ethereum contract is saved here. - - This may be hardcoded as well - - At some later step, we will need to check that all validators have their eth address in there -1. There is a governance resolution that says "we are going to start gravity at block x" - - This is a parameter-changing resolution that the gravity module looks for -1. Right after block x, the gravity module looks at the validator set at block x, and signs over it using its Ethereum keypair. -1. Gravity puts the Ethereum signature from the last step into the consensus state. As part of consensus, the validators check that each of these signatures is valid. - - The Eth signatures over the Eth addresses of the validator set from the last block are now required in every block going forward. -1. The deployer script hits a full node api, gets the Eth signatures of the valset from the latest block, and deploys the Ethereum contract. -1. The deployer submits the address of the gravity contract that it deployed to Ethereum. - - We will consider the scenario that many deployers deploy many valid gravity eth contracts. - - The gravity module checks the Ethereum chain for each submitted address, and makes sure that the gravity contract at that address is using the correct source code, and has the correct validator set. -1. There is a rule in the gravity module that the correct gravity eth contract address with the lowest address in the earliest block that is at least n blocks back is the "official" contract. After n blocks passes, this allows anyone wanting to use gravity to know which ethereum contract to send their money to. - -# Creating messages for the Ethereum contract - -## Valset Process - -- Gravity Daemon on each val submits a "MsgSetEthAddress" with an eth address and its signature over their Cosmos address -- This validates the signature and adds the Eth addresss to the store under the EthAddressKey prefix. -- Somebody submits a "MsgValsetRequest". -- The valset from the current block goes into the store under the ValsetRequestKey prefix - - The valset's nonce is set as the current blockheight - - The valset is stored using the nonce/blockheight as the key -- When the gravity daemons see a valset in the store, they sign over it with their eth key, and submit a MsgValsetConfirm. This goes into the store, after validation. - - Gravity daemons sign every valset that shows up in the store automatically, since they implicitly endorse it by having participated in the consensus which put it in the store. - - The valset confirm is stored using the nonce as the key, like the valset request -- Once 66% of the gravity daemons have submitted signatures for a particular valset, a relayer can submit the valset, by accessing the valset and the signatures from the store. Maybe we will make a method to do this easily. - -## TX Batch process - -- User submits Cosmos TX with requested Eth TX "EthTx" -- This goes into everyone's stores by consensus - -- --> Gravity module sorts TXs into batches, and puts the batches into the "BatchStore", and all Eth TXs in a batch are removed from the mempool. - -- Gravity Daemon on each validator sees all batches in the BatchStore, signs over the batches, sends a "BatchConfirmTx" containing all eth signatures for all the batches. -- The BatchConfirmTx goes into a BatchConfirmStore, now the relayer can relay the batch once there's 66% - -- Now the batch is processed by the Eth contract. -- The Gravity Daemons on the validators observe this, and they submit a "BatchSubmittedTx". This TX goes into a Batch SubmittedStore. The cosmos state machine discards the batch permanently once it sees that over 66% of the validators have submitted a BatchSubmittedTx. - - If there are any older batches in the BatchConfirmStore, they are removed because they can now never be submitted. The Eth Tx's in the old batches are released back into the mempool. - -## Deposit oracle process - -- Gravity Daemons constantly observe the Ethereum blockchain. Specifically the Gravity Ethereum contract -- When a deposit is observed each validator sends a DepositTX after 50 blocks have elapsed (to resolve forks) -- When more than 66% of the validator shave signed off on a DepositTX the message handler itself calls out to the bank and generates tokens - -# CosmosSDK / Tendermint considerations - -## Signing - -In order to update the validator state on the Gravity Ethereum contract we need to perform probably the simplest 'off chain work' possible. Signing the current validator state with an Ethereum key and submitting that as a message -so that a relayer may observe and ferry the signed 'ValSetUpdate' message over to Ethereum. - -The concept of 'validators signing some known value' is very core to Tendermint and of course any proof of stake system. So when it's presented as a step in any Gravity process no one bats an eye. But we're not coding Gravity as a Tendermint extension, it's a CosmosSDK module. - -CosmosSDK modules don't have access to validator private keys or a signing context to work with. In order to get around this we perform the signing in a separate codebase that interacts with the main module. Typically this would be called a 'relayer' but since we're writing a module where the validators specifically must perform actions with their own private keys it may be better to term this as a 'validator external signer' or something along those lines. - -The need for an external signer doubles the number of states required to produce a working Gravity CosmosSDK module state machine. For example the ValSetUpdate message generation process requires a trigger message, this goes into a store where the external signers observe it and submit their own signatures. This 'waiting for sigs' state could be eliminated if signing the state update could be processed as part of the trigger message handler itself. - -This obviously isn't a show stopper, but if it's easy _and_ maintainable we should consider using ABCI to do this at the Tendermint level. - -## Gravity Consensus - -Performing our signing at the CosmosSDK level rather than the Tendermint level has other implications. Mainly it changes the nature of the slashing and halting conditions. At the Tendermint level if signing the ValSetUpdate was part of processing the message failing to do so would result in downtime for that validator on that block. On the other hand submitting a ValSetUpdate signature in a CosmosSDK module is just another message, having no consensus impact other than slashing conditions we may add. Since slashing conditions are slow this produces the following potential vulnerability. - -If a validator failing to produce ValSetUpdates and the process is implemented in Tendermint they are simply racking up downtime and have no capabilities as a validator. But if the process is implemented at the CosmosSDK level they will continue to operate normally as a validator. - -My intuition about vulnerabilities here is that they could only be used to halt the bridge using 1/3rd of the stake. Since that's roughly the same as halting the chain using 1/3rd of the active stake I don't think it's an issue. -Ethereum event feed - -- There is a governance parameter called EthBlockDelay, for example 50 blocks -- Gravity Daemons get the current block number from their Geth, then get the events from the block EthBlockDelay lower than the current one -- They send an EthBlockData message -- These messages go in an EthBlockDataStore, indexed by the block number and the validator that sent them. -- Once there is a version of the block data that matches from at least 66% of the validators, it is considered legit -- Once a block goes over 66% (and all previous blocks are also over 66%), tokens are minted as a result of EthToCosmos transfers in that block. -- (optional downtime slashing???) Something watches for validators that have not submitted matching block data, and triggers a downtime slashing - -Alternate experimental ethereum input - -- Let's say that accounts have to send a ClaimTokens message to get their tokens that have been transferred over from Eth (just for sake of argument) - -- When a ClaimTokens message comes in, each validator in the state machine, checks it's own eth block DB (this is seperate from the Cosmos KV stores, and is access only by the gravity module. The gravity daemon fills it up with block data from a different process) to see if the tokens have been transferred to that account. -- Validators with a different opinion on the state of Eth will arrive at different conclusions, and produce different blocks. Validators that disagree will have downtime, according to Tendermint. This allows Tendermint to handle all consensus, and we don't think about it. - -Ethereum to Cosmos transfers - -- Function in contract takes a destination Cosmos address and transfer amount -- Does the transfer and logs a EthToCosmosTransfer event with the amount and destination - -Alternate batch assembly by validators - -- Allowing anyone to request batches as we have envisioned previously opens up an attack vector where someone assembles unprofitable batches to stop the bridge. -- Instead, why not just have the validators assemble batches? -- In the cosmos state machine, they look at all transactions, sort them from lowest to highest fee, and chop that list into batches. -- Now relayers can try to submit the batches. -- Batches are submitted to Eth, and transactions build up in the pool, in parallel. -- At some point the validators make new batches sorted in the same way. -- Relayers may choose to submit new batches which invalidate older low fee batches. diff --git a/readme.md b/readme.md index 44abfeacc..d681024ae 100644 --- a/readme.md +++ b/readme.md @@ -2,9 +2,39 @@ Gravity bridge is Cosmos <-> Ethereum bridge designed to run on the [Cosmos Hub](https://github.com/cosmos/gaia) focused on maximum design simplicity and efficiency. -Gravity is currently can transfer ERC20 assets originating on Ethereum to a Cosmos based chain and back to Ethereum. +Gravity is currently can transfer ERC20 assets originating on Cosmos or Ethereum to and from Ethereum. -The ability to transfer assets originating on Cosmos to an ERC20 representation on Ethereum is coming within a few months. +## Documentation + +### Design docs + +[design overview](/docs/design/overview.md) + +[Bootstrapping the bridge](/docs/design/bootstrapping.md) + +[Minting and locking tokens in Gravity](/docs/design/mint-lock.md) + +[Oracle design](/docs/design/oracle.md) + +[Ethereum signing](/docs/design/ethereum-signing.md) + +[Messages](/docs/design/messages.md) + +[Parameters](/docs/design/parameters.md) + +[Incentives](/docs/design/incentives.md) + +[arbitrary logic](/docs/design/arbitrary-logic.md) + +[relaying semantics](/docs/design/relaying-semantics.md) + +### Specs + +[slashing-spec](/spec/slashing-spec.md) + +[batch-creation-spec](/spec/batch-creation-spec.md) + +[valset-creation-spec](/spec/valset-creation-spec.md) ## Status @@ -19,7 +49,7 @@ You can keep up with the latest development by watching our [public standups](ht - [x] Tested with 100+ validators - [x] Unit tests for every throw condition - [x] Audit for assets originating on Ethereum - - [ ] Support for issuing Cosmos assets on Ethereum + - [x] Support for issuing Cosmos assets on Ethereum - Cosmos Module - [x] Basic validator set syncing - [x] Basic transaction batch generation @@ -30,8 +60,8 @@ You can keep up with the latest development by watching our [public standups](ht - [x] Validator set syncing edge cases - [x] Slashing - [x] Relaying edge cases - - [ ] Transaction batch edge cases - - [ ] Support for issuing Cosmos assets on Ethereum + - [x] Transaction batch edge cases + - [x] Support for issuing Cosmos assets on Ethereum - [ ] Audit - Orchestrator / Relayer - [x] Validator set update relaying diff --git a/spec/batch-creation-spec.md b/spec/batch-creation-spec.md index bfc12d91a..a309e9317 100644 --- a/spec/batch-creation-spec.md +++ b/spec/batch-creation-spec.md @@ -1,6 +1,6 @@ ## Transaction batch creation -Deposits (Ethereum > Cosmos transfers) happen as single operations. Each deposit creates a single oracle event that is voted on see [the deposit spce](deposit-spec.md). Withdraws are more complicated, since Ethereum gas is very expensive we want to spread out the cost of verifying the validator signatures across as many transactions as possible. Hence batches. +Deposits (Ethereum > Cosmos transfers) happen as single operations. Each deposit creates a single oracle event that is voted on see [the deposit spec](deposit-spec.md). Withdraws are more complicated, since Ethereum gas is very expensive we want to spread out the cost of verifying the validator signatures across as many transactions as possible. Hence batches. When a user calls MsgSendToEth they lock up some tokens and some fee value into the 'Gravity tx pool' which is a pool of transactions waiting to enter batches. diff --git a/spec/slashing-spec.md b/spec/slashing-spec.md index b18e7ce1b..f45720ebb 100644 --- a/spec/slashing-spec.md +++ b/spec/slashing-spec.md @@ -8,16 +8,29 @@ This slashing condition is intended to stop validators from signing over a valid The trickiest part of this slashing condition is determining that a validator set has never existed on Cosmos. To save space, we will need to clean up old validator sets. We could keep a mapping of validator set hash to true in the KV store, and use that to check if a validator set has ever existed. This is more efficient than storing the whole validator set, but its growth is still unbounded. It might be possible to use other cryptographic methods to cut down on the size of this mapping. It might be OK to prune very old entries from this mapping, but any pruning reduces the deterrence of this slashing condition. -## GRAVSLASH-02: Failure to sign validator set update or tx batch +Currently this is implemented as an ever growing array of hashes in state. -This slashing condition is triggered when a validator does not sign a validator set update or transaction batch which is produced by the Gravity Cosmos module. This prevents two bad scenarios- +## GRAVSLASH-02: Failure to sign tx batch, or arbitrary logic call + +This slashing condition is triggered when a validator does not sign a transaction batch or arbitrary logic call which is produced by the Gravity Cosmos module. This prevents two bad scenarios- + +1. A validator simply does not bother to keep the correct binaries running on their system, +2. A cartel of >1/3 validators unbond and then refuse to sign updates, preventing any batches or logic calls from getting enough signatures to be submitted to the Gravity Ethereum contract. + +## GRAVSLASH-03: Failure to sign validator set update + +This slashing condition is triggered when a validator does not sign a validator set update or transaction batch which is produced by the Gravity Cosmos module. This prevents two bad scenarios- 1. A validator simply does not bother to keep the correct binaries running on their system, -2. A cartel of >1/3 validators unbond and then refuse to sign updates, preventing any validator set updates from getting enough signatures to be submitted to the Gravity Ethereum contract. If they prevent validator set updates for longer than the Cosmos unbonding period, they can no longer be punished for submitting fake validator set updates and tx batches (GRAVSLASH-01 and GRAVSLASH-02). +2. A cartel of >1/3 validators unbond and then refuse to sign updates, preventing any validator set updates from getting enough signatures to be submitted to the Gravity Ethereum contract. If they prevent validator set updates for longer than the Cosmos unbonding period, they can no longer be punished for submitting fake validator set updates and tx batches (GRAVSLASH-01 and GRAVSLASH-03). + +To deal with scenario 2, GRAVSLASH-03 will also need to slash validators who are no longer validating, but are still in the unbonding period for up to `UnbondSlashingValsetsWindow` blocks. This means that when a validator leaves the validator set, they will need to keep running their equipment for at least `UnbondSlashingValsetsWindow` blocks. This is unusual for a Cosmos chain, and may not be accepted by the validators. -To deal with scenario 2, GRAVSLASH-02 will also need to slash validators who are no longer validating, but are still in the unbonding period. This means that when a validator leaves the validator set, they will need to keep running their equipment for 2 weeks. This is unusual for a Cosmos chain, and may not be accepted by the validators. Research is ongoing for ways to allow validators to stop signing before the unbonding period is fully over. +The current value of `UnbondSlashingValsetsWindow` is 10,000 blocks, or about 12-14 hours. We have determined this to be a safe value based on the following logic. So long as every validator leaving hte validator set signs at least one validator set update that they are not contained in then it is guaranteed to be possible for a relayer to produce a chain of validator set updates to transform the current state on the chain into the present state. -## GRAVSLASH-03: Submitting incorrect Eth oracle claim - INTENTIONALLY NOT IMPLEMENTED +It should be noted that both GRAVSLASH-02 and GRAVSLASH-03 could be eliminated with no loss of security if it where possible to perform the Ethereum signatures inside the consensus code. This is a pretty limited feature addition to Tendermint that would make Gravity far less prone to slashing. + +## GRAVSLASH-04: Submitting incorrect Eth oracle claim - INTENTIONALLY NOT IMPLEMENTED The Ethereum oracle code (currently mostly contained in attestation.go), is a key part of Gravity. It allows the Gravity module to have knowledge of events that have occurred on Ethereum, such as deposits and executed batches. GRAVSLASH-03 is intended to punish validators who submit a claim for an event that never happened on Ethereum. @@ -29,18 +42,20 @@ Although well-intentioned, this slashing condition is likely not advisable for m Maybe GRAVSLASH-03 is not necessary at all: -The real utility of this slashing condition is to make it so that, if >2/3 of the validators form a cartel to all submit a fake event at a certain nonce, some number of them can defect from the cartel and submit the real event at that nonce. If there are enough defecting cartel members that the real event becomes observed, then the remaining cartel members will be slashed by this condition. However, this would require >1/2 of the cartel members to defect in most conditions. +The real utility of this slashing condition is to make it so that, if >2/3 of the validators form a cartel to all submit a fake event at a certain nonce, some number of them can defect from the cartel and submit the real event at that nonce. If there are enough defecting cartel members that the real event becomes observed, then the remaining cartel members will be slashed by this condition. However, this would require >1/2 of the cartel members to defect in most conditions. -If not enough of the cartel defects, then neither event will be observed, and the Ethereum oracle will just halt. This is a much more likely scenario than one in which GRAVSLASH-03 is actually triggered. +If not enough of the cartel defects, then neither event will be observed, and the Ethereum oracle will just halt. This is a much more likely scenario than one in which GRAVSLASH-04 is actually triggered. -Also, GRAVSLASH-03 will be triggered against the honest validators in the case of a successful cartel. This could act to make it easier for a forming cartel to threaten validators who do not want to join. +Also, GRAVSLASH-04 will be triggered against the honest validators in the case of a successful cartel. This could act to make it easier for a forming cartel to threaten validators who do not want to join. -## GRAVSLASH-04: Failure to submit Eth oracle claims +## GRAVSLASH-05: Failure to submit Eth oracle claims - INTENTIONALLY NOT IMPLEMENTED -This is similar to GRAVSLASH-03, but it is triggered against validators who do not submit an oracle claim that has been observed. In contrast to GRAVSLASH-03, GRAVSLASH-04 is intended to punish validators who stop participating in the oracle completely. +This is similar to GRAVSLASH-04, but it is triggered against validators who do not submit an oracle claim that has been observed. In contrast to GRAVSLASH-04, GRAVSLASH-05 is intended to punish validators who stop participating in the oracle completely. **Implementation considerations** -Unfortunately, GRAVSLASH-04 has the same downsides as GRAVSLASH-03 in that it ties the correct operation of the Cosmos chain to the Ethereum chain. Also, it likely does not incentivize much in the way of correct behavior. To avoid triggering GRAVSLASH-04, a validator simply needs to copy claims which are close to becoming observed. This copying of claims could be prevented by a commit-reveal scheme, but it would still be easy for a "lazy validator" to simply use a public Ethereum full node or block explorer, with similar effects on security. Therefore, the real usefulness of GRAVSLASH-04 is likely minimal +Unfortunately, GRAVSLASH-05 has the same downsides as GRAVSLASH-04 in that it ties the correct operation of the Cosmos chain to the Ethereum chain. Also, it likely does not incentivize much in the way of correct behavior. To avoid triggering GRAVSLASH-05, a validator simply needs to copy claims which are close to becoming observed. This copying of claims could be prevented by a commit-reveal scheme, but it would still be easy for a "lazy validator" to simply use a public Ethereum full node or block explorer, with similar effects on security. Therefore, the real usefulness of GRAVSLASH-04 is likely minimal + +GRAVSLASH-05 also introduces significant risks. Mostly around forks on the Ethereum chain. For example recently OpenEthereum failed to properly handle the Berlin hardfork, the resulting node 'failure' was totally undetectable to automated tools. It didn't crash so there was no restart to perform, blocks where still being produced although extremely slowly. If this had occurred while Gravity was running with GRAVSLASH-05 active it would have caused those validators to be removed from the set. Possibly resulting in a very chaotic moment for the chain as dozens of validators where removed for little to no fault of their own. -Without GRAVSLASH-03 and GRAVSLASH-04, the Ethereum event oracle only continues to function if >2/3 of the validators voluntarily submit correct claims. Although the arguments against GRAVSLASH-03 and GRAVSLASH-04 are convincing, we must decide whether we are comfortable with this fact. We should probably make it possible to enable or disable GRAVSLASH-03 and GRAVSLASH-04 in the chain's parameters. \ No newline at end of file +Without GRAVSLASH-04 and GRAVSLASH-05, the Ethereum event oracle only continues to function if >2/3 of the validators voluntarily submit correct claims. Although the arguments against GRAVSLASH-04 and GRAVSLASH-05 are convincing, we must decide whether we are comfortable with this fact. Alternatively we must be comfortable with the Cosmos chain potentially halting entirely due to Ethereum generated factors. We should probably make it possible to enable or disable GRAVSLASH-04 and GRAVSLASH-05 in the chain's parameters. diff --git a/spec/valset-creation-spec.md b/spec/valset-creation-spec.md index fe7c9f7a8..adcec436e 100644 --- a/spec/valset-creation-spec.md +++ b/spec/valset-creation-spec.md @@ -1,15 +1,21 @@ ## Validator set creation -In Gravity when we talk about a `valset` we mean a `validator set update` which is a series of ethereum addresses with attached normalized powers used to represent the Cosmos validator set in the Gravity Ethereum contract. Since the Cosmos validator set can and will change frequently. +In Gravity when we talk about a `valset` we mean a `validator set update` which is a series of ethereum addresses with attached normalized powers used to represent the Cosmos validator set in the Gravity Ethereum contract. Since the Cosmos validator set can and will change frequently. Validator set creation is a critical part of the Gravity system. The goal is to produce and sign enough validator sets that no matter which one is in the Ethereum contract there is an unbroken chain of correctly signed state updates (greater than 66% of the previous voting power) to sync the Ethereum contract with the current Cosmos validator set. -The key to understanding valset creation is to understand that it is *absolutely impossible* for either side be fully synced with the other. The Cosmos chain has finality, but produces blocks so much faster than Ethereum that the validator set could change completely 6 times over between Ethereum blocks. In the other direction Ethereum does not have finality, so there is a significant block delay before the Cosmos chain can know what occurred on Ethereum. It's because of these fundamental restrictions that we focus on continuity of produced validator sets rather than determining what the 'last state on Ethereum' is. +The key to understanding valset creation is to understand that it is _absolutely impossible_ for either side be fully synced with the other. The Cosmos chain has finality, but produces blocks so much faster than Ethereum that the validator set could change completely an arbitrary number of times between Ethereum blocks. In the other direction Ethereum does not have finality, so there is a significant block delay before the Cosmos chain can know what occurred on Ethereum. It's because of these fundamental restrictions that we focus on continuity of produced validator sets rather than determining what the 'last state on Ethereum' is. + +We generate a validator set update for a given percentage of power change. Note that power change is computed in a normalized fashion, whereas Cosmos power exits relative to some changing total power value. So for example if the total power on Cosmos increased 10% due purely to inflation the power in the Gravity bridge contract would not change at all, as all validators would inflate equally barring slashing or some other event. + +Currently a 5% power change threshold has been selected somewhat arbitrarily. A survey of power on the hub says that a power change of less than 1% a week is common, but as a general number for all Cosmos zones it may be a little too conservative. This should probably be broken out into a parameter and changed as required by the active validator set. + +The main consideration when setting this parameter is that your security is reduced, instead of requiring 66% of validators to execute a message on Ethereum, you may need up to 66% + power change percentage of the current active validator set. Of course the ideal case is to generate validator sets on every power change of any kind, but this is infeasible both from a signature submission perspective (submitting hundreds of messages per block to handle signatures is infeasible) but also infeasible from a cost standpoint. ### When are validator sets created 1. If there are no valset requests, create a new one 2. If there is at least one validator who started unbonding in current block. (we persist last unbonded block height in hooks.go) - This will make sure the unbonding validator has to provide an attestation to a new Valset - that excludes him before he completely Unbonds. Otherwise he will be slashed -3. If power change between validators of CurrentValset and latest valset request is > 5% \ No newline at end of file + This will make sure the unbonding validator has to provide an attestation to a new Valset + that excludes him before he completely Unbonds. Otherwise he will be slashed +3. If power change between validators of CurrentValset and latest valset request is > 5%