Git Product home page Git Product logo

flashbots / suave-geth Goto Github PK

View Code? Open in Web Editor NEW
183.0 16.0 48.0 180.42 MB

Home Page: https://collective.flashbots.net/t/suave-centauri-open-sourcing-suave-geth/2196

License: GNU Lesser General Public License v3.0

Dockerfile 0.01% Makefile 0.07% Go 89.36% Shell 0.24% NSIS 0.17% Python 0.08% JavaScript 3.28% HTML 0.09% Assembly 0.70% C 4.99% M4 0.19% Sage 0.22% Java 0.22% Solidity 0.35% Smarty 0.02%

suave-geth's Introduction

SUAVE

Goreport status CI status

SUAVE is designed to decentralize the MEV supply chain by enabling centralized infrastructure (builders, relays, centralized RFQ routing, etc.) to be programmed as smart contracts on a decentralized blockchain.

suave-geth is a work-in-progress Golang SUAVE client consisting of two separable components: chain nodes and execution nodes. SUAVE clients offer confidential execution for smart contracts, allowing confidential processing with extended precompiles for enhanced MEV functionalities, including transaction simulation via geth RPC, block building, and relay boosting, all handled by dedicated execution nodes.

For a deeper dive, check out the following links:


Getting Started

Starting a local devnet

You can use suave-geth to start a local SUAVE devnet.

There's multiple ways to get suave-geth:

  1. Install the latest release binary
  2. Build from source
  3. Use Docker

Install the latest suave-geth release binary

curl -L https://suaveup.flashbots.net | bash

Building from source

# build the binary
$ make suave

Now you can go to /build/bin and:

Start the local devnet like this:

$ ./suave-geth --suave.dev

Start the Rigil testnet like this:

$ ./suave-geth --rigil

Using Docker

# spin up the local devnet with docker-compose
$ make devnet-up

# check that the containers are running
$ docker ps

# you can stop the local devnet like this
$ make devnet-down

Testing the devnet

Create a few example transactions:

$ go run suave/devenv/cmd/main.go

Execute a RPC request with curl like this:

$ curl 'http://localhost:8545' --header 'Content-Type: application/json' --data '{ "jsonrpc":"2.0", "method":"eth_blockNumber", "params":[], "id":83 }'

What next?

  • suapp-examples is a collection of example SUAVE apps and boilerplate to get started quickly and right-footed.
  • suave-specs is the spec repository for SUAVE which contains all the technical documentation.

suave-geth's People

Contributors

aaronbuchwald avatar acud avatar arachnid avatar cjentzsch avatar cubedro avatar debris avatar ferranbt avatar fjl avatar gavofyork avatar gballet avatar gluk256 avatar holiman avatar holisticode avatar janos avatar jsvisa avatar karalabe avatar lightclient avatar ligi avatar mariusvanderwijden avatar nonsense avatar obscuren avatar renaynay avatar rjl493456442 avatar s1na avatar s7v7nislands avatar tgerring avatar ucwong avatar vbuterin avatar zelig avatar zsfelfoldi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

suave-geth's Issues

Restricting access to EVM callback

SuaveTransaction execution environment doesn't expose any properties of ConfidentialRequest that invoked it.

Rationale

Suppose you have a confidential method bid() which allows you to simulate payment tx; store it in confidential store etc.. The contract returns a callback to bidCallback(), a public non-confidential method. It has to be public and external to be called by the ConfidentialComputeRequest-sender in the SuaveTransaction.
Now, lets say you want to store the bid information and emit a lot, so you pass the data to the callback and store it during SuaveTransaction. But because the callback is public anybody can call it and change the storage or emit the log.

I tackled this by implementing ConfidentialControl using hash-based access control (implementation). But this requires unnecessary confidential initialisation of the contract and gas spent on guard checks.

Implementation

I'm not sure what implementation is the best for this. One way I believe it could work is to create a non-confidential precompile that returns the recipient field of the ConfidentialRequest used to invoke the SuaveTransaction. This way it is much easier and less gas intensive to create a guard that restricts access to the callback method.

`--json` flag in `spell deploy`

Describe the feature you would like

Output the contract address, tx hash, and deployer address (same as forge create --json) as JSON to stdout, so it can be used in shell scripts.

Additional context

No response

`buildEthblock` precompile fails with 'out of gas' with large payload

What version of Suave are you on?

suave-geth version 0.1.5-d8f48a86-20240414

What command(s) is the bug in?

No response

Operating System

Linux

Describe the bug

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import "suave-std/suavelib/Suave.sol";

contract Builder {
    event NewBuilderBidEvent(Suave.DataId dataId, uint64 decryptionCondition, address[] allowedPeekers);

    function emitNewBuilderBidEvent(Suave.DataRecord memory record) public {
        emit NewBuilderBidEvent(record.id, record.decryptionCondition, record.allowedPeekers);
    }

    function build(
        uint64 blockNumber,
        string calldata relayUrl,
        address[] calldata allowedPeekers,
        address[] calldata allowedStores
    ) external payable returns (bytes memory) {
        require(Suave.isConfidential());
        Suave.DataId[] memory dataids = new Suave.DataId[](0);
        Suave.DataRecord memory record =
            Suave.newDataRecord(blockNumber, allowedPeekers, allowedStores, "random");
        Suave.confidentialStore(record.id, "default:v0:mergedDataRecords", abi.encode(dataids));
        Suave.BuildBlockArgs memory blockArgs;
        blockArgs.fillPending = true;
        (bytes memory builderBid, bytes memory envelope) = Suave.buildEthBlock(blockArgs, record.id, ""); // namespace not used.
        Suave.submitEthBlockToRelay(relayUrl, builderBid);
        return bytes.concat(this.emitNewBuilderBidEvent.selector, abi.encode(record));
    }
}

The method build() fails with 'out of gas' when Suave.buildEthBlock returns very large payload. When I ran It failed with 300 tx in a block

No Deneb payload

When submitting the block to the relay via Suave I get bad request with error {"code":400,"message":"not deneb payload"}\n.

The source of the error is here in the relay code.

It appears suave-geth and suave-execution-geth need support for the new payload with blobs.

Private Key Gen Precompile

Rationale

Right now the EthBuildBlock precompile implicitly generates a private key to construct the mevboost payment transaction, but we dont have a precompile to do solely this task. Some SUAPPs would like to generate a private key from inside the SUAPP to claim they dont have control over it. If the SUAPP leaks this info via smart contract code then obviously their claim doesn't hold, but you can verify this via contract introspection.

Key should be ECDA secp256k1 and stored in a format that the signMessage precompile supports so that SUAPPs dont need to reformat.

Precompile that exposes execution-node's API

Describe the feature you would like

A precompile that exposes execution-node's API. For starters eth namespace would be enough.

Afaik now one needs to call external node to get the latest block or account balance, this seems unnecessary as there is a local node running alongside SUAVE.
It is true that some values could be obtained by eth_call to a contract exposing block API (like the Maker's MulticallV2), but this again seems more convoluted that it should be.

Additional context

No response

Precompiles `simulateBundle` & `submitBundleJsonRPC` have different inputs

For simulateBundle you have to pass a struct as input that reflects

type SBundle struct {
 BlockNumber     *big.Int      `json:"blockNumber,omitempty"` // if BlockNumber is set it must match DecryptionCondition!
 MaxBlock        *big.Int      `json:"maxBlock,omitempty"`
 Txs             Transactions  `json:"txs"`
 RevertingHashes []common.Hash `json:"revertingHashes,omitempty"`
 RefundPercent   *int          `json:"percent,omitempty"`
}

For submitBundleJsonRPC you have to pass json encoded string:

[
    {
      txs,               // Array[String], A list of signed transactions to execute in an atomic bundle
      blockNumber,       // String, a hex encoded block number for which this bundle is valid on
      minTimestamp,      // (Optional) Number, the minimum timestamp for which this bundle is valid, in seconds since the unix epoch
      maxTimestamp,      // (Optional) Number, the maximum timestamp for which this bundle is valid, in seconds since the unix epoch
      revertingTxHashes, // (Optional) Array[String], A list of tx hashes that are allowed to revert
      replacementUuid,   // (Optional) String, UUID that can be used to cancel/replace this bundle
    }
  ]

I understand that these work differently (simulate does local simulation via buildBlock & submitBundle just does signing and remote call). Still this could be a source of confusion and would help to have similar input for both of these precompiles.

Service Not Available Message

Describe the feature you would like

When a kettle turns off a service it should have something like "service not available" message

Additional context

No response

How to ensure a piece of state is only used by a CCR once

I am confused on how to ensure that confidential compute requests (CCRs) only use a piece of state once.

Rationale

It would be useful for suave developers to know if a piece of state has been consumed by a CCR already.

Take the use case of trying to create and send transactions to an L1 using a singular private key. The suapp stores the private key in the confidential store so this operation must be ran in a CCR. Each transaction needs a unique and continuously increasing nonce to sign over. The question is: where can we store this nonce so CCRs can be triggered permissionlessly?

Option 1: Put the nonce on-chain and increment it during CCR callbacks.
Issue: What happens if multiple CCRs are sent per on-chain block? In this case, the on-chain nonce would be used multilpe times and CCRs would fail to have their logic execute as intended.

Option 2: Put the nonce in the confidential store.
Issue: What happens if two kettles get a CCR at the same time? How do the CCRs coordinate around the race condition of consuming and updating the confidential store?

Option 3: Have the user pass it in.
Issue: Similar race condition to (1)/(2) and additional greifing attack vector of users intentionally submitting wrong nonces.

Option 4: Put the nonce in the confidential store and restrict the Suapp to a single kettle to avoid the race conditions.
Issue: this is not decentralized enough for some applications.

Ask

Is there another solution that I'm not considering?

I'm working on an application and would like to have data stored somewhere that can be safely and permissonlessly acted on by multiple kettles inside of CCRs.

suave-geth locally does not revert when a confidential request update state storage

What version of Suave are you on?

suave-geth version 0.1.5-23d7a718-20240404

What command(s) is the bug in?

No response

Operating System

macOS (Apple Silicon)

Describe the bug

I'm building something on top of Suave, and was following the documentation on how to make an off-chain call to ChatGPT.

In the example https://suave-alpha.flashbots.net/concepts/offchain-http, a new instance of ChatGPT is created inside of the offchain() and it updates the storage state of that contract apiKey = _apiKey;.

When running that example locally using suave-geth, and calling the offchain() method, it does not revert.
When deploying the same contract on Rigil testnet, it does revert with panic: confidential request cannot modify state storage. I'm assuming this is a bug as the behaviour locally should mimic the one in production?

End Builder Session on New Block

Rationale

Right now a session can last indefinitely but should be canceled when a new block comes in as that makes the state its simulating on invalid

Implementation

Do you have ideas regarding the implementation of this feature?
Are you willing to implement this feature?

suaveup installation without root password

Describe the feature you would like

running the suaveup installation script puts the executable in /usr/local/bin, which requires root access. it would be preferable to install by default in a user specific location to avoid asking for the root password.

Additional context

No response

RPC port fixed to 8545 in dev mode

System information

Suave-Geth
Version: 1.12.0-stable
Git Commit: 11f4230
Git Commit Date: 20231207
Architecture: arm64
Go Version: go1.20.8
Operating System: darwin

Expected behaviour

In dev mode, the HTTP-RPC server is started on the specified --http.port.

Actual behaviour

Instead, HTTP-RPC server will always start on 8545.

Steps to reproduce the behaviour

suave --suave.dev --http.port 3000
The port will still start on 8545

This inhibits the developer from starting the suave RPC server on a port of their choice in case port 8545 is already occupied.

parameterize `genesisForkVersion` in `buildEthBlockTo`

Describe the feature you would like

Currently we have this value hardcoded to Holesky's genesis fork version.
Add a new parameter chainId uint64 to BuildBlockArgs that maps the given chainId to that chain's genesisForkVersion to allow suapps to sign blocks for all currently-live ethereum networks, including mainnet, sepolia, and holesky.

For example, if chainId was set to 1, the genesisForkVersion should be phase0.Version{0x00, 0x00, 0x00, 0x00}.

Additional context

No response

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.