From 6c97c2007d9da9c8e01f53f19f14a1df0541060d Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Tue, 19 Sep 2023 16:50:00 +0300 Subject: [PATCH 01/16] feature gate DevSigner --- examples/demo-rollup/Cargo.toml | 1 + examples/demo-rollup/src/rollup.rs | 2 ++ examples/demo-rollup/tests/evm/mod.rs | 8 ++++++-- full-node/sov-ethereum/Cargo.toml | 1 + full-node/sov-ethereum/src/lib.rs | 4 +++- 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/examples/demo-rollup/Cargo.toml b/examples/demo-rollup/Cargo.toml index cd2ef22fe..ba14b2f36 100644 --- a/examples/demo-rollup/Cargo.toml +++ b/examples/demo-rollup/Cargo.toml @@ -70,6 +70,7 @@ revm = { workspace = true } [features] default = [] experimental = ["sov-ethereum/experimental", "reth-primitives", "secp256k1", "demo-stf/experimental"] +local = ["sov-ethereum/local"] [[bench]] name = "rollup_bench" diff --git a/examples/demo-rollup/src/rollup.rs b/examples/demo-rollup/src/rollup.rs index 6e32f9500..255b98907 100644 --- a/examples/demo-rollup/src/rollup.rs +++ b/examples/demo-rollup/src/rollup.rs @@ -150,6 +150,7 @@ pub async fn new_rollup_with_celestia_da( eth_rpc_config: EthRpcConfig { min_blob_size: Some(1), sov_tx_signer_priv_key: read_sov_tx_signer_priv_key()?, + #[cfg(feature = "local")] eth_signer, }, prover, @@ -198,6 +199,7 @@ pub fn new_rollup_with_mock_da_from_config( eth_rpc_config: EthRpcConfig { min_blob_size: Some(1), sov_tx_signer_priv_key: read_sov_tx_signer_priv_key()?, + #[cfg(feature = "local")] eth_signer, }, prover, diff --git a/examples/demo-rollup/tests/evm/mod.rs b/examples/demo-rollup/tests/evm/mod.rs index cdbcd1111..40e455776 100644 --- a/examples/demo-rollup/tests/evm/mod.rs +++ b/examples/demo-rollup/tests/evm/mod.rs @@ -129,6 +129,7 @@ impl TestClient { Ok(ethereum_types::U256::from(resp_array)) } + #[cfg(feature = "local")] async fn eth_accounts(&self) -> Vec
{ self.http_client .request("eth_accounts", rpc_params![]) @@ -238,8 +239,11 @@ async fn send_tx_test_to_eth(rpc_address: SocketAddr) -> Result<(), Box, pub sov_tx_signer_priv_key: DefaultPrivateKey, - //TODO #839 + #[cfg(feature = "local")] pub eth_signer: DevSigner, } @@ -174,6 +175,7 @@ pub mod experimental { }, )?; + #[cfg(feature = "local")] rpc.register_async_method("eth_accounts", |_parameters, ethereum| async move { Ok::<_, ErrorObjectOwned>(ethereum.eth_rpc_config.eth_signer.signers()) })?; From fdd02815200c2c116a9bf03efc1304bbea145393 Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Wed, 20 Sep 2023 12:11:59 +0300 Subject: [PATCH 02/16] ethers signer on devsigner --- examples/demo-rollup/tests/evm/mod.rs | 42 +++++++++++++++++- full-node/sov-ethereum/src/lib.rs | 43 ++++++++++++++++--- .../sov-evm/src/signer/mod.rs | 20 +++++++++ 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/examples/demo-rollup/tests/evm/mod.rs b/examples/demo-rollup/tests/evm/mod.rs index 40e455776..ea9d7aacc 100644 --- a/examples/demo-rollup/tests/evm/mod.rs +++ b/examples/demo-rollup/tests/evm/mod.rs @@ -84,6 +84,22 @@ impl TestClient { Ok(receipt_req) } + async fn set_value_unsigned(&self, contract_address: H160, set_arg: u32, nonce: u64) -> TxHash { + 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.eth_send_transaction(typed_transaction).await + } + async fn set_value( &self, contract_address: H160, @@ -137,6 +153,14 @@ impl TestClient { .unwrap() } + #[cfg(feature = "local")] + async fn eth_send_transaction(&self, tx: TypedTransaction) -> TxHash { + self.http_client + .request("eth_sendTransaction", rpc_params![tx]) + .await + .unwrap() + } + async fn eth_chain_id(&self) -> u64 { let chain_id: ethereum_types::U64 = self .http_client @@ -222,6 +246,22 @@ impl TestClient { assert_eq!(102, get_arg.as_u32()); } + #[cfg(feature = "local")] + { + let value = 103; + + let tx_hash = self.set_value_raw(contract_address, value, nonce).await; + self.send_publish_batch_request().await; + + let latest_block = self.eth_get_block_by_number(None).await; + assert_eq!(latest_block.transactions.len(), 1); + assert_eq!(latest_block.transactions[0], tx_hash); + + let get_arg = self.query_contract(contract_address, nonce).await?; + // FIXME: Transaction is not failing but the value is not set + assert_eq!(value, get_arg.as_u32()); + } + Ok(()) } } @@ -239,7 +279,7 @@ async fn send_tx_test_to_eth(rpc_address: SocketAddr) -> Result<(), Box(ethereum.eth_rpc_config.eth_signer.signers()) })?; - // TODO https://github.com/Sovereign-Labs/sovereign-sdk/issues/502 - rpc.register_async_method("eth_sendTransaction", |parameters, _ethereum| async move { - let _data: reth_rpc_types::TransactionRequest = parameters.one().unwrap(); - unimplemented!("eth_sendTransaction not implemented") + #[cfg(feature = "local")] + rpc.register_async_method("eth_sendTransaction", |parameters, ethereum| async move { + let typed_transaction: TypedTransaction = parameters.one().unwrap(); + + let signed_tx = ethereum + .eth_rpc_config + .eth_signer + .sign_ethers_transaction(typed_transaction) + .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; + + let raw_evm_tx = RlpEvmTransaction { + rlp: signed_tx.to_vec(), + }; + + let (tx_hash, raw_tx) = ethereum + .make_raw_tx(raw_evm_tx) + .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; + + let blob = ethereum + .batch_builder + .lock() + .unwrap() + .add_transactions_and_get_next_blob( + ethereum.eth_rpc_config.min_blob_size, + vec![raw_tx], + ); + + if !blob.is_empty() { + ethereum + .submit_batch(blob) + .await + .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; + } + + Ok::<_, ErrorObjectOwned>(tx_hash) })?; Ok(()) diff --git a/module-system/module-implementations/sov-evm/src/signer/mod.rs b/module-system/module-implementations/sov-evm/src/signer/mod.rs index c98fde337..e41c7ec87 100644 --- a/module-system/module-implementations/sov-evm/src/signer/mod.rs +++ b/module-system/module-implementations/sov-evm/src/signer/mod.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; +use ethers_core::types::{transaction::eip2718::TypedTransaction, Bytes, Signature}; use reth_primitives::{sign_message, Address, Transaction, TransactionSigned, H256}; use secp256k1::{PublicKey, SecretKey}; @@ -57,6 +58,25 @@ impl DevSigner { )) } + pub fn sign_ethers_transaction( + &self, + transaction: TypedTransaction, + ) -> Result { + let from = reth_primitives::H160(transaction.from().ok_or(SignError::NoAccount)?.0); + let signer = self.signers.get(&from).ok_or(SignError::NoAccount)?; + + let tx_signature_hash = transaction.sighash(); + let signature = sign_message(H256::from_slice(signer.as_ref()), tx_signature_hash.into()) + .map_err(|_| SignError::CouldNotSign)?; + + let chain_id = transaction.chain_id().map(|id| id.as_u64()).unwrap_or(1); + Ok(transaction.rlp_signed(&Signature { + r: signature.r.into(), + s: signature.s.into(), + v: signature.v(Some(chain_id)).into(), + })) + } + pub fn signers(&self) -> Vec
{ self.signers.keys().copied().collect() } From 1ec814f6eddd497ed02bacf85d78366367255f28 Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Wed, 20 Sep 2023 12:29:21 +0300 Subject: [PATCH 03/16] update branch --- examples/demo-rollup/tests/evm/mod.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/demo-rollup/tests/evm/mod.rs b/examples/demo-rollup/tests/evm/mod.rs index 1da589584..bc14a78ec 100644 --- a/examples/demo-rollup/tests/evm/mod.rs +++ b/examples/demo-rollup/tests/evm/mod.rs @@ -84,7 +84,9 @@ impl TestClient { Ok(receipt_req) } - async fn set_value_unsigned(&self, contract_address: H160, set_arg: u32, nonce: u64) -> TxHash { + async fn set_value_unsigned(&self, contract_address: H160, set_arg: u32) -> TxHash { + let nonce = self.eth_get_transaction_count(self.from_addr).await; + let req = Eip1559TransactionRequest::new() .from(self.from_addr) .to(contract_address) @@ -268,14 +270,14 @@ impl TestClient { { let value = 103; - let tx_hash = self.set_value_raw(contract_address, value, nonce).await; + let tx_hash = self.set_value_unsigned(contract_address, value).await; self.send_publish_batch_request().await; let latest_block = self.eth_get_block_by_number(None).await; assert_eq!(latest_block.transactions.len(), 1); assert_eq!(latest_block.transactions[0], tx_hash); - let get_arg = self.query_contract(contract_address, nonce).await?; + let get_arg = self.query_contract(contract_address).await?; // FIXME: Transaction is not failing but the value is not set assert_eq!(value, get_arg.as_u32()); } From b461c4e5bef75d03b85bda1e3cb1468c5a73020e Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Wed, 20 Sep 2023 15:16:44 +0300 Subject: [PATCH 04/16] access storage in sov-ethereum rpc --- examples/demo-rollup/src/register_rpc.rs | 5 +- examples/demo-rollup/src/rollup.rs | 10 +- full-node/sov-ethereum/src/lib.rs | 91 +++++++++++++++---- .../sov-evm/src/signer/mod.rs | 20 +--- 4 files changed, 87 insertions(+), 39 deletions(-) diff --git a/examples/demo-rollup/src/register_rpc.rs b/examples/demo-rollup/src/register_rpc.rs index c1b862ef1..57d1a340b 100644 --- a/examples/demo-rollup/src/register_rpc.rs +++ b/examples/demo-rollup/src/register_rpc.rs @@ -42,12 +42,13 @@ pub fn register_ledger( #[cfg(feature = "experimental")] /// register ethereum methods. -pub fn register_ethereum( +pub fn register_ethereum( da_service: Da, eth_rpc_config: EthRpcConfig, + storage: C::Storage, methods: &mut jsonrpsee::RpcModule<()>, ) -> Result<(), anyhow::Error> { - let ethereum_rpc = sov_ethereum::get_ethereum_rpc(da_service, eth_rpc_config); + let ethereum_rpc = sov_ethereum::get_ethereum_rpc::(da_service, eth_rpc_config, storage); methods .merge(ethereum_rpc) diff --git a/examples/demo-rollup/src/rollup.rs b/examples/demo-rollup/src/rollup.rs index ae868deff..cada6a724 100644 --- a/examples/demo-rollup/src/rollup.rs +++ b/examples/demo-rollup/src/rollup.rs @@ -19,6 +19,7 @@ use sov_db::ledger_db::LedgerDB; #[cfg(feature = "experimental")] use sov_ethereum::experimental::EthRpcConfig; use sov_modules_api::default_context::ZkDefaultContext; +use sov_modules_api::DaSpec; use sov_modules_stf_template::AppTemplate; use sov_rollup_interface::da::DaVerifier; use sov_rollup_interface::mocks::{MockAddress, MockDaConfig, MockDaService}; @@ -240,14 +241,19 @@ impl + Clone> Rollup channel: Option>, ) -> Result<(), anyhow::Error> { let storage = self.app.get_storage(); - let mut methods = get_rpc_methods::(storage); + let mut methods = get_rpc_methods::(storage.clone()); // register rpc methods { 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(), self.eth_rpc_config, &mut methods)?; + register_ethereum::( + self.da_service.clone(), + self.eth_rpc_config, + storage, + &mut methods, + )?; } let storage = self.app.get_storage(); diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index e32a925f1..e765f91d4 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -18,14 +18,15 @@ pub mod experimental { use jsonrpsee::types::ErrorObjectOwned; use jsonrpsee::RpcModule; use reth_primitives::{ - Address as RethAddress, TransactionSignedNoHash as RethTransactionSignedNoHash, + Address as RethAddress, TransactionSignedNoHash as RethTransactionSignedNoHash, U256, }; - use reth_rpc_types::TypedTransactionRequest; + use reth_rpc_types::{TransactionRequest, TypedTransactionRequest}; use sov_evm::call::CallMessage; use sov_evm::evm::RlpEvmTransaction; + use sov_evm::Evm; use sov_modules_api::transaction::Transaction; use sov_modules_api::utils::to_jsonrpsee_error_object; - use sov_modules_api::EncodeCall; + use sov_modules_api::{EncodeCall, WorkingSet}; use sov_rollup_interface::services::da::DaService; use super::batch_builder::EthBatchBuilder; @@ -41,45 +42,50 @@ pub mod experimental { pub eth_signer: DevSigner, } - pub fn get_ethereum_rpc( + pub fn get_ethereum_rpc( da_service: Da, eth_rpc_config: EthRpcConfig, - ) -> RpcModule> { + storage: C::Storage, + ) -> RpcModule> { let mut rpc = RpcModule::new(Ethereum::new( Default::default(), da_service, Arc::new(Mutex::new(EthBatchBuilder::default())), eth_rpc_config, + storage, )); register_rpc_methods(&mut rpc).expect("Failed to register sequencer RPC methods"); rpc } - pub struct Ethereum { + pub struct Ethereum { nonces: Mutex>, da_service: Da, batch_builder: Arc>, eth_rpc_config: EthRpcConfig, + storage: C::Storage, } - impl Ethereum { + impl Ethereum { fn new( nonces: Mutex>, da_service: Da, batch_builder: Arc>, eth_rpc_config: EthRpcConfig, + storage: C::Storage, ) -> Self { Self { nonces, da_service, batch_builder, eth_rpc_config, + storage, } } } - impl Ethereum { + impl Ethereum { fn make_raw_tx( &self, raw_tx: RlpEvmTransaction, @@ -121,8 +127,8 @@ pub mod experimental { } } - fn register_rpc_methods( - rpc: &mut RpcModule>, + fn register_rpc_methods( + rpc: &mut RpcModule>, ) -> Result<(), jsonrpsee::core::Error> { rpc.register_async_method("eth_publishBatch", |params, ethereum| async move { let mut params_iter = params.sequence(); @@ -184,22 +190,76 @@ pub mod experimental { #[cfg(feature = "local")] rpc.register_async_method("eth_sendTransaction", |parameters, ethereum| async move { - let typed_transaction: TypedTransaction = parameters.one().unwrap(); + let mut transaction_request: TransactionRequest = parameters.one().unwrap(); + + let working_set = WorkingSet::::new(ethereum.storage.clone()); + let evm = Evm::::default(); + + // get from, return error if none + let from = transaction_request + .from + .ok_or(to_jsonrpsee_error_object("No from address", ETH_RPC_ERROR))?; + + // return error if not in signers + if !ethereum.eth_rpc_config.eth_signer.signers().contains(&from) { + return Err(to_jsonrpsee_error_object( + "From address not in signers", + ETH_RPC_ERROR, + )); + } + + if transaction_request.nonce.is_none() { + let nonce = evm + .get_transaction_count(from, None, &mut working_set) + .unwrap_or_default(); + + transaction_request.nonce = Some(reth_primitives::U256::from(nonce.as_u64())); + } + + let chain_id = evm + .chain_id(&mut working_set) + .expect("Failed to get chain id") + .map(|id| id.as_u64()) + .unwrap_or(1); + + // TODO: implement gas logic after gas estimation is implemented + let transaction_request = match transaction_request.into_typed_request() { + Some(TypedTransactionRequest::Legacy(mut m)) => { + m.chain_id = Some(chain_id); + + TypedTransactionRequest::Legacy(m) + } + Some(TypedTransactionRequest::EIP2930(mut m)) => { + m.chain_id = chain_id; + + TypedTransactionRequest::EIP2930(m) + } + Some(TypedTransactionRequest::EIP1559(mut m)) => { + m.chain_id = chain_id; + + TypedTransactionRequest::EIP1559(m) + } + None => { + // to_jsonrpsee_error_object("Conflicting fee fields", ETH_RPC_ERROR)?; + return Err(to_jsonrpsee_error_object( + "Conflicting fee fields", + ETH_RPC_ERROR, + )); + } + }; let signed_tx = ethereum .eth_rpc_config .eth_signer - .sign_ethers_transaction(typed_transaction) + .sign_transaction(transaction_request.into_transaction(), from) .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; let raw_evm_tx = RlpEvmTransaction { - rlp: signed_tx.to_vec(), + rlp: signed_tx.envelope_encoded().to_vec(), }; - let (tx_hash, raw_tx) = ethereum .make_raw_tx(raw_evm_tx) .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - let blob = ethereum .batch_builder .lock() @@ -208,7 +268,6 @@ pub mod experimental { ethereum.eth_rpc_config.min_blob_size, vec![raw_tx], ); - if !blob.is_empty() { ethereum .submit_batch(blob) diff --git a/module-system/module-implementations/sov-evm/src/signer/mod.rs b/module-system/module-implementations/sov-evm/src/signer/mod.rs index e41c7ec87..bda96a549 100644 --- a/module-system/module-implementations/sov-evm/src/signer/mod.rs +++ b/module-system/module-implementations/sov-evm/src/signer/mod.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use ethers_core::types::{transaction::eip2718::TypedTransaction, Bytes, Signature}; use reth_primitives::{sign_message, Address, Transaction, TransactionSigned, H256}; +use reth_rpc_types::TypedTransactionRequest; use secp256k1::{PublicKey, SecretKey}; /// Ethereum transaction signer. @@ -58,25 +59,6 @@ impl DevSigner { )) } - pub fn sign_ethers_transaction( - &self, - transaction: TypedTransaction, - ) -> Result { - let from = reth_primitives::H160(transaction.from().ok_or(SignError::NoAccount)?.0); - let signer = self.signers.get(&from).ok_or(SignError::NoAccount)?; - - let tx_signature_hash = transaction.sighash(); - let signature = sign_message(H256::from_slice(signer.as_ref()), tx_signature_hash.into()) - .map_err(|_| SignError::CouldNotSign)?; - - let chain_id = transaction.chain_id().map(|id| id.as_u64()).unwrap_or(1); - Ok(transaction.rlp_signed(&Signature { - r: signature.r.into(), - s: signature.s.into(), - v: signature.v(Some(chain_id)).into(), - })) - } - pub fn signers(&self) -> Vec
{ self.signers.keys().copied().collect() } From aef1cc748594b2f055c7673f9728c99c20b49a99 Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Wed, 20 Sep 2023 15:20:00 +0300 Subject: [PATCH 05/16] remove unnecessary imports --- examples/demo-rollup/src/rollup.rs | 1 - full-node/sov-ethereum/src/lib.rs | 5 ++--- .../module-implementations/sov-evm/src/signer/mod.rs | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/examples/demo-rollup/src/rollup.rs b/examples/demo-rollup/src/rollup.rs index cada6a724..8586bc472 100644 --- a/examples/demo-rollup/src/rollup.rs +++ b/examples/demo-rollup/src/rollup.rs @@ -19,7 +19,6 @@ use sov_db::ledger_db::LedgerDB; #[cfg(feature = "experimental")] use sov_ethereum::experimental::EthRpcConfig; use sov_modules_api::default_context::ZkDefaultContext; -use sov_modules_api::DaSpec; use sov_modules_stf_template::AppTemplate; use sov_rollup_interface::da::DaVerifier; use sov_rollup_interface::mocks::{MockAddress, MockDaConfig, MockDaService}; diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index e765f91d4..bf0162233 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -13,12 +13,11 @@ pub mod experimental { use borsh::ser::BorshSerialize; use demo_stf::app::DefaultPrivateKey; use demo_stf::runtime::{DefaultContext, Runtime}; - use ethers::types::transaction::eip2718::TypedTransaction; - use ethers::types::{Bytes, H160, H256}; + use ethers::types::{Bytes, H256}; use jsonrpsee::types::ErrorObjectOwned; use jsonrpsee::RpcModule; use reth_primitives::{ - Address as RethAddress, TransactionSignedNoHash as RethTransactionSignedNoHash, U256, + Address as RethAddress, TransactionSignedNoHash as RethTransactionSignedNoHash, }; use reth_rpc_types::{TransactionRequest, TypedTransactionRequest}; use sov_evm::call::CallMessage; diff --git a/module-system/module-implementations/sov-evm/src/signer/mod.rs b/module-system/module-implementations/sov-evm/src/signer/mod.rs index bda96a549..afe63c6e8 100644 --- a/module-system/module-implementations/sov-evm/src/signer/mod.rs +++ b/module-system/module-implementations/sov-evm/src/signer/mod.rs @@ -1,8 +1,5 @@ use std::collections::HashMap; - -use ethers_core::types::{transaction::eip2718::TypedTransaction, Bytes, Signature}; use reth_primitives::{sign_message, Address, Transaction, TransactionSigned, H256}; -use reth_rpc_types::TypedTransactionRequest; use secp256k1::{PublicKey, SecretKey}; /// Ethereum transaction signer. From 11e2d657e6c09022602f9a7d9cb4f02d7a66d5ad Mon Sep 17 00:00:00 2001 From: bkolad Date: Wed, 20 Sep 2023 16:41:14 +0200 Subject: [PATCH 06/16] cargo fmt --- Cargo.lock | 4 ++-- .../module-implementations/sov-evm/src/signer/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e4e103cd..5b980dbdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,9 +88,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2135563fb5c609d2b2b87c1e8ce7bc41b0b45430fa9661f457981503dd5bf0" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" dependencies = [ "memchr", ] diff --git a/module-system/module-implementations/sov-evm/src/signer/mod.rs b/module-system/module-implementations/sov-evm/src/signer/mod.rs index afe63c6e8..ff7e50f4e 100644 --- a/module-system/module-implementations/sov-evm/src/signer/mod.rs +++ b/module-system/module-implementations/sov-evm/src/signer/mod.rs @@ -1,6 +1,6 @@ -use std::collections::HashMap; use reth_primitives::{sign_message, Address, Transaction, TransactionSigned, H256}; use secp256k1::{PublicKey, SecretKey}; +use std::collections::HashMap; /// Ethereum transaction signer. pub struct DevSigner { From 4a6e9b14042b265ede3343ff993f5cd6a319d0d6 Mon Sep 17 00:00:00 2001 From: bkolad Date: Wed, 20 Sep 2023 16:48:25 +0200 Subject: [PATCH 07/16] fix compilation problems --- full-node/sov-ethereum/src/lib.rs | 90 ++++++++++++++++--------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index bf0162233..d15a458f3 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -191,7 +191,6 @@ pub mod experimental { rpc.register_async_method("eth_sendTransaction", |parameters, ethereum| async move { let mut transaction_request: TransactionRequest = parameters.one().unwrap(); - let working_set = WorkingSet::::new(ethereum.storage.clone()); let evm = Evm::::default(); // get from, return error if none @@ -207,54 +206,57 @@ pub mod experimental { )); } - if transaction_request.nonce.is_none() { - let nonce = evm - .get_transaction_count(from, None, &mut working_set) - .unwrap_or_default(); + let raw_evm_tx = { + let working_set = WorkingSet::::new(ethereum.storage.clone()); + if transaction_request.nonce.is_none() { + let nonce = evm + .get_transaction_count(from, None, &mut working_set) + .unwrap_or_default(); - transaction_request.nonce = Some(reth_primitives::U256::from(nonce.as_u64())); - } - - let chain_id = evm - .chain_id(&mut working_set) - .expect("Failed to get chain id") - .map(|id| id.as_u64()) - .unwrap_or(1); - - // TODO: implement gas logic after gas estimation is implemented - let transaction_request = match transaction_request.into_typed_request() { - Some(TypedTransactionRequest::Legacy(mut m)) => { - m.chain_id = Some(chain_id); - - TypedTransactionRequest::Legacy(m) + transaction_request.nonce = Some(reth_primitives::U256::from(nonce.as_u64())); } - Some(TypedTransactionRequest::EIP2930(mut m)) => { - m.chain_id = chain_id; - TypedTransactionRequest::EIP2930(m) - } - Some(TypedTransactionRequest::EIP1559(mut m)) => { - m.chain_id = chain_id; + let chain_id = evm + .chain_id(&mut working_set) + .expect("Failed to get chain id") + .map(|id| id.as_u64()) + .unwrap_or(1); + + // TODO: implement gas logic after gas estimation is implemented + let transaction_request = match transaction_request.into_typed_request() { + Some(TypedTransactionRequest::Legacy(mut m)) => { + m.chain_id = Some(chain_id); + + TypedTransactionRequest::Legacy(m) + } + Some(TypedTransactionRequest::EIP2930(mut m)) => { + m.chain_id = chain_id; + + TypedTransactionRequest::EIP2930(m) + } + Some(TypedTransactionRequest::EIP1559(mut m)) => { + m.chain_id = chain_id; + + TypedTransactionRequest::EIP1559(m) + } + None => { + // to_jsonrpsee_error_object("Conflicting fee fields", ETH_RPC_ERROR)?; + return Err(to_jsonrpsee_error_object( + "Conflicting fee fields", + ETH_RPC_ERROR, + )); + } + }; + + let signed_tx = ethereum + .eth_rpc_config + .eth_signer + .sign_transaction(transaction_request.into_transaction(), from) + .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - TypedTransactionRequest::EIP1559(m) + RlpEvmTransaction { + rlp: signed_tx.envelope_encoded().to_vec(), } - None => { - // to_jsonrpsee_error_object("Conflicting fee fields", ETH_RPC_ERROR)?; - return Err(to_jsonrpsee_error_object( - "Conflicting fee fields", - ETH_RPC_ERROR, - )); - } - }; - - let signed_tx = ethereum - .eth_rpc_config - .eth_signer - .sign_transaction(transaction_request.into_transaction(), from) - .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - - let raw_evm_tx = RlpEvmTransaction { - rlp: signed_tx.envelope_encoded().to_vec(), }; let (tx_hash, raw_tx) = ethereum .make_raw_tx(raw_evm_tx) From b8ea20f6271c5441a08f7bd5f98dbf072136c9ad Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Thu, 21 Sep 2023 12:18:11 +0300 Subject: [PATCH 08/16] fix mutable working set --- full-node/sov-ethereum/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index d15a458f3..5f0c81941 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -207,7 +207,7 @@ pub mod experimental { } let raw_evm_tx = { - let working_set = WorkingSet::::new(ethereum.storage.clone()); + let mut working_set = WorkingSet::::new(ethereum.storage.clone()); if transaction_request.nonce.is_none() { let nonce = evm .get_transaction_count(from, None, &mut working_set) From aba434fcf03e60c9f755cb4c901fa03718908619 Mon Sep 17 00:00:00 2001 From: bkolad Date: Thu, 21 Sep 2023 12:10:15 +0200 Subject: [PATCH 09/16] Add debug printlns --- examples/demo-rollup/Cargo.toml | 4 ++-- examples/demo-rollup/tests/evm/mod.rs | 20 ++++++++++++++------ full-node/sov-ethereum/src/lib.rs | 6 ++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/examples/demo-rollup/Cargo.toml b/examples/demo-rollup/Cargo.toml index ba14b2f36..0de5da065 100644 --- a/examples/demo-rollup/Cargo.toml +++ b/examples/demo-rollup/Cargo.toml @@ -68,8 +68,8 @@ ethers = { workspace = true } revm = { workspace = true } [features] -default = [] -experimental = ["sov-ethereum/experimental", "reth-primitives", "secp256k1", "demo-stf/experimental"] +default = ["experimental"] +experimental = ["sov-ethereum/experimental", "reth-primitives", "secp256k1", "demo-stf/experimental", "local"] local = ["sov-ethereum/local"] [[bench]] diff --git a/examples/demo-rollup/tests/evm/mod.rs b/examples/demo-rollup/tests/evm/mod.rs index bc14a78ec..7cde569e3 100644 --- a/examples/demo-rollup/tests/evm/mod.rs +++ b/examples/demo-rollup/tests/evm/mod.rs @@ -84,7 +84,11 @@ impl TestClient { Ok(receipt_req) } - async fn set_value_unsigned(&self, contract_address: H160, set_arg: u32) -> TxHash { + async fn set_value_unsigned( + &self, + contract_address: H160, + set_arg: u32, + ) -> PendingTransaction<'_, Http> { let nonce = self.eth_get_transaction_count(self.from_addr).await; let req = Eip1559TransactionRequest::new() @@ -158,9 +162,10 @@ impl TestClient { } #[cfg(feature = "local")] - async fn eth_send_transaction(&self, tx: TypedTransaction) -> TxHash { - self.http_client - .request("eth_sendTransaction", rpc_params![tx]) + async fn eth_send_transaction(&self, tx: TypedTransaction) -> PendingTransaction<'_, Http> { + self.client + .provider() + .send_transaction(tx, None) .await .unwrap() } @@ -270,12 +275,15 @@ impl TestClient { { let value = 103; - let tx_hash = self.set_value_unsigned(contract_address, value).await; + let receipt = self.set_value_unsigned(contract_address, value).await; self.send_publish_batch_request().await; let latest_block = self.eth_get_block_by_number(None).await; assert_eq!(latest_block.transactions.len(), 1); - assert_eq!(latest_block.transactions[0], tx_hash); + let r = receipt.await.unwrap().unwrap(); + + println!("Receipt {:?}", r); + //assert_eq!(latest_block.transactions[0], tx_hash); let get_arg = self.query_contract(contract_address).await?; // FIXME: Transaction is not failing but the value is not set diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index 5f0c81941..f597fe80f 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -155,6 +155,8 @@ pub mod experimental { rpc.register_async_method( "eth_sendRawTransaction", |parameters, ethereum| async move { + println!("Calling: eth_sendRawTransaction"); + let data: Bytes = parameters.one().unwrap(); let raw_evm_tx = RlpEvmTransaction { rlp: data.to_vec() }; @@ -189,8 +191,11 @@ pub mod experimental { #[cfg(feature = "local")] rpc.register_async_method("eth_sendTransaction", |parameters, ethereum| async move { + println!("Calling: eth_sendTransaction"); + let mut transaction_request: TransactionRequest = parameters.one().unwrap(); + println!("Print: transaction_request {:?}", transaction_request); let evm = Evm::::default(); // get from, return error if none @@ -276,6 +281,7 @@ pub mod experimental { .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; } + println!("End: eth_sendTransaction"); Ok::<_, ErrorObjectOwned>(tx_hash) })?; From 32c05920fd985c18780268cd33690d1bf65525bc Mon Sep 17 00:00:00 2001 From: bkolad Date: Thu, 21 Sep 2023 12:47:46 +0200 Subject: [PATCH 10/16] add more debugs --- full-node/sov-ethereum/src/lib.rs | 57 ++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index f597fe80f..6b4e1f198 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -198,6 +198,7 @@ pub mod experimental { println!("Print: transaction_request {:?}", transaction_request); let evm = Evm::::default(); + println!("!!!!! 1"); // get from, return error if none let from = transaction_request .from @@ -211,6 +212,7 @@ pub mod experimental { )); } + println!("!!!!! 2"); let raw_evm_tx = { let mut working_set = WorkingSet::::new(ethereum.storage.clone()); if transaction_request.nonce.is_none() { @@ -227,6 +229,7 @@ pub mod experimental { .map(|id| id.as_u64()) .unwrap_or(1); + println!("!!!!! 3"); // TODO: implement gas logic after gas estimation is implemented let transaction_request = match transaction_request.into_typed_request() { Some(TypedTransactionRequest::Legacy(mut m)) => { @@ -241,6 +244,7 @@ pub mod experimental { } Some(TypedTransactionRequest::EIP1559(mut m)) => { m.chain_id = chain_id; + println!("EIP1559 nonce {:?}", m.nonce); TypedTransactionRequest::EIP1559(m) } @@ -253,12 +257,19 @@ pub mod experimental { } }; + println!("!!!!! 4"); + + let tx = into_transaction(transaction_request); + + println!("!!!!! 4.5"); + let signed_tx = ethereum .eth_rpc_config .eth_signer - .sign_transaction(transaction_request.into_transaction(), from) + .sign_transaction(tx, from) .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; + println!("!!!!! 5"); RlpEvmTransaction { rlp: signed_tx.envelope_encoded().to_vec(), } @@ -287,4 +298,48 @@ pub mod experimental { Ok(()) } + + pub fn into_transaction(request: TypedTransactionRequest) -> reth_primitives::Transaction { + match request { + TypedTransactionRequest::Legacy(tx) => { + reth_primitives::Transaction::Legacy(reth_primitives::TxLegacy { + chain_id: tx.chain_id, + nonce: u64::from_be_bytes(tx.nonce.to_be_bytes()), + gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), + gas_limit: u64::from_be_bytes(tx.gas_limit.to_be_bytes()), + to: tx.kind.into(), + value: u128::from_be_bytes(tx.value.to_be_bytes()), + input: tx.input, + }) + } + TypedTransactionRequest::EIP2930(tx) => { + reth_primitives::Transaction::Eip2930(reth_primitives::TxEip2930 { + chain_id: tx.chain_id, + nonce: u64::from_be_bytes(tx.nonce.to_be_bytes()), + gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), + gas_limit: u64::from_be_bytes(tx.gas_limit.to_be_bytes()), + to: tx.kind.into(), + value: u128::from_be_bytes(tx.value.to_be_bytes()), + input: tx.input, + access_list: tx.access_list, + }) + } + TypedTransactionRequest::EIP1559(tx) => { + reth_primitives::Transaction::Eip1559(reth_primitives::TxEip1559 { + chain_id: tx.chain_id, + + nonce: u64::from_be_bytes(tx.nonce.to_be_bytes()), + max_fee_per_gas: u128::from_be_bytes(tx.max_fee_per_gas.to_be_bytes()), + gas_limit: u64::from_be_bytes(tx.gas_limit.to_be_bytes()), + to: tx.kind.into(), + value: u128::from_be_bytes(tx.value.to_be_bytes()), + input: tx.input, + access_list: tx.access_list, + max_priority_fee_per_gas: u128::from_be_bytes( + tx.max_priority_fee_per_gas.to_be_bytes(), + ), + }) + } + } + } } From 91b2606e5880e5c13f87bafb7680d1d9b9ee04f0 Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Thu, 21 Sep 2023 15:17:01 +0300 Subject: [PATCH 11/16] temporary fix into transaction method --- examples/demo-rollup/tests/evm/mod.rs | 13 +++--- full-node/sov-ethereum/src/lib.rs | 61 ++++++++++++++------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/examples/demo-rollup/tests/evm/mod.rs b/examples/demo-rollup/tests/evm/mod.rs index 7cde569e3..c164942f0 100644 --- a/examples/demo-rollup/tests/evm/mod.rs +++ b/examples/demo-rollup/tests/evm/mod.rs @@ -275,18 +275,17 @@ impl TestClient { { let value = 103; - let receipt = self.set_value_unsigned(contract_address, value).await; - self.send_publish_batch_request().await; + let tx_hash = { + let set_value_req = self.set_value_unsigned(contract_address, value).await; + self.send_publish_batch_request().await; + set_value_req.await.unwrap().unwrap().transaction_hash + }; let latest_block = self.eth_get_block_by_number(None).await; assert_eq!(latest_block.transactions.len(), 1); - let r = receipt.await.unwrap().unwrap(); - - println!("Receipt {:?}", r); - //assert_eq!(latest_block.transactions[0], tx_hash); + assert_eq!(latest_block.transactions[0], tx_hash); let get_arg = self.query_contract(contract_address).await?; - // FIXME: Transaction is not failing but the value is not set assert_eq!(value, get_arg.as_u32()); } diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index 6b4e1f198..c9b4852a6 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -155,8 +155,6 @@ pub mod experimental { rpc.register_async_method( "eth_sendRawTransaction", |parameters, ethereum| async move { - println!("Calling: eth_sendRawTransaction"); - let data: Bytes = parameters.one().unwrap(); let raw_evm_tx = RlpEvmTransaction { rlp: data.to_vec() }; @@ -191,14 +189,10 @@ pub mod experimental { #[cfg(feature = "local")] rpc.register_async_method("eth_sendTransaction", |parameters, ethereum| async move { - println!("Calling: eth_sendTransaction"); - let mut transaction_request: TransactionRequest = parameters.one().unwrap(); - println!("Print: transaction_request {:?}", transaction_request); let evm = Evm::::default(); - println!("!!!!! 1"); // get from, return error if none let from = transaction_request .from @@ -212,7 +206,6 @@ pub mod experimental { )); } - println!("!!!!! 2"); let raw_evm_tx = { let mut working_set = WorkingSet::::new(ethereum.storage.clone()); if transaction_request.nonce.is_none() { @@ -229,7 +222,6 @@ pub mod experimental { .map(|id| id.as_u64()) .unwrap_or(1); - println!("!!!!! 3"); // TODO: implement gas logic after gas estimation is implemented let transaction_request = match transaction_request.into_typed_request() { Some(TypedTransactionRequest::Legacy(mut m)) => { @@ -244,12 +236,10 @@ pub mod experimental { } Some(TypedTransactionRequest::EIP1559(mut m)) => { m.chain_id = chain_id; - println!("EIP1559 nonce {:?}", m.nonce); TypedTransactionRequest::EIP1559(m) } None => { - // to_jsonrpsee_error_object("Conflicting fee fields", ETH_RPC_ERROR)?; return Err(to_jsonrpsee_error_object( "Conflicting fee fields", ETH_RPC_ERROR, @@ -257,19 +247,12 @@ pub mod experimental { } }; - println!("!!!!! 4"); - - let tx = into_transaction(transaction_request); - - println!("!!!!! 4.5"); - let signed_tx = ethereum .eth_rpc_config .eth_signer - .sign_transaction(tx, from) + .sign_transaction(into_transaction(transaction_request), from) .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - println!("!!!!! 5"); RlpEvmTransaction { rlp: signed_tx.envelope_encoded().to_vec(), } @@ -292,34 +275,47 @@ pub mod experimental { .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; } - println!("End: eth_sendTransaction"); Ok::<_, ErrorObjectOwned>(tx_hash) })?; Ok(()) } - pub fn into_transaction(request: TypedTransactionRequest) -> reth_primitives::Transaction { + // Temporary solution until https://github.com/paradigmxyz/reth/issues/4704 is resolved + // The problem is having wrong length nonce/gas_limt/value fields in the transaction request + fn into_transaction(request: TypedTransactionRequest) -> reth_primitives::Transaction { match request { TypedTransactionRequest::Legacy(tx) => { reth_primitives::Transaction::Legacy(reth_primitives::TxLegacy { chain_id: tx.chain_id, - nonce: u64::from_be_bytes(tx.nonce.to_be_bytes()), + nonce: u64::from_be_bytes( + tx.nonce.to_be_bytes::<32>()[24..].try_into().unwrap(), + ), gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), - gas_limit: u64::from_be_bytes(tx.gas_limit.to_be_bytes()), + gas_limit: u64::from_be_bytes( + tx.gas_limit.to_be_bytes::<32>()[24..].try_into().unwrap(), + ), to: tx.kind.into(), - value: u128::from_be_bytes(tx.value.to_be_bytes()), + value: u128::from_be_bytes( + tx.value.to_be_bytes::<32>()[16..].try_into().unwrap(), + ), input: tx.input, }) } TypedTransactionRequest::EIP2930(tx) => { reth_primitives::Transaction::Eip2930(reth_primitives::TxEip2930 { chain_id: tx.chain_id, - nonce: u64::from_be_bytes(tx.nonce.to_be_bytes()), + nonce: u64::from_be_bytes( + tx.nonce.to_be_bytes::<32>()[24..].try_into().unwrap(), + ), gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), - gas_limit: u64::from_be_bytes(tx.gas_limit.to_be_bytes()), + gas_limit: u64::from_be_bytes( + tx.gas_limit.to_be_bytes::<32>()[24..].try_into().unwrap(), + ), to: tx.kind.into(), - value: u128::from_be_bytes(tx.value.to_be_bytes()), + value: u128::from_be_bytes( + tx.value.to_be_bytes::<32>()[16..].try_into().unwrap(), + ), input: tx.input, access_list: tx.access_list, }) @@ -327,12 +323,17 @@ pub mod experimental { TypedTransactionRequest::EIP1559(tx) => { reth_primitives::Transaction::Eip1559(reth_primitives::TxEip1559 { chain_id: tx.chain_id, - - nonce: u64::from_be_bytes(tx.nonce.to_be_bytes()), + nonce: u64::from_be_bytes( + tx.nonce.to_be_bytes::<32>()[24..].try_into().unwrap(), + ), max_fee_per_gas: u128::from_be_bytes(tx.max_fee_per_gas.to_be_bytes()), - gas_limit: u64::from_be_bytes(tx.gas_limit.to_be_bytes()), + gas_limit: u64::from_be_bytes( + tx.gas_limit.to_be_bytes::<32>()[24..].try_into().unwrap(), + ), to: tx.kind.into(), - value: u128::from_be_bytes(tx.value.to_be_bytes()), + value: u128::from_be_bytes( + tx.value.to_be_bytes::<32>()[16..].try_into().unwrap(), + ), input: tx.input, access_list: tx.access_list, max_priority_fee_per_gas: u128::from_be_bytes( From 0551f239d806c5449f881bd46b7db1c732b840a2 Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Thu, 21 Sep 2023 15:20:48 +0300 Subject: [PATCH 12/16] lint: eth_sendTransaction --- module-system/module-implementations/sov-evm/src/signer/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/module-system/module-implementations/sov-evm/src/signer/mod.rs b/module-system/module-implementations/sov-evm/src/signer/mod.rs index ff7e50f4e..c98fde337 100644 --- a/module-system/module-implementations/sov-evm/src/signer/mod.rs +++ b/module-system/module-implementations/sov-evm/src/signer/mod.rs @@ -1,6 +1,7 @@ +use std::collections::HashMap; + use reth_primitives::{sign_message, Address, Transaction, TransactionSigned, H256}; use secp256k1::{PublicKey, SecretKey}; -use std::collections::HashMap; /// Ethereum transaction signer. pub struct DevSigner { From 83a7c398f0bc1d404f7eaa223fcee73e99f8a2a8 Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Thu, 21 Sep 2023 16:42:20 +0300 Subject: [PATCH 13/16] fix reviews --- examples/demo-rollup/Cargo.toml | 6 +- full-node/sov-ethereum/src/lib.rs | 123 ++++++++++++++---------------- 2 files changed, 60 insertions(+), 69 deletions(-) diff --git a/examples/demo-rollup/Cargo.toml b/examples/demo-rollup/Cargo.toml index 22fa70a2a..e7fbbd669 100644 --- a/examples/demo-rollup/Cargo.toml +++ b/examples/demo-rollup/Cargo.toml @@ -72,12 +72,12 @@ ethers = { workspace = true } revm = { workspace = true } [features] -default = ["native", "experimental"] # 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 = ["sov-ethereum/experimental", "reth-primitives", "secp256k1", "demo-stf/experimental"] +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 = ["sov-ethereum/experimental", "reth-primitives", "secp256k1", "demo-stf/experimental", "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", "local"] + "sov-modules-api/native"] bench = ["native", "async-trait", "borsh", "hex"] local = ["sov-ethereum/local"] diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index c9b4852a6..0e2b42d8b 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -7,6 +7,7 @@ pub use sov_evm::signer::DevSigner; #[cfg(feature = "experimental")] pub mod experimental { + use std::array::TryFromSliceError; use std::collections::HashMap; use std::sync::{Arc, Mutex}; @@ -112,6 +113,27 @@ pub mod experimental { Ok((H256::from(tx_hash), tx.try_to_vec()?)) } + async fn build_and_submit_batch( + &self, + txs: Vec>, + min_blob_size: Option, + ) -> Result<(), jsonrpsee::core::Error> { + let min_blob_size = min_blob_size.or(self.eth_rpc_config.min_blob_size); + + let batch = self + .batch_builder + .lock() + .unwrap() + .add_transactions_and_get_next_blob(min_blob_size, txs); + + if !batch.is_empty() { + self.submit_batch(batch) + .await + .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; + } + Ok(()) + } + async fn submit_batch(&self, raw_txs: Vec>) -> Result<(), jsonrpsee::core::Error> { let blob = raw_txs .try_to_vec() @@ -137,18 +159,11 @@ pub mod experimental { txs.push(tx) } - let blob = ethereum - .batch_builder - .lock() - .unwrap() - .add_transactions_and_get_next_blob(Some(1), txs); + ethereum + .build_and_submit_batch(txs, Some(1)) + .await + .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - if !blob.is_empty() { - ethereum - .submit_batch(blob) - .await - .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - } Ok::("Submitted transaction".to_string()) })?; @@ -163,21 +178,11 @@ pub mod experimental { .make_raw_tx(raw_evm_tx) .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - let blob = ethereum - .batch_builder - .lock() - .unwrap() - .add_transactions_and_get_next_blob( - ethereum.eth_rpc_config.min_blob_size, - vec![raw_tx], - ); - - if !blob.is_empty() { - ethereum - .submit_batch(blob) - .await - .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - } + ethereum + .build_and_submit_batch(vec![raw_tx], None) + .await + .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; + Ok::<_, ErrorObjectOwned>(tx_hash) }, )?; @@ -222,7 +227,8 @@ pub mod experimental { .map(|id| id.as_u64()) .unwrap_or(1); - // TODO: implement gas logic after gas estimation is implemented + // TODO: implement gas logic after gas estimation (#906) is implemented + // https://github.com/Sovereign-Labs/sovereign-sdk/issues/906 let transaction_request = match transaction_request.into_typed_request() { Some(TypedTransactionRequest::Legacy(mut m)) => { m.chain_id = Some(chain_id); @@ -247,10 +253,14 @@ pub mod experimental { } }; + let transaction = try_into_transaction(transaction_request).map_err(|_| { + to_jsonrpsee_error_object("Invalid types in transaction request", ETH_RPC_ERROR) + })?; + let signed_tx = ethereum .eth_rpc_config .eth_signer - .sign_transaction(into_transaction(transaction_request), from) + .sign_transaction(transaction, from) .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; RlpEvmTransaction { @@ -260,20 +270,11 @@ pub mod experimental { let (tx_hash, raw_tx) = ethereum .make_raw_tx(raw_evm_tx) .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - let blob = ethereum - .batch_builder - .lock() - .unwrap() - .add_transactions_and_get_next_blob( - ethereum.eth_rpc_config.min_blob_size, - vec![raw_tx], - ); - if !blob.is_empty() { - ethereum - .submit_batch(blob) - .await - .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; - } + + ethereum + .build_and_submit_batch(vec![raw_tx], None) + .await + .map_err(|e| to_jsonrpsee_error_object(e, ETH_RPC_ERROR))?; Ok::<_, ErrorObjectOwned>(tx_hash) })?; @@ -283,39 +284,33 @@ pub mod experimental { // Temporary solution until https://github.com/paradigmxyz/reth/issues/4704 is resolved // The problem is having wrong length nonce/gas_limt/value fields in the transaction request - fn into_transaction(request: TypedTransactionRequest) -> reth_primitives::Transaction { - match request { + fn try_into_transaction( + request: TypedTransactionRequest, + ) -> Result { + Ok(match request { TypedTransactionRequest::Legacy(tx) => { reth_primitives::Transaction::Legacy(reth_primitives::TxLegacy { chain_id: tx.chain_id, - nonce: u64::from_be_bytes( - tx.nonce.to_be_bytes::<32>()[24..].try_into().unwrap(), - ), + nonce: u64::from_be_bytes(tx.nonce.to_be_bytes::<32>()[24..].try_into()?), gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), gas_limit: u64::from_be_bytes( - tx.gas_limit.to_be_bytes::<32>()[24..].try_into().unwrap(), + tx.gas_limit.to_be_bytes::<32>()[24..].try_into()?, ), to: tx.kind.into(), - value: u128::from_be_bytes( - tx.value.to_be_bytes::<32>()[16..].try_into().unwrap(), - ), + value: u128::from_be_bytes(tx.value.to_be_bytes::<32>()[16..].try_into()?), input: tx.input, }) } TypedTransactionRequest::EIP2930(tx) => { reth_primitives::Transaction::Eip2930(reth_primitives::TxEip2930 { chain_id: tx.chain_id, - nonce: u64::from_be_bytes( - tx.nonce.to_be_bytes::<32>()[24..].try_into().unwrap(), - ), + nonce: u64::from_be_bytes(tx.nonce.to_be_bytes::<32>()[24..].try_into()?), gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), gas_limit: u64::from_be_bytes( - tx.gas_limit.to_be_bytes::<32>()[24..].try_into().unwrap(), + tx.gas_limit.to_be_bytes::<32>()[24..].try_into()?, ), to: tx.kind.into(), - value: u128::from_be_bytes( - tx.value.to_be_bytes::<32>()[16..].try_into().unwrap(), - ), + value: u128::from_be_bytes(tx.value.to_be_bytes::<32>()[16..].try_into()?), input: tx.input, access_list: tx.access_list, }) @@ -323,17 +318,13 @@ pub mod experimental { TypedTransactionRequest::EIP1559(tx) => { reth_primitives::Transaction::Eip1559(reth_primitives::TxEip1559 { chain_id: tx.chain_id, - nonce: u64::from_be_bytes( - tx.nonce.to_be_bytes::<32>()[24..].try_into().unwrap(), - ), + nonce: u64::from_be_bytes(tx.nonce.to_be_bytes::<32>()[24..].try_into()?), max_fee_per_gas: u128::from_be_bytes(tx.max_fee_per_gas.to_be_bytes()), gas_limit: u64::from_be_bytes( - tx.gas_limit.to_be_bytes::<32>()[24..].try_into().unwrap(), + tx.gas_limit.to_be_bytes::<32>()[24..].try_into()?, ), to: tx.kind.into(), - value: u128::from_be_bytes( - tx.value.to_be_bytes::<32>()[16..].try_into().unwrap(), - ), + value: u128::from_be_bytes(tx.value.to_be_bytes::<32>()[16..].try_into()?), input: tx.input, access_list: tx.access_list, max_priority_fee_per_gas: u128::from_be_bytes( @@ -341,6 +332,6 @@ pub mod experimental { ), }) } - } + }) } } From ad633f25165cade6a3e594b73b319877ba7001f8 Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Thu, 21 Sep 2023 16:50:17 +0300 Subject: [PATCH 14/16] remove unnecessary result --- full-node/sov-ethereum/src/lib.rs | 49 ++++++++++++++++--------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index 0e2b42d8b..ba02b034d 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -7,7 +7,6 @@ pub use sov_evm::signer::DevSigner; #[cfg(feature = "experimental")] pub mod experimental { - use std::array::TryFromSliceError; use std::collections::HashMap; use std::sync::{Arc, Mutex}; @@ -253,9 +252,7 @@ pub mod experimental { } }; - let transaction = try_into_transaction(transaction_request).map_err(|_| { - to_jsonrpsee_error_object("Invalid types in transaction request", ETH_RPC_ERROR) - })?; + let transaction = into_transaction(transaction_request); let signed_tx = ethereum .eth_rpc_config @@ -284,33 +281,27 @@ pub mod experimental { // Temporary solution until https://github.com/paradigmxyz/reth/issues/4704 is resolved // The problem is having wrong length nonce/gas_limt/value fields in the transaction request - fn try_into_transaction( - request: TypedTransactionRequest, - ) -> Result { - Ok(match request { + fn into_transaction(request: TypedTransactionRequest) -> reth_primitives::Transaction { + match request { TypedTransactionRequest::Legacy(tx) => { reth_primitives::Transaction::Legacy(reth_primitives::TxLegacy { chain_id: tx.chain_id, - nonce: u64::from_be_bytes(tx.nonce.to_be_bytes::<32>()[24..].try_into()?), + nonce: convert_array_to_u64(tx.nonce.to_be_bytes()), gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), - gas_limit: u64::from_be_bytes( - tx.gas_limit.to_be_bytes::<32>()[24..].try_into()?, - ), + gas_limit: convert_array_to_u64(tx.gas_limit.to_be_bytes()), to: tx.kind.into(), - value: u128::from_be_bytes(tx.value.to_be_bytes::<32>()[16..].try_into()?), + value: convert_array_to_u128(tx.value.to_be_bytes()), input: tx.input, }) } TypedTransactionRequest::EIP2930(tx) => { reth_primitives::Transaction::Eip2930(reth_primitives::TxEip2930 { chain_id: tx.chain_id, - nonce: u64::from_be_bytes(tx.nonce.to_be_bytes::<32>()[24..].try_into()?), + nonce: convert_array_to_u64(tx.nonce.to_be_bytes()), gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), - gas_limit: u64::from_be_bytes( - tx.gas_limit.to_be_bytes::<32>()[24..].try_into()?, - ), + gas_limit: convert_array_to_u64(tx.gas_limit.to_be_bytes()), to: tx.kind.into(), - value: u128::from_be_bytes(tx.value.to_be_bytes::<32>()[16..].try_into()?), + value: convert_array_to_u128(tx.value.to_be_bytes()), input: tx.input, access_list: tx.access_list, }) @@ -318,13 +309,11 @@ pub mod experimental { TypedTransactionRequest::EIP1559(tx) => { reth_primitives::Transaction::Eip1559(reth_primitives::TxEip1559 { chain_id: tx.chain_id, - nonce: u64::from_be_bytes(tx.nonce.to_be_bytes::<32>()[24..].try_into()?), + nonce: convert_array_to_u64(tx.nonce.to_be_bytes()), max_fee_per_gas: u128::from_be_bytes(tx.max_fee_per_gas.to_be_bytes()), - gas_limit: u64::from_be_bytes( - tx.gas_limit.to_be_bytes::<32>()[24..].try_into()?, - ), + gas_limit: convert_array_to_u64(tx.gas_limit.to_be_bytes()), to: tx.kind.into(), - value: u128::from_be_bytes(tx.value.to_be_bytes::<32>()[16..].try_into()?), + value: convert_array_to_u128(tx.value.to_be_bytes()), input: tx.input, access_list: tx.access_list, max_priority_fee_per_gas: u128::from_be_bytes( @@ -332,6 +321,18 @@ pub mod experimental { ), }) } - }) + } + } + + fn convert_array_to_u64(array: [u8; 32]) -> u64 { + let mut bytes = [0u8; 8]; + bytes.copy_from_slice(&array[24..]); + u64::from_be_bytes(bytes) + } + + fn convert_array_to_u128(array: [u8; 32]) -> u128 { + let mut bytes = [0u8; 16]; + bytes.copy_from_slice(&array[16..]); + u128::from_be_bytes(bytes) } } From a3a39a751616c49411843b59776ab5ac035d8a60 Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Fri, 22 Sep 2023 10:44:34 +0300 Subject: [PATCH 15/16] error on conversions --- full-node/sov-ethereum/src/lib.rs | 47 +++++++++++++++++-------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/full-node/sov-ethereum/src/lib.rs b/full-node/sov-ethereum/src/lib.rs index ba02b034d..747396ecf 100644 --- a/full-node/sov-ethereum/src/lib.rs +++ b/full-node/sov-ethereum/src/lib.rs @@ -7,6 +7,7 @@ pub use sov_evm::signer::DevSigner; #[cfg(feature = "experimental")] pub mod experimental { + use std::array::TryFromSliceError; use std::collections::HashMap; use std::sync::{Arc, Mutex}; @@ -252,7 +253,9 @@ pub mod experimental { } }; - let transaction = into_transaction(transaction_request); + let transaction = into_transaction(transaction_request).map_err(|_| { + to_jsonrpsee_error_object("Invalid types in transaction request", ETH_RPC_ERROR) + })?; let signed_tx = ethereum .eth_rpc_config @@ -281,27 +284,29 @@ pub mod experimental { // Temporary solution until https://github.com/paradigmxyz/reth/issues/4704 is resolved // The problem is having wrong length nonce/gas_limt/value fields in the transaction request - fn into_transaction(request: TypedTransactionRequest) -> reth_primitives::Transaction { - match request { + fn into_transaction( + request: TypedTransactionRequest, + ) -> Result { + Ok(match request { TypedTransactionRequest::Legacy(tx) => { reth_primitives::Transaction::Legacy(reth_primitives::TxLegacy { chain_id: tx.chain_id, - nonce: convert_array_to_u64(tx.nonce.to_be_bytes()), + nonce: convert_u256_to_u64(tx.nonce)?, gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), - gas_limit: convert_array_to_u64(tx.gas_limit.to_be_bytes()), + gas_limit: convert_u256_to_u64(tx.gas_limit)?, to: tx.kind.into(), - value: convert_array_to_u128(tx.value.to_be_bytes()), + value: convert_u256_to_u128(tx.value)?, input: tx.input, }) } TypedTransactionRequest::EIP2930(tx) => { reth_primitives::Transaction::Eip2930(reth_primitives::TxEip2930 { chain_id: tx.chain_id, - nonce: convert_array_to_u64(tx.nonce.to_be_bytes()), + nonce: convert_u256_to_u64(tx.nonce)?, gas_price: u128::from_be_bytes(tx.gas_price.to_be_bytes()), - gas_limit: convert_array_to_u64(tx.gas_limit.to_be_bytes()), + gas_limit: convert_u256_to_u64(tx.gas_limit)?, to: tx.kind.into(), - value: convert_array_to_u128(tx.value.to_be_bytes()), + value: convert_u256_to_u128(tx.value)?, input: tx.input, access_list: tx.access_list, }) @@ -309,11 +314,11 @@ pub mod experimental { TypedTransactionRequest::EIP1559(tx) => { reth_primitives::Transaction::Eip1559(reth_primitives::TxEip1559 { chain_id: tx.chain_id, - nonce: convert_array_to_u64(tx.nonce.to_be_bytes()), + nonce: convert_u256_to_u64(tx.nonce)?, max_fee_per_gas: u128::from_be_bytes(tx.max_fee_per_gas.to_be_bytes()), - gas_limit: convert_array_to_u64(tx.gas_limit.to_be_bytes()), + gas_limit: convert_u256_to_u64(tx.gas_limit)?, to: tx.kind.into(), - value: convert_array_to_u128(tx.value.to_be_bytes()), + value: convert_u256_to_u128(tx.value)?, input: tx.input, access_list: tx.access_list, max_priority_fee_per_gas: u128::from_be_bytes( @@ -321,18 +326,18 @@ pub mod experimental { ), }) } - } + }) } - fn convert_array_to_u64(array: [u8; 32]) -> u64 { - let mut bytes = [0u8; 8]; - bytes.copy_from_slice(&array[24..]); - u64::from_be_bytes(bytes) + fn convert_u256_to_u64(u256: reth_primitives::U256) -> Result { + let bytes: [u8; 32] = u256.to_be_bytes(); + let bytes: [u8; 8] = bytes[24..].try_into()?; + Ok(u64::from_be_bytes(bytes)) } - fn convert_array_to_u128(array: [u8; 32]) -> u128 { - let mut bytes = [0u8; 16]; - bytes.copy_from_slice(&array[16..]); - u128::from_be_bytes(bytes) + fn convert_u256_to_u128(u256: reth_primitives::U256) -> Result { + let bytes: [u8; 32] = u256.to_be_bytes(); + let bytes: [u8; 16] = bytes[16..].try_into()?; + Ok(u128::from_be_bytes(bytes)) } } From b5ff891f90e38cdd360ee73ba889f780b8434a0d Mon Sep 17 00:00:00 2001 From: orkunkilic Date: Fri, 22 Sep 2023 11:41:16 +0300 Subject: [PATCH 16/16] enable local with experimental on evm --- full-node/sov-ethereum/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/full-node/sov-ethereum/Cargo.toml b/full-node/sov-ethereum/Cargo.toml index 6137f08de..bf09e2907 100644 --- a/full-node/sov-ethereum/Cargo.toml +++ b/full-node/sov-ethereum/Cargo.toml @@ -36,5 +36,5 @@ tokio = { workspace = true } [features] default = [] local = [] -experimental = ["demo-stf/experimental", "sov-evm/experimental"] +experimental = ["demo-stf/experimental", "sov-evm/experimental", "local"] native = ["demo-stf/native", "sov-evm/native"]