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

EVM: Implement Gas Oracle #975

Merged
merged 35 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
76dd96b
implement gas oracle
orkunkilic Oct 3, 2023
6ea8a7b
Merge branch 'nightly' into orkun/gas-price
orkunkilic Oct 3, 2023
8b2d063
lint
orkunkilic Oct 3, 2023
2b00df1
fix compilation issues
bkolad Oct 3, 2023
a1f51df
move gas oracle to sequencer with cache
orkunkilic Oct 5, 2023
091c7da
lint
orkunkilic Oct 5, 2023
bcc2c56
test
orkunkilic Oct 5, 2023
75c9eb9
integration test for failing case
orkunkilic Oct 5, 2023
2394cc2
fix conflicts
orkunkilic Oct 9, 2023
120a1f0
fix conflicts
orkunkilic Oct 9, 2023
ce240f2
update lock
orkunkilic Oct 9, 2023
ec22381
fix conflicts
orkunkilic Oct 9, 2023
ca81c72
add experimental
orkunkilic Oct 9, 2023
c3239f5
Merge branch 'orkun/bug-parent-hash' into orkun/gas-price
orkunkilic Oct 9, 2023
ceb5587
lint
orkunkilic Oct 9, 2023
3420b02
add refs
orkunkilic Oct 9, 2023
eabdea4
tracing
orkunkilic Oct 9, 2023
dff4ded
gas price oracle tests
orkunkilic Oct 10, 2023
8a6eefe
lint
orkunkilic Oct 10, 2023
d2b1ce1
Merge branch 'nightly' into orkun/gas-price
orkunkilic Oct 10, 2023
b286b6a
fix
orkunkilic Oct 10, 2023
ca1a973
remove unnecessary line
orkunkilic Oct 10, 2023
8422891
move module into sov-ethereum
orkunkilic Oct 10, 2023
3a2ff15
move module into sov-ethereum
orkunkilic Oct 10, 2023
6c16d97
fix imports
orkunkilic Oct 10, 2023
5718774
Merge branch 'nightly' into orkun/gas-price
orkunkilic Oct 17, 2023
771f221
fix conflict
orkunkilic Oct 17, 2023
dc5ace0
update cargo lock
orkunkilic Oct 17, 2023
accdd6d
lint
orkunkilic Oct 17, 2023
eee475a
fix conflicts
orkunkilic Oct 17, 2023
ef6dfba
fix test conflicts
orkunkilic Oct 17, 2023
232c589
fix integration tests
orkunkilic Oct 18, 2023
cca53d7
Merge branch 'nightly' into orkun/gas-price
orkunkilic Oct 18, 2023
b91845b
update cargo lock
bkolad Oct 18, 2023
dab4b02
Merge branch 'nightly' into orkun/gas-price
bkolad Oct 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
568 changes: 266 additions & 302 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ members = [
"full-node/db/sov-db",
"full-node/sov-sequencer",
"full-node/sov-ethereum",
"full-node/sov-ethereum-gas-price",
"full-node/sov-stf-runner",

"utils/zk-cycle-macros",
Expand Down
71 changes: 56 additions & 15 deletions examples/demo-rollup/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ default-run = "sov-demo-rollup"

[dependencies]
# non-optional dependencies

serde = { workspace = true, features = ["derive"], optional = true }
sov-celestia-adapter = { path = "../../adapters/celestia" }
const-rollup-config = { path = "../const-rollup-config" }
sov-stf-runner = { path = "../../full-node/sov-stf-runner" }
Expand All @@ -22,32 +24,41 @@ sov-modules-api = { path = "../../module-system/sov-modules-api" }
sov-nft-module = { path = "../../module-system/module-implementations/sov-nft-module" }
demo-stf = { path = "../demo-stf" }
methods = { path = "../demo-prover/methods" }
borsh = { workspace = true, features = ["bytes"]}
borsh = { workspace = true, features = ["bytes"] }
async-trait = { workspace = true, optional = true }
anyhow = { workspace = true, optional = true }
jsonrpsee = { workspace = true, features = ["http-client", "server"], optional = true }
serde = { workspace = true, features = ["derive"], optional = true }
jsonrpsee = { workspace = true, features = [
"http-client",
"server",
], optional = true }
serde_json = { workspace = true, optional = true }
tracing = { workspace = true, optional = true }
hex = { workspace = true, optional = true }
secp256k1 = { workspace = true, optional = true }

tokio = { workspace = true, optional = true }
reth-primitives = { workspace = true, optional = true }
tracing-subscriber = { version = "0.3.17", features = ["env-filter"], optional = true }
tracing-subscriber = { version = "0.3.17", features = [
"env-filter",
], optional = true }

sov-db = { path = "../../full-node/db/sov-db", optional = true }
sov-ethereum-gas-price = { path = "../../full-node/sov-ethereum-gas-price", optional = true }
sov-ethereum = { path = "../../full-node/sov-ethereum", optional = true }
sov-sequencer = { path = "../../full-node/sov-sequencer", optional = true }
sov-sequencer = { path = "../../full-node/sov-sequencer", optional = true }
sov-risc0-adapter = { path = "../../adapters/risc0" }
sov-state = { path = "../../module-system/sov-state" }
sov-cli = { path = "../../module-system/sov-cli", optional = true }
clap = { workspace = true, optional = true}
clap = { workspace = true, optional = true }


[dev-dependencies]
sov-evm = { path = "../../module-system/module-implementations/sov-evm", features = ["smart_contracts"] }
sov-bank = { path = "../../module-system/module-implementations/sov-bank", features = ["native"] }
sov-evm = { path = "../../module-system/module-implementations/sov-evm", features = [
"smart_contracts",
] }
sov-bank = { path = "../../module-system/module-implementations/sov-bank", features = [
"native",
] }
borsh = { workspace = true }
sha2 = { workspace = true }
hex = { workspace = true }
Expand All @@ -56,7 +67,9 @@ reqwest = "0.11"
tendermint = "0.32"
tempfile = { workspace = true }
proptest = { workspace = true }
sov-rollup-interface = { path = "../../rollup-interface", features = ["fuzzing"] }
sov-rollup-interface = { path = "../../rollup-interface", features = [
"fuzzing",
] }
tokio = { workspace = true }
sov-demo-rollup = { path = ".", features = ["native"] }
prometheus = "0.11.0"
Expand All @@ -73,12 +86,40 @@ ethers = { workspace = true }
revm = { workspace = true }

[features]
default = ["native"] # Deviate from convention by making the "native" feature active by default. This aligns with how this package is meant to be used (as a binary first, library second).
experimental = ["default", "sov-ethereum/experimental", "reth-primitives", "secp256k1", "demo-stf/experimental", "sov-ethereum/local"]
native = ["anyhow", "jsonrpsee", "serde", "serde_json", "tracing", "tokio", "tracing-subscriber",
"demo-stf/native", "sov-modules-stf-template/native", "sov-risc0-adapter/native", "sov-modules-api/native",
"sov-state/native", "sov-cli", "clap", "sov-celestia-adapter/native", "sov-db", "sov-sequencer", "sov-stf-runner/native",
"sov-modules-api/native", "sov-rollup-interface/native"]
default = [
"native",
] # Deviate from convention by making the "native" feature active by default. This aligns with how this package is meant to be used (as a binary first, library second).
experimental = [
"default",
"sov-ethereum/experimental",
"sov-ethereum-gas-price/experimental",
"reth-primitives",
"secp256k1",
"demo-stf/experimental",
"sov-ethereum/local",
]
native = [
"anyhow",
"jsonrpsee",
"serde",
"serde_json",
"tracing",
"tokio",
"tracing-subscriber",
"demo-stf/native",
"sov-modules-stf-template/native",
"sov-risc0-adapter/native",
"sov-modules-api/native",
"sov-state/native",
"sov-cli",
"clap",
"sov-celestia-adapter/native",
"sov-db",
"sov-sequencer",
"sov-stf-runner/native",
"sov-modules-api/native",
"sov-rollup-interface/native",
]
bench = ["native", "async-trait", "hex"]
offchain = ["demo-stf/offchain"]

Expand Down
16 changes: 16 additions & 0 deletions examples/demo-rollup/src/register_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,19 @@ pub fn register_ethereum<C: sov_modules_api::Context, Da: DaService>(
.merge(ethereum_rpc)
.context("Failed to merge Ethereum RPC modules")
}

#[cfg(feature = "experimental")]
/// register ethereum gas price methods.
pub fn register_ethereum_gas_price<C: sov_modules_api::Context>(
orkunkilic marked this conversation as resolved.
Show resolved Hide resolved
gas_price_oracle_config: sov_ethereum_gas_price::experimental::GasPriceOracleConfig,
storage: C::Storage,
methods: &mut jsonrpsee::RpcModule<()>,
) -> Result<(), anyhow::Error> {
let ethereum_gas_price_rpc = sov_ethereum_gas_price::experimental::get_ethereum_gas_price_rpc::<
C,
>(gas_price_oracle_config, storage);

methods
.merge(ethereum_gas_price_rpc)
.context("Failed to merge Ethereum gas price RPC modules")
}
18 changes: 17 additions & 1 deletion examples/demo-rollup/src/rollup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use sov_cli::wallet_state::PrivateKeyAndAddress;
use sov_db::ledger_db::LedgerDB;
#[cfg(feature = "experimental")]
use sov_ethereum::experimental::EthRpcConfig;
#[cfg(feature = "experimental")]
use sov_ethereum_gas_price::experimental::GasPriceOracleConfig;
use sov_modules_api::default_context::{DefaultContext, ZkDefaultContext};
#[cfg(feature = "experimental")]
use sov_modules_api::default_signature::private_key::DefaultPrivateKey;
Expand All @@ -33,7 +35,7 @@ use tokio::sync::oneshot;
use tracing::debug;

#[cfg(feature = "experimental")]
use crate::register_rpc::register_ethereum;
use crate::register_rpc::{register_ethereum, register_ethereum_gas_price};
use crate::register_rpc::{register_ledger, register_sequencer};
use crate::{initialize_ledger, ROLLUP_NAMESPACE};

Expand All @@ -57,6 +59,9 @@ pub struct Rollup<Vm: ZkvmHost, Da: DaService + Clone> {
#[cfg(feature = "experimental")]
/// Configuration for the Ethereum RPC.
pub eth_rpc_config: EthRpcConfig,
#[cfg(feature = "experimental")]
/// Configuration for the gas price oracle.
pub gas_price_oracle_config: GasPriceOracleConfig,
/// Prover for the rollup.
#[allow(clippy::type_complexity)]
pub prover: Option<Prover<ZkStf<Da::Spec, Vm::Guest>, Da, Vm>>,
Expand Down Expand Up @@ -125,6 +130,7 @@ pub async fn new_rollup_with_celestia_da<Vm: ZkvmHost, P: AsRef<Path>>(
#[cfg(feature = "experimental")]
eth_signer.signers(),
);

let prover = prover.map(|(vm, config)| {
configure_prover(
vm,
Expand All @@ -147,6 +153,8 @@ pub async fn new_rollup_with_celestia_da<Vm: ZkvmHost, P: AsRef<Path>>(
sov_tx_signer_priv_key: read_sov_tx_signer_priv_key()?,
eth_signer,
},
#[cfg(feature = "experimental")]
gas_price_oracle_config: GasPriceOracleConfig::default(),
prover,
})
}
Expand Down Expand Up @@ -201,6 +209,8 @@ pub fn new_rollup_with_mock_da_from_config<Vm: ZkvmHost, P: AsRef<Path>>(
sov_tx_signer_priv_key: read_sov_tx_signer_priv_key()?,
eth_signer,
},
#[cfg(feature = "experimental")]
gas_price_oracle_config: GasPriceOracleConfig::default(),
prover,
})
}
Expand Down Expand Up @@ -252,6 +262,12 @@ impl<Vm: ZkvmHost, Da: DaService<Error = anyhow::Error> + Clone> Rollup<Vm, Da>
register_ethereum::<DefaultContext, Da>(
self.da_service.clone(),
self.eth_rpc_config,
storage.clone(),
&mut methods,
)?;
#[cfg(feature = "experimental")]
register_ethereum_gas_price::<DefaultContext>(
self.gas_price_oracle_config,
storage,
&mut methods,
)?;
Expand Down
29 changes: 27 additions & 2 deletions examples/demo-rollup/tests/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ async fn execute(client: &TestClient) -> Result<(), Box<dyn std::error::Error>>

let set_arg = 923;
let tx_hash = {
let set_value_req = client.set_value(contract_address, set_arg).await;
let set_value_req = client
.set_value(contract_address, set_arg, None, None)
.await;
client.send_publish_batch_request().await;
set_value_req.await.unwrap().unwrap().transaction_hash
};
Expand Down Expand Up @@ -150,7 +152,7 @@ async fn execute(client: &TestClient) -> Result<(), Box<dyn std::error::Error>>
// Create a blob with multiple transactions.
let mut requests = Vec::default();
for value in 100..103 {
let set_value_req = client.set_value(contract_address, value).await;
let set_value_req = client.set_value(contract_address, value, None, None).await;
requests.push(set_value_req);
}

Expand Down Expand Up @@ -195,5 +197,28 @@ async fn execute(client: &TestClient) -> Result<(), Box<dyn std::error::Error>>
assert_eq!(value, get_arg.as_u32());
}

{
// get initial gas price
let initial_gas_price = client.eth_gas_price().await;

// send 100 set transaction with high gas fee
let mut requests = Vec::default();
for value in 200..300 {
let set_value_req = client
.set_value(contract_address, value, Some(20u64), Some(21u64))
.await;
requests.push(set_value_req);
}

client.send_publish_batch_request().await;

// get gas price
let latest_gas_price = client.eth_gas_price().await;

// assert gas price is higher
// TODO: emulate gas price oracle here to have exact value
assert!(latest_gas_price > initial_gas_price);
}

Ok(())
}
13 changes: 11 additions & 2 deletions examples/demo-rollup/tests/evm/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ impl TestClient {
&self,
contract_address: H160,
set_arg: u32,
max_priority_fee_per_gas: Option<u64>,
max_fee_per_gas: Option<u64>,
) -> PendingTransaction<'_, Http> {
let nonce = self.eth_get_transaction_count(self.from_addr).await;

Expand All @@ -132,8 +134,8 @@ impl TestClient {
.chain_id(self.chain_id)
.nonce(nonce)
.data(self.contract.set_call_data(set_arg))
.max_priority_fee_per_gas(10u64)
.max_fee_per_gas(MAX_FEE_PER_GAS)
.max_priority_fee_per_gas(max_priority_fee_per_gas.unwrap_or(10u64))
.max_fee_per_gas(max_fee_per_gas.unwrap_or(MAX_FEE_PER_GAS))
.gas(GAS);

let typed_transaction = TypedTransaction::Eip1559(req);
Expand Down Expand Up @@ -286,6 +288,13 @@ impl TestClient {
count.as_u64()
}

pub(crate) async fn eth_gas_price(&self) -> ethereum_types::U256 {
self.http_client
.request("eth_gasPrice", rpc_params![])
.await
.unwrap()
}

pub(crate) async fn eth_get_block_by_number(
&self,
block_number: Option<String>,
Expand Down
44 changes: 44 additions & 0 deletions full-node/sov-ethereum-gas-price/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[package]
name = "sov-ethereum-gas-price"
authors = { workspace = true }
edition = { workspace = true }
homepage = { workspace = true }
license = { workspace = true }
repository = { workspace = true }
rust-version = { workspace = true }
version = { workspace = true }
readme = "README.md"
resolver = "2"
publish = false

[dependencies]
anyhow = { workspace = true }
serde = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
jsonrpsee = { workspace = true, features = ["http-client", "server"] }
sov-rollup-interface = { path = "../../rollup-interface" }

sov-evm = { path = "../../module-system/module-implementations/sov-evm" }
demo-stf = { path = "../../examples/demo-stf", features = ["native"] }
sov-modules-api = { path = "../../module-system/sov-modules-api" }

borsh = { workspace = true }
serde_json = { workspace = true }

reth-primitives = { workspace = true }
reth-rpc-types = { workspace = true }
reth-interfaces = { workspace = true }

schnellru = "0.2.1"

[dev-dependencies]
sov-rollup-interface = { path = "../../rollup-interface", features = ["mocks"] }
tokio = { workspace = true }


[features]
default = []
local = []
experimental = ["demo-stf/experimental", "sov-evm/experimental", "local"]
native = ["demo-stf/native", "sov-evm/native"]
48 changes: 48 additions & 0 deletions full-node/sov-ethereum-gas-price/src/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::sync::Mutex;

use reth_primitives::H256;
use reth_rpc_types::{Block, Rich};
use schnellru::{ByLength, LruMap};
use sov_evm::EthResult;
use sov_modules_api::WorkingSet;

/// Block cache for gas oracle
pub struct BlockCache<C: sov_modules_api::Context> {
cache: Mutex<LruMap<H256, Rich<Block>, ByLength>>,
provider: sov_evm::Evm<C>,
}

impl<C: sov_modules_api::Context> BlockCache<C> {
pub fn new(max_size: u32, provider: sov_evm::Evm<C>) -> Self {
Self {
cache: Mutex::new(LruMap::new(ByLength::new(max_size))),
provider,
}
}

/// Gets block from cache or from provider
pub fn get_block(
&self,
block_hash: H256,
working_set: &mut WorkingSet<C>,
) -> EthResult<Option<Rich<Block>>> {
// Check if block is in cache
let mut cache = self.cache.lock().unwrap();
if let Some(block) = cache.get(&block_hash) {
return Ok(Some(block.clone()));
}

// Get block from provider
let block = self
.provider
.get_block_by_hash(block_hash.into(), Some(true), working_set)
.unwrap_or(None);

// Add block to cache if it exists
if let Some(block) = &block {
cache.insert(block_hash, block.clone());
}

Ok(block)
}
}
Loading