Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/shutter-network/shutter

Prevent frontrunning and malicious MEV on Ethereum by using a threshold cryptography-based distributed key generation (DKG) protocol.
https://github.com/shutter-network/shutter

ethereum

Last synced: 2 months ago
JSON representation

Prevent frontrunning and malicious MEV on Ethereum by using a threshold cryptography-based distributed key generation (DKG) protocol.

Lists

README

        

# Shutter

This repository contains Shutter, a threshold encryption based frontrunning protection system for
Ethereum smart contracts.

The code is split into three directories:

- `contracts/`: the contracts to be deployed on mainnet, written in Solidity and tested in Python
with eth-brownie
- `shuttermint/`: the main application code written in Go, in particular the Shuttermint and Keyper
implementation
- `example/`: a little example dapp user interface

To see it in action, check out the example application hosted
[here](https://brainbot-com.github.io/shutter-example-dapp/).

## Setup a Full Testing Environment

The following steps will setup a local testing environment consisting of an Ethereum dev chain, a
single Shuttermint node, and an arbitrary number of keyper nodes. The commands referenced can be
found in `shuttermint/bin` after `make build` has been run in the `shuttermint/` directory.

### 1) Start the Ethereum Dev Chain

There are many options, but we suggest using either Geth or Ganache with a block time of 3s. Make
sure that the JSON RPC interface is enabled and accessible via websockets and that you know the
private key of at least one funded account. In the rest of the guide, we'll assume the JSON RPC URL
is `ws://localhost:8545` and the private key is
`b0057716d5917badaf911b193b12b910811c1497b5bada8d7711f758981c3773`. If Ganache is used, the
following command replicates these settings:

```
ganache-cli -d -b 3
```

### 2) Build Shutter and deploy the Shutter Contracts:

If you use the source release or git repository, you need to build the shuttermint application:

```
cd shuttermint
make build
```

Next, the Shutter contract suite has to be deployed on the dev chain:

```
shuttermint deploy -e ws://localhost:8545 -k b0057716d5917badaf911b193b12b910811c1497b5bada8d7711f758981c3773 -o contracts.json
```

This will output the addresses into a JSON file for later reference.

### 3) Initialize the Keypers

Now, we can initialize the keypers. Running

```
shuttermint prepare configs -c contracts.json -e ws://localhost:8545 --num-keypers 3
```

creates a new directory called `testrun` (customizable via the `-d` flag) with one subdirectory for
each of three keypers. It also creates the file `testrun/config.json`, which contains an example batch
config for later use.

The newly created config files found in `testrun/keyper/config.toml` contain an Ethereum private
key under `SigningKey`. This key is randomly generated, so doesn't yet have access to ETH needed
to send transactions. To change this, run

```
shuttermint prepare fund -e ws://localhost:8545 -k b0057716d5917badaf911b193b12b910811c1497b5bada8d7711f758981c3773 --config testrun/config.json
```

which will send 1 (dev chain) ETH from the deployer account to each keyper.

### 4) Schedule a Batch Config

Next, a batch config has to be defined and scheduled on the main chain, defining some important
system parameters. Write the following contents to a new file called `config.json` or use the
example config `testrun/config.json` generated in the previous step.

```
{
"StartBatchIndex": 0,
"StartBlockNumber": ,
"Keypers": [

],
"Threshold": ,
"BatchSpan": 10,
"BatchSizeLimit": 100000,
"TransactionSizeLimit": 1000,
"TransactionGasLimit": 10000,
"FeeReceiver": "0x1111111111111111111111111111111111111111",
"TargetAddress": ,
"TargetFunctionSelector": "0x943d7209",
"ExecutionTimeout": 15
}
```

Make sure to fill in the following fields:

- `StartBlockNumber`: Use a block number of the Ethereum dev chain that's in the near future (e.g.,
current block number plus 100 blocks). For testing purposes it's also okay to use 0
here. `shuttermint config` will choose a valid value for `StartBlockNumber` and `StartBatchIndex`
in that case.
- `TargetAddress`: The hex encoded, checksummed address of the test target contract to be found in
`contracts.json` under `TargetContract`.
- `Threshold`: The threshold parameter to use. We suggest two thirds of the number of keypers,
rounded up.
- `Keypers`: The list of keyper addresses. The addresses must correspond to the private keys
defined in the keyper config files. The generated files show the keyper address in the first line.

Now, send the config to the config contract:

```
shuttermint config -c contracts.json -e ws://localhost:8545 set-next --config config.json -k b0057716d5917badaf911b193b12b910811c1497b5bada8d7711f758981c3773
```

After all transactions have been confirmed, double check that the contract has accepted everything:

```
shuttermint config -c contracts.json -e ws://localhost:8545 query -i next | diff config.json -
```

If so (i.e., the output is empty), schedule the config with

```
shuttermint config -c contracts.json -e ws://localhost:8545 schedule -k b0057716d5917badaf911b193b12b910811c1497b5bada8d7711f758981c3773
```

and, once more,

```
shuttermint config -c contracts.json -e ws://localhost:8545 query -i last | diff config.json -
```

double check that the changes are live.

### 5) Start and Bootstrap Shuttermint

Now that the main chain is ready, we have to tend to the Shuttermint chain. Initialize its directory with

```
shuttermint init --dev --root testchain
```

and launch it:

```
shuttermint chain --config testchain/config/config.toml
```

Lastly, the Shuttermint chain has to be told about the initial keyper set. To do so, run the
following command:

```
shuttermint bootstrap -c contracts.json -k b0057716d5917badaf911b193b12b910811c1497b5bada8d7711f758981c3773 -e ws://localhost:8545
```

### 6) Run the Keypers

Finally, the keyper nodes can be started:

```
shuttermint keyper --config testrun/keyper/config.toml
```

Run this command for each of the keypers initialized.

Now, the keypers should start generating keys as well as decrypting and executing batches on the
main chain.

### 7) Shut It Down

To shut everything down in the end, kill the following processes:

- the keyper nodes started in step 6
- the Shuttermint node started in step 5
- the Ethereum chain started in step 1

Delete the `testchain` and `testrun` directories as well as the `contracts.json` and `config.json`
files to clean up.

## Contracts

At its core, Shutter's contract suite consists of three main components:

- the config contract
- the batcher contract
- the executor contract

The following contracts perform auxiliary tasks:

- the deposit contract
- the fee bank contract
- the key broadcast contract
- the keyper slasher contract

All contracts can be found in the `contracts/` subdirectory.

### Config Contract

The config contract defines the system parameters. Since they must be able to evolve over time,
they are given as a list of batch config objects.

New batch configs can be scheduled for the future, as long as the `configChangeHeadsUp` interval
set during construction is abided by. This is intended to give keypers enough time to react to
changes. Once scheduled, batch configs cannot be removed and their order cannot be changed.

Scheduling a config is a two step process: First, the config object is drafted using the various
`setNext...` functions and, second, it is finalized using `schedule`.

Only the contract owner is allowed to schedule configs. This role is inteded to be played by a DAO.

The batch config objects divide time into a sequence of batches and each config is applicable to a
range of them. The following fields specify this:

- `startBatchIndex`: the index of the first batch for which the config is applicable to
- `startBlockNumber`: the Ethereum block number at which the first batch starts
- `batchSpan`: the length of each batch in Ethereum blocks

The first config has a `startBatchIndex` of 0. It will end with the `startBatchIndex` of the second
config, and so on. The config contract enforces that transitions between batches are seamless,
i.e., the start block number of a config fits to the batch span and start block number of the
previous config (e.g., if config 1 starts at batch index `100` and block `500` and has a span of
`10` and config 2 at batch index `200`, it's start block number must be `600`).

The batch span can be zero denoting that the system is disabled. It can be enabled again by
scheduling a new config with a batch span greater than zero.

The key generation parameters are set by the `keypers` and `threshold` fields. Note that `keypers`
must not contain duplicates and that the threshold must less than or equal to the number of
keypers, but greater than half of it.

The transactions that are allowed to enter a batch are constrained by the following fields:

- `transactionSizeLimit`: the maximum size of a transaction in bytes
- `batchSizeLimit`: the maximum size of all transactions in a single batch in bytes
- `feeReceiver`: address that will receive transaction fees

For transaction execution after decryption, the following fields are relevant:

- `transactionGasLimit`: the maximum amount of gas a transaction is allowed to consume during
execution once it is decrypted
- `targetAddress`: the address of the contract to which the derypted transactions will be passed
to
- `targetFunctionSelector`: the 4 byte function selector that specifies the function in the target
contract that will be called with each decrypted transaction
- `executionTimeout`: the number of blocks to pass between the end of a batch and the time at which
it is assumed that decryption has failed and can be skipped (e.g., because too many keyper were
offline)

### Batcher Contract

### Executor Contract

### Auxiliary Contracts