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 SendTransaction and Storage access on RPC #902

Merged
merged 19 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from 4 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 examples/demo-rollup/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions examples/demo-rollup/src/rollup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ pub async fn new_rollup_with_celestia_da<Vm: ZkvmHost>(
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,
Expand Down Expand Up @@ -199,6 +200,7 @@ pub fn new_rollup_with_mock_da_from_config<Vm: ZkvmHost>(
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,
Expand Down
50 changes: 48 additions & 2 deletions examples/demo-rollup/tests/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,24 @@ impl TestClient {
Ok(receipt_req)
}

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)
.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,
Expand Down Expand Up @@ -131,13 +149,22 @@ impl TestClient {
Ok(ethereum_types::U256::from(resp_array))
}

#[cfg(feature = "local")]
async fn eth_accounts(&self) -> Vec<Address> {
self.http_client
.request("eth_accounts", rpc_params![])
.await
.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
Expand Down Expand Up @@ -239,6 +266,22 @@ impl TestClient {
assert_eq!(102, get_arg.as_u32());
}

#[cfg(feature = "local")]
{
let value = 103;

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).await?;
// FIXME: Transaction is not failing but the value is not set
assert_eq!(value, get_arg.as_u32());
}

Ok(())
}
}
Expand All @@ -256,8 +299,11 @@ async fn send_tx_test_to_eth(rpc_address: SocketAddr) -> Result<(), Box<dyn std:

let test_client = TestClient::new(chain_id, key, from_addr, contract, rpc_address).await;

let etc_accounts = test_client.eth_accounts().await;
assert_eq!(vec![from_addr], etc_accounts);
#[cfg(feature = "local")]
{
let etc_accounts = test_client.eth_accounts().await;
assert_eq!(vec![from_addr], etc_accounts);
}

let eth_chain_id = test_client.eth_chain_id().await;
assert_eq!(chain_id, eth_chain_id);
Expand Down
1 change: 1 addition & 0 deletions full-node/sov-ethereum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ tokio = { workspace = true }

[features]
default = []
local = []
experimental = ["demo-stf/experimental", "sov-evm/experimental"]
native = ["demo-stf/native", "sov-evm/native"]
47 changes: 41 additions & 6 deletions full-node/sov-ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ pub mod experimental {
use borsh::ser::BorshSerialize;
use demo_stf::app::DefaultPrivateKey;
use demo_stf::runtime::{DefaultContext, Runtime};
use ethers::types::{Bytes, H256};
use ethers::types::transaction::eip2718::TypedTransaction;
use ethers::types::{Bytes, H160, H256};
use jsonrpsee::types::ErrorObjectOwned;
use jsonrpsee::RpcModule;
use reth_primitives::{
Address as RethAddress, TransactionSignedNoHash as RethTransactionSignedNoHash,
};
use reth_rpc_types::TypedTransactionRequest;
use sov_evm::call::CallMessage;
use sov_evm::evm::RlpEvmTransaction;
use sov_modules_api::transaction::Transaction;
Expand All @@ -27,14 +29,15 @@ pub mod experimental {
use sov_rollup_interface::services::da::DaService;

use super::batch_builder::EthBatchBuilder;
#[cfg(feature = "local")]
use super::DevSigner;

const ETH_RPC_ERROR: &str = "ETH_RPC_ERROR";

pub struct EthRpcConfig {
pub min_blob_size: Option<usize>,
pub sov_tx_signer_priv_key: DefaultPrivateKey,
//TODO #839
#[cfg(feature = "local")]
pub eth_signer: DevSigner,
}

Expand Down Expand Up @@ -174,14 +177,46 @@ 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())
})?;

// 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 {
orkunkilic marked this conversation as resolved.
Show resolved Hide resolved
let typed_transaction: TypedTransaction = parameters.one().unwrap();

let signed_tx = ethereum
.eth_rpc_config
.eth_signer
.sign_ethers_transaction(typed_transaction)
orkunkilic marked this conversation as resolved.
Show resolved Hide resolved
.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(())
Expand Down
20 changes: 20 additions & 0 deletions module-system/module-implementations/sov-evm/src/signer/mod.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -57,6 +58,25 @@ impl DevSigner {
))
}

pub fn sign_ethers_transaction(
orkunkilic marked this conversation as resolved.
Show resolved Hide resolved
&self,
transaction: TypedTransaction,
) -> Result<Bytes, SignError> {
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<Address> {
self.signers.keys().copied().collect()
}
Expand Down
Loading