Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WEB3-67: feat: switch Steel to alloy #183

Merged
merged 32 commits into from
Aug 7, 2024
Merged

WEB3-67: feat: switch Steel to alloy #183

merged 32 commits into from
Aug 7, 2024

Conversation

Wollac
Copy link
Contributor

@Wollac Wollac commented Jul 24, 2024

⚡️ Features

  • Replace ethers dependency completely with alloy.
  • Make host functions async.
  • Add support to build EvmEnv from any alloy provider.
  • Add more efficient RLP-based serialization for the header.

🛠 Fixes

  • Store the commitment inside the EvmEnv.
  • Use eth_getTransactionCount and eth_getBalance instead of eth_getProof to query basic account information.
  • Switch tests from pre-recorded RPC responses to Anvil.

🚨 Breaking Changes

  • EthEvmEnv::from_rpc now accepts a Url instead of a &str for the HTTP RPC endpoint.
  • EvmEnv::from_provider now requires an alloy provider, and the block number parameter has been changed to a BlockNumberOrTag.
  • EvmEnv::sol_commitment has been replaced with EvmEnv::commitment (to get a reference), or EvmEnv::into_commitment (to consume and return the commitment).
  • ETH_SEPOLIA_CHAIN_SPEC and ETH_MAINNET_CHAIN_SPEC have been moved to the ethereum module.
  • CachedProvider has been removed completely. As alternatives, you can:
    • Use anvil --fork-url https://ethereum-rpc.publicnode.com@20475759 to create a cached fork for block 20475759.
    • Cache the RPC responses on an HTTP level using Tower or a caching forward proxy.
  • The host functions are now async instead of blocking:
// Create an EVM environment from an RPC endpoint and a block number or tag.
let mut env = EthEvmEnv::from_rpc(args.rpc_url, BlockNumberOrTag::Latest).await?;
//  The `with_chain_spec` method is used to specify the chain configuration.
env = env.with_chain_spec(&ETH_SEPOLIA_CHAIN_SPEC);

// Preflight the call to prepare the input that is required to execute the function in
// the guest without RPC access. It also returns the result of the call.
let mut contract = Contract::preflight(CONTRACT, &mut env);
let returns = contract.call_builder(&CALL).from(CALLER).call().await?;

// Finally, construct the input from the environment.
let input = env.into_input().await?;

@Wollac Wollac self-assigned this Aug 5, 2024
@Wollac Wollac marked this pull request as ready for review August 5, 2024 14:02
@Wollac Wollac requested review from capossele and a team as code owners August 5, 2024 14:02
@nategraf nategraf self-requested a review August 5, 2024 16:30
// we cannot clone the database, so it gets moved in and out of the task
let db = self.env.db.take().unwrap();

let (res, db) = tokio::task::spawn_blocking(move || {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be preferable, if Steel as a library relies on tokio. Would be nice if this could remain runtime agnostic.
However, we have to call a long running blocking function inside of an async library, I don't think there is a way around this.

};

EvmEnv::from_provider(provider, block_number)
pub async fn from_rpc(url: Url, number: BlockNumberOrTag) -> anyhow::Result<Self> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be rather switch this to a block hash or tag?
Could there be situations in which the block number is not well defined, maybe due to re-orgs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible. One API solution to this is to use a builder pattern and split the method that adds the RPC URL from the method that specifies the block ref. In this case, we could provide two methods, one for BlockNumberOrTag and one for block hash (or something like that).

Copy link
Contributor

@nategraf nategraf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! I added some comments. None of them are concerns about the core of this PR.

Comment on lines -32 to -33
ethers-core = "2.0"
ethers-providers = "2.0"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

examples/erc20-counter/README.md Show resolved Hide resolved
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(wallet)
.on_http(args.rpc_url);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option is to use on_builtin to support HTTPS and WS URLs without code changes. https://docs.rs/alloy-provider/latest/alloy_provider/struct.ProviderBuilder.html#method.on_builtin

Copy link
Contributor Author

@Wollac Wollac Aug 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very interesting, I didn't even know that existed. It even takes a string similar to the eth provider before...

🤔 I kinda liked the change to Url for its additional type safety and I guess HTTP is the more realistic provider as we don't rely on any pubsub and even then we have the from_provider for any alloy provider...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the question of using Url, I also like that from a semantics point of view. With on_builtin, we could call url.as_str to pass it in, so we can keep that change either way. On the use of HTTP provider. I do see that we constrain the types to HTTP providers anyway. Something we should think about before marking 1.0 is whether we should/can loosen thew type constraints there. It's really not a major issue in any case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The types of EthEvmEnv::from_rpc are only Http because this is what .on_http returns. There is also

pub async fn from_provider(provider: P, number: BlockNumberOrTag) -> anyhow::Result<Self> {

which works with any generic alloy provider.

steel/src/config.rs Outdated Show resolved Hide resolved
};

EvmEnv::from_provider(provider, block_number)
pub async fn from_rpc(url: Url, number: BlockNumberOrTag) -> anyhow::Result<Self> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible. One API solution to this is to use a builder pattern and split the method that adds the RPC URL from the method that specifies the block ref. In this case, we could provide two methods, one for BlockNumberOrTag and one for block hash (or something like that).

steel/src/state.rs Show resolved Hide resolved
state_trie: MerkleTrie,
storage_tries: impl IntoIterator<Item = MerkleTrie>,
contracts: impl IntoIterator<Item = Bytes>,
block_hashes: HashMap<u64, B256>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this also be impl IntoIterator or is there a reason not to (e.g. maybe it would waste a lot of time constructing the map)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HashMap is actually already constructed during validation in the into_env step. So I think it makes sense to just move it here.

steel/tests/steel.rs Outdated Show resolved Hide resolved
steel/tests/erc20.rs Show resolved Hide resolved
steel/tests/steel.rs Outdated Show resolved Hide resolved
Pending #185 

Attempt at solving #174 and #176. 

Closes #174
Closes #176

---------

Co-authored-by: Victor Graf <victor@risczero.com>
@github-actions github-actions bot changed the title feat: switch Steel to alloy WEB3-67: feat: switch Steel to alloy Aug 7, 2024
@Wollac Wollac enabled auto-merge (squash) August 7, 2024 09:59
@Wollac Wollac merged commit b2dcc8e into main Aug 7, 2024
9 checks passed
@Wollac Wollac deleted the feat/alloy branch August 7, 2024 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants