mirror of
https://github.com/status-im/EIPs.git
synced 2025-01-27 07:05:47 +00:00
Automatically merged updates to draft EIP(s) 1613
Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing
This commit is contained in:
parent
90eecfe868
commit
f15cd4a294
@ -1,7 +1,7 @@
|
||||
---
|
||||
eip: 1613
|
||||
title: Gas stations network
|
||||
author: Yoav Weiss <yoav@tabookey.com>, Dror Tirosh <dror@tabookey.com>
|
||||
author: Yoav Weiss <yoav@tabookey.com>, Dror Tirosh <dror@tabookey.com>, Alex Forshtat <alex@tabookey.com>
|
||||
discussions-to: https://github.com/yoav-tabookey/EIPs/issues/1
|
||||
status: Draft
|
||||
type: Standards Track
|
||||
@ -58,7 +58,6 @@ Roles of a `Relay` node:
|
||||
* Maintain a hot wallet with a small amount of ETH, to pay for gas.
|
||||
* Provide a public interface for user apps to send gasless transactions via channels such as https or whisper.
|
||||
* Publish it's public interfaces and its price (as a multiplier of the actual transaction gas cost) in `RelayHub`.
|
||||
* Help `RelayHub` maintain the list of relays in a trustless way. Relays are incentivized to remove other verifiably-stale relays.
|
||||
* Optionally monitor reverted transactions of other relays through RelayHub, catching offending relays and claiming their stakes. This can be done by anyone, not just a relay.
|
||||
|
||||
Implementing a `RelayRecipient` contract:
|
||||
@ -96,19 +95,14 @@ The process of registering/refreshing a `Relay`:
|
||||
* If starting for the first time (no key yet), generate a key pair for Relay's address.
|
||||
* If Relay's address doesn't hold sufficient funds for gas (e.g. because it was just generated), Relay stays inactive until its owner funds it.
|
||||
* Relay's owner funds it.
|
||||
* Relay sends the required stake to `RelayHub`.
|
||||
* Relay calls `RelayHub.register_relay(address owner, uint transaction_fee, string[] url, address optional_stale_relay_for_removal)`, with its `owner` (the address that funded it),
|
||||
the relay's `transaction fee` (as a multiplier on transaction gas cost), and one or more URL for incoming transactions.
|
||||
The `optional_stale_relay_for_removal` arg is the address of a stale relay found in the list.
|
||||
* `RelayHub` checks Relay.balance and emits `NeedsFunding(Relay)` to alert the owner if it runs low.
|
||||
* Relay's owner sends the required stake to `RelayHub` by calling `RelayHub.stake(address relay, uint unstake_delay)`.
|
||||
* `RelayHub` puts the `owner` and `unstake delay` in the relays map, indexed by `relay` address.
|
||||
* Relay calls `RelayHub.register_relay(uint transaction_fee, string memory url)` with the relay's `transaction fee` (as a multiplier on transaction gas cost), and a URL for incoming transactions.
|
||||
* `RelayHub` ensures that Relay has a sufficient stake.
|
||||
* `RelayHub` puts the `owner`, current `timestamp`, `transaction fee`, and `urls`, in the relays map, indexed by `relay` address.
|
||||
* `RelayHub` emits an event, `RelayAdded(Relay, transaction_fee, relay_stake, urls)`.
|
||||
* If `optional_stale_relay_for_removal` is in the relays map and is stale (hasn't communicated in a few days), `RelayHub` removes it.
|
||||
Relay benefits by receiving a gas refund for the freed storage, so it's incentivized to always include a stale relay if there is one.
|
||||
* Relay starts a timer to perform a `keepalive` transaction after a certain amount of time if no real transactions are relayed through it.
|
||||
`Relay` is considered stale if it hasn't sent anything to `RelayHub` in a while, e.g. 4 days.
|
||||
* `Relay` goes to sleep and waits signing requests.
|
||||
* `RelayHub` puts the `transaction fee` in the relays map.
|
||||
* `RelayHub` emits an event, `RelayAdded(Relay, owner, transaction_fee, relay_stake, unstake_delay, url)`.
|
||||
* Relay starts a timer to perform a `keepalive` transaction every 6000 blocks.
|
||||
* `Relay` goes to sleep and waits for signing requests.
|
||||
|
||||
The process of sending a relayed transaction:
|
||||
|
||||
@ -120,7 +114,8 @@ The process of sending a relayed transaction:
|
||||
* Sender prepares the transaction with Sender's address, the recipient address, the actual transaction data, Relay's transaction fee, gas price, gas limit, its current nonce from `RelayHub.nonces`, RelayHub's address, and Relay's address, and then signs it.
|
||||
* Sender verifies that `RelayHub.balances[recipient]` holds enough ETH to pay Relay's fee.
|
||||
* Sender verifies that `Relay.balance` has enough eth to send the transaction
|
||||
* Sender sends the signed transaction to Relay's web interface.
|
||||
* Sender reads the Relay's current `nonce` value and decides on the `max_nonce` parameter.
|
||||
* Sender sends the signed transaction amd metadata to Relay's web interface.
|
||||
* `Relay` wraps the transaction with a transaction to `RelayHub`, with zero ETH value.
|
||||
* `Relay` signs the wrapper transaction with its key in order to pay for gas.
|
||||
* `Relay` verifies that:
|
||||
@ -130,12 +125,14 @@ The process of sending a relayed transaction:
|
||||
* The relay address in the transaction matches Relay's address.
|
||||
* The transaction's recipient has enough ETH deposited in `RelayHub` to pay the transaction fee.
|
||||
* Relay has enough ETH to pay for the gas required by the transaction.
|
||||
* Value of `max_nonce` is higher than current Relay's `nonce`
|
||||
* If any of Relay's checks fail, it returns an error to sender, and doesn't proceed.
|
||||
* Relay submits the signed wrapped transaction to the blockchain.
|
||||
* Relay immediately returns the signed wrapped transaction to the sender. This step is discussed below, in attacks/mitigations.
|
||||
* `Sender` receives the wrapped transaction and verifies that:
|
||||
* It's a valid relay call to `RelayHub`. from Relay's address.
|
||||
* The transaction's ethereum nonce matches Relay's current nonce.
|
||||
* The transaction's ethereum nonce is lower than or equal to `max_nonce`.
|
||||
* `Relay` is sufficiently funded to pay for it.
|
||||
* The wrapped transaction is valid and signed by `sender`.
|
||||
* Recipient contract has sufficient funds in `RelayHub.balances` to pay for Relay's fee as stated in the transaction.
|
||||
@ -153,7 +150,6 @@ The process of sending a relayed transaction:
|
||||
* Verifies that the signature of the internal transaction matches its stated origin (sender's key).
|
||||
* Verifies that the relay address written in the transaction matches msg.sender.
|
||||
* Verifies that the transaction's `nonce` matches the stated origin's nonce in `RelayHub.nonces`.
|
||||
* Checks `Relay.balance` and emits `NeedsFunding(Relay)` to alert the owner if it runs low.
|
||||
* Calls recipient's `accept_relayed_call` function, asking whether it's going to accept the transaction. If not, `RelayHub` reverts.
|
||||
In this case, Relay doesn't get paid, as it was its responsibility to check `RelayHub.can_relay` before releasing the transaction.
|
||||
* Sends the transaction to the recipient. The call is made using `call()`, so reverts won't kill the transaction, just return false.
|
||||
@ -181,15 +177,6 @@ The process of winding a `Relay` down:
|
||||
* `Relay` shuts down.
|
||||
* Once the owner's unstake delay is over, owner calls `RelayHub.unstake()`, and withdraws the stake.
|
||||
|
||||
Removal of stale/invalid relays:
|
||||
|
||||
* During registration/refresh, `Relay` helps purging stale relays.
|
||||
* `Relay` scans the relays in `RelayHub`, e.g. by going through old `RelayAdded` events.
|
||||
* `Relay` looks for stale relays (where the latest recorded `timestamp` is a few days ago).
|
||||
* If `Relay` finds such relay, it passes the stale relay as `optional_relay_removal` during registration.
|
||||
* `RelayHub` verifies that the reported stale relay is indeed stale or invalid, removes it from the relays map and emits `RelayRemoved(r)`.
|
||||
The storage refund offsets Relay's registration cost, so `Relay` is incentivized to remove a stale relay whenever if can find one.
|
||||
|
||||
## Rationale
|
||||
The rationale for the gas stations network design is a combination of two sets of requirements: Easy adoption, and robustness.
|
||||
|
||||
@ -236,6 +223,13 @@ The sender then proceeds to select a new relay and send the original transaction
|
||||
The result of such attack is a delay of a few blocks in sending the transaction (until the attack is detected) but the relay gets removed and loses its entire stake.
|
||||
Scaling such attack would be prohibitively expensive, and actually quite profitable for senders and honest relays.
|
||||
|
||||
##### Attack: Relay attempts to censor a transaction by signing it, but using a nonce higher than it's current nonce.
|
||||
In this attack, the Relay did create and return a perfectly valid transaction, but it will not be mined until this Relay fills the gap in the nonce with 'missing' transactions.
|
||||
This may delay the relaying of some transactions indefinately. In order to mitigate that, the sender includes a `max_nonce` parameter with it's signing request.
|
||||
It is suggested to be higher by 2-3 from current nonce, to allow the relay process several transactions.
|
||||
|
||||
When the sender receives a transaction signed by a Relay he validates that the nonce used is valid, and if it is not, the client will ignore the given relay and use other relays to relay given transaction. Therefore, there will be no actual delay introduced by such attack.
|
||||
|
||||
##### Attack: Dapp attempts to burn relays funds by implementing an inconsistent accept_relayed_call() and using multiple sender addresses to generate expensive transactions, thus performing a DoS attack on relays and reducing their profitability.
|
||||
In this attack, a contract sets an inconsistent accept_relayed_call (e.g. return zero for even blocks, nonzero for odd blocks), and uses it to exhaust relay resources through unpaid transactions.
|
||||
Relays can easily detect it after the fact.
|
||||
@ -275,9 +269,6 @@ After it caused this minor delay and got blacklisted, the attacker must wait a m
|
||||
Simultaneously bringing up a number of unreliable relays, large enough to cause a noticeable network delay, would be prohibitively expensive due to the required stake,
|
||||
and even then, all those relays will get blacklisted within a short time.
|
||||
|
||||
##### Attack: Relay attempts to unregister other relays.
|
||||
Removal of stale relays is trustless. RelayHub verifies whether the removed relay has performed any action recently, and would revert any transaction that tries to remove an active relay.
|
||||
|
||||
##### Attack: Attacker attempts to replay a relayed transaction.
|
||||
Transactions include a nonce. RelayHub maintains a nonce (counter) for each sender. Transactions with bad nonces get reverted by RelayHub. Each transaction can only be relayed once.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user