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: Allow DA blobs with multiple transactions. #767

Merged
merged 9 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions examples/demo-rollup/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use celestia::types::NamespaceId;
use const_rollup_config::ROLLUP_NAMESPACE_RAW;
use demo_stf::genesis_config::create_demo_genesis_config;
use demo_stf::runtime::GenesisConfig;
#[cfg(feature = "experimental")]
pub use rollup::read_tx_signer_priv_key;
pub use rollup::{new_rollup_with_celestia_da, Rollup};
use sov_cli::wallet_state::{HexPrivateAndAddress, PrivateKeyAndAddress};
use sov_db::ledger_db::LedgerDB;
Expand Down
20 changes: 4 additions & 16 deletions examples/demo-rollup/src/register_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ use anyhow::Context;
use celestia::verifier::address::CelestiaAddress;
use demo_stf::app::App;
use sov_db::ledger_db::LedgerDB;
#[cfg(feature = "experimental")]
use sov_ethereum::experimental::EthRpcConfig;
use sov_modules_stf_template::{SequencerOutcome, TxEffect};
use sov_rollup_interface::services::da::DaService;
use sov_rollup_interface::zk::Zkvm;
use sov_sequencer::get_sequencer_rpc;
use sov_stf_runner::get_ledger_rpc;

#[cfg(feature = "experimental")]
const TX_SIGNER_PRIV_KEY_PATH: &str = "../test-data/keys/tx_signer_private_key.json";

/// register sequencer rpc methods.
pub fn register_sequencer<Vm, DA>(
da_service: DA,
Expand Down Expand Up @@ -45,22 +44,11 @@ pub fn register_ledger(
/// register ethereum methods.
pub fn register_ethereum<DA: DaService>(
da_service: DA,
eth_rpc_config: EthRpcConfig,
methods: &mut jsonrpsee::RpcModule<()>,
) -> Result<(), anyhow::Error> {
use std::fs;

let data = fs::read_to_string(TX_SIGNER_PRIV_KEY_PATH).context("Unable to read file")?;

let hex_key: sov_cli::wallet_state::HexPrivateAndAddress =
serde_json::from_str(&data).context("JSON does not have a correct format.")?;

let key_and_address: sov_cli::wallet_state::PrivateKeyAndAddress<
sov_modules_api::default_context::DefaultContext,
> = hex_key
.try_into()
.expect("Failed to parse sequencer private key and address");
let ethereum_rpc = sov_ethereum::get_ethereum_rpc(da_service, eth_rpc_config);

let ethereum_rpc = sov_ethereum::get_ethereum_rpc(da_service, key_and_address.private_key);
methods
.merge(ethereum_rpc)
.context("Failed to merge Ethereum RPC modules")
Expand Down
33 changes: 32 additions & 1 deletion examples/demo-rollup/src/rollup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ use celestia::verifier::address::CelestiaAddress;
use celestia::verifier::RollupParams;
use celestia::CelestiaService;
use const_rollup_config::SEQUENCER_DA_ADDRESS;
#[cfg(feature = "experimental")]
use demo_stf::app::DefaultPrivateKey;
use demo_stf::app::{App, DefaultContext};
use demo_stf::runtime::{get_rpc_methods, GenesisConfig};
use risc0_adapter::host::Risc0Verifier;
use sov_db::ledger_db::LedgerDB;
#[cfg(feature = "experimental")]
use sov_ethereum::experimental::EthRpcConfig;
use sov_rollup_interface::services::da::DaService;
use sov_rollup_interface::zk::Zkvm;
use sov_state::storage::Storage;
Expand All @@ -22,6 +26,9 @@ use crate::register_rpc::register_ethereum;
use crate::register_rpc::{register_ledger, register_sequencer};
use crate::{get_genesis_config, initialize_ledger, ROLLUP_NAMESPACE};

#[cfg(feature = "experimental")]
const TX_SIGNER_PRIV_KEY_PATH: &str = "../test-data/keys/tx_signer_private_key.json";

/// Dependencies needed to run the rollup.
pub struct Rollup<Vm: Zkvm, DA: DaService + Clone> {
/// Implementation of the STF.
Expand All @@ -34,6 +41,9 @@ pub struct Rollup<Vm: Zkvm, DA: DaService + Clone> {
pub runner_config: RunnerConfig,
/// Initial rollup configuration.
pub genesis_config: GenesisConfig<DefaultContext>,
#[cfg(feature = "experimental")]
/// Configuration for the Ethereum RPC.
pub eth_rpc_config: EthRpcConfig,
}

/// Creates celestia based rollup.
Expand Down Expand Up @@ -64,9 +74,30 @@ pub async fn new_rollup_with_celestia_da(
ledger_db,
runner_config: rollup_config.runner,
genesis_config,
#[cfg(feature = "experimental")]
eth_rpc_config: EthRpcConfig {
min_blob_size: Some(1),
tx_signer_priv_key: read_tx_signer_priv_key()?,
},
})
}

#[cfg(feature = "experimental")]
/// Ethereum RPC wraps EVM transaction in a rollup transaction.
/// This function reads the private key of the rollup transaction signer.
pub fn read_tx_signer_priv_key() -> Result<DefaultPrivateKey, anyhow::Error> {
let data = std::fs::read_to_string(TX_SIGNER_PRIV_KEY_PATH).context("Unable to read file")?;

let hex_key: crate::HexPrivateAndAddress =
serde_json::from_str(&data).context("JSON does not have correct format.")?;

let priv_key = sov_modules_api::default_signature::private_key::DefaultPrivateKey::from_hex(
&hex_key.hex_priv_key,
)?;

Ok(priv_key)
}

impl<Vm: Zkvm, DA: DaService<Error = anyhow::Error> + Clone> Rollup<Vm, DA> {
/// Runs the rollup.
pub async fn run(self) -> Result<(), anyhow::Error> {
Expand All @@ -86,7 +117,7 @@ impl<Vm: Zkvm, DA: DaService<Error = anyhow::Error> + Clone> Rollup<Vm, DA> {
register_ledger(self.ledger_db.clone(), &mut methods)?;
register_sequencer(self.da_service.clone(), &mut self.app, &mut methods)?;
#[cfg(feature = "experimental")]
register_ethereum(self.da_service.clone(), &mut methods)?;
register_ethereum(self.da_service.clone(), self.eth_rpc_config, &mut methods)?;
}

let storage = self.app.get_storage();
Expand Down
169 changes: 114 additions & 55 deletions examples/demo-rollup/tests/evm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
use std::net::SocketAddr;
use std::str::FromStr;

use ethereum_types::H160;
use ethers_core::abi::Address;
use ethers_core::k256::ecdsa::SigningKey;
use ethers_core::types::transaction::eip2718::TypedTransaction;
use ethers_core::types::Eip1559TransactionRequest;
use ethers_middleware::SignerMiddleware;
use ethers_providers::{Http, Middleware, Provider};
use ethers_providers::{Http, Middleware, PendingTransaction, Provider};
use ethers_signers::{LocalWallet, Signer, Wallet};
use jsonrpsee::core::client::ClientT;
use jsonrpsee::http_client::{HttpClient, HttpClientBuilder};
use jsonrpsee::rpc_params;
use sov_evm::smart_contracts::SimpleStorageContract;

use super::test_helpers::start_rollup;
Expand All @@ -19,6 +23,7 @@ struct TestClient {
from_addr: Address,
contract: SimpleStorageContract,
client: SignerMiddleware<Provider<Http>, Wallet<SigningKey>>,
http_client: HttpClient,
}

impl TestClient {
Expand All @@ -30,86 +35,141 @@ impl TestClient {
contract: SimpleStorageContract,
rpc_addr: std::net::SocketAddr,
) -> Self {
let provider =
Provider::try_from(&format!("http://localhost:{}", rpc_addr.port())).unwrap();
let host = format!("http://localhost:{}", rpc_addr.port());

let provider = Provider::try_from(&host).unwrap();
let client = SignerMiddleware::new_with_provider_chain(provider, key)
.await
.unwrap();

let http_client = HttpClientBuilder::default().build(host).unwrap();

Self {
chain_id,
from_addr,
contract,
client,
http_client,
}
}

async fn execute(self) -> Result<(), Box<dyn std::error::Error>> {
// Deploy contract
async fn send_publish_batch_request(&self) {
let _: String = self
.http_client
.request("eth_publishBatch", rpc_params![])
.await
.unwrap();
}

async fn deploy_contract(
&self,
) -> Result<PendingTransaction<'_, Http>, Box<dyn std::error::Error>> {
let req = Eip1559TransactionRequest::new()
.from(self.from_addr)
.chain_id(self.chain_id)
.nonce(0u64)
.max_priority_fee_per_gas(10u64)
.max_fee_per_gas(MAX_FEE_PER_GAS)
.gas(900000u64)
.data(self.contract.byte_code());

let typed_transaction = TypedTransaction::Eip1559(req);

let receipt_req = self
.client
.send_transaction(typed_transaction, None)
.await?;

Ok(receipt_req)
}

async fn set_value(
&self,
contract_address: H160,
set_arg: u32,
nonce: u64,
) -> PendingTransaction<'_, Http> {
let req = Eip1559TransactionRequest::new()
.from(self.from_addr)
.to(contract_address)
.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)
.gas(900000u64);

let typed_transaction = TypedTransaction::Eip1559(req);

self.client
.send_transaction(typed_transaction, None)
.await
.unwrap()
}

async fn query_contract(
&self,
contract_address: H160,
nonce: u64,
) -> Result<ethereum_types::U256, Box<dyn std::error::Error>> {
let req = Eip1559TransactionRequest::new()
.from(self.from_addr)
.to(contract_address)
.chain_id(self.chain_id)
.nonce(nonce)
.data(self.contract.get_call_data())
.gas(900000u64);

let typed_transaction = TypedTransaction::Eip1559(req);

let response = self.client.call(&typed_transaction, None).await?;

let resp_array: [u8; 32] = response.to_vec().try_into().unwrap();
Ok(ethereum_types::U256::from(resp_array))
}

async fn execute(self) -> Result<(), Box<dyn std::error::Error>> {
let contract_address = {
let request = Eip1559TransactionRequest::new()
.from(self.from_addr)
.chain_id(self.chain_id)
.nonce(0u64)
.max_priority_fee_per_gas(10u64)
.max_fee_per_gas(MAX_FEE_PER_GAS)
.gas(900000u64)
.data(self.contract.byte_code());

let typed_transaction = TypedTransaction::Eip1559(request);

let receipt = self
.client
.send_transaction(typed_transaction, None)
.await?
.await?;
let deploy_contract_req = self.deploy_contract().await?;
self.send_publish_batch_request().await;

receipt.unwrap().contract_address.unwrap()
deploy_contract_req
.await?
.unwrap()
.contract_address
.unwrap()
};

// Call contract
let set_arg = 923;
{
let request = Eip1559TransactionRequest::new()
.from(self.from_addr)
.to(contract_address)
.chain_id(self.chain_id)
.nonce(1u64)
.data(self.contract.set_call_data(set_arg))
.max_priority_fee_per_gas(10u64)
.max_fee_per_gas(MAX_FEE_PER_GAS)
.gas(900000u64);

let typed_transaction = TypedTransaction::Eip1559(request);

let _ = self
.client
.send_transaction(typed_transaction, None)
.await
.unwrap()
.await;
let set_value_req = self.set_value(contract_address, set_arg, 1).await;
self.send_publish_batch_request().await;
set_value_req.await.unwrap();
}

// Query contract
{
let request = Eip1559TransactionRequest::new()
.from(self.from_addr)
.to(contract_address)
.chain_id(self.chain_id)
.nonce(2u64)
.data(self.contract.get_call_data())
.gas(900000u64);
let get_arg = self.query_contract(contract_address, 2).await?;
assert_eq!(set_arg, get_arg.as_u32());
}

let typed_transaction = TypedTransaction::Eip1559(request);
// Create a blob with multiple transactions.
let mut requests = Vec::default();
let mut nonce = 2;
for value in 100..103 {
let set_value_req = self.set_value(contract_address, value, nonce).await;
requests.push(set_value_req);
nonce += 1
}

let response = self.client.call(&typed_transaction, None).await?;
self.send_publish_batch_request().await;

let resp_array: [u8; 32] = response.to_vec().try_into().unwrap();
let get_arg = ethereum_types::U256::from(resp_array);
for req in requests {
req.await.unwrap();
}

assert_eq!(set_arg, get_arg.as_u32())
{
let get_arg = self.query_contract(contract_address, nonce).await?;
assert_eq!(102, get_arg.as_u32());
}

Ok(())
Expand All @@ -124,7 +184,6 @@ async fn send_tx_test_to_eth(rpc_address: SocketAddr) -> Result<(), Box<dyn std:
.with_chain_id(chain_id);

let contract = SimpleStorageContract::default();

let from_addr = Address::from_str("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266").unwrap();

let test_client = TestClient::new(chain_id, key, from_addr, contract, rpc_address).await;
Expand Down
9 changes: 8 additions & 1 deletion examples/demo-rollup/tests/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::net::SocketAddr;
use demo_stf::app::App;
use risc0_adapter::host::Risc0Verifier;
use sov_demo_rollup::{get_genesis_config, initialize_ledger, Rollup};
#[cfg(feature = "experimental")]
use sov_ethereum::experimental::EthRpcConfig;
use sov_rollup_interface::mocks::{MockAddress, MockDaService};
use sov_stf_runner::{RollupConfig, RpcConfig, RunnerConfig, StorageConfig};
use tokio::sync::oneshot;
Expand All @@ -15,7 +17,6 @@ fn create_mock_da_rollup(rollup_config: RollupConfig<()>) -> Rollup<Risc0Verifie
let da_service = MockDaService::new(sequencer_da_address);

let app = App::new(rollup_config.storage);

let genesis_config = get_genesis_config(sequencer_da_address);

Rollup {
Expand All @@ -24,6 +25,12 @@ fn create_mock_da_rollup(rollup_config: RollupConfig<()>) -> Rollup<Risc0Verifie
ledger_db,
runner_config: rollup_config.runner,
genesis_config,
#[cfg(feature = "experimental")]
eth_rpc_config: EthRpcConfig {
min_blob_size: None,
tx_signer_priv_key: sov_demo_rollup::read_tx_signer_priv_key()
.expect("Unable to read signer private key"),
},
}
}

Expand Down
Loading