Skip to content

Commit

Permalink
estimate-gas signed (#947)
Browse files Browse the repository at this point in the history
  • Loading branch information
orkunkilic authored Sep 29, 2023
1 parent e481346 commit 91c3423
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 19 deletions.
30 changes: 23 additions & 7 deletions examples/demo-rollup/tests/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,15 @@ impl TestClient {
contract_address: H160,
set_arg: u32,
) -> PendingTransaction<'_, Http> {
let nonce = self.eth_get_transaction_count(self.from_addr).await;

// Tx without gas_limit should estimate and include it in send_transaction endpoint
// Tx without nonce should fetch and include it in send_transaction endpoint
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);
.max_fee_per_gas(MAX_FEE_PER_GAS);

let typed_transaction = TypedTransaction::Eip1559(req);

Expand Down Expand Up @@ -148,9 +146,17 @@ impl TestClient {
.chain_id(self.chain_id)
.nonce(nonce)
.data(self.contract.set_call_data(set_arg))
.gas_price(10u64)
.gas(900000u64);
.gas_price(10u64);

let typed_transaction = TypedTransaction::Legacy(req.clone());

// Estimate gas on rpc
let gas = self
.eth_estimate_gas(typed_transaction, Some("latest".to_owned()))
.await;

// Call with the estimated gas
let req = req.gas(gas);
let typed_transaction = TypedTransaction::Legacy(req);

let response = self
Expand Down Expand Up @@ -268,6 +274,16 @@ impl TestClient {
.map_err(|e| e.into())
}

async fn eth_estimate_gas(&self, tx: TypedTransaction, block_number: Option<String>) -> u64 {
let gas: ethereum_types::U64 = self
.http_client
.request("eth_estimateGas", rpc_params![tx, block_number])
.await
.unwrap();

gas.as_u64()
}

async fn execute(self) -> Result<(), Box<dyn std::error::Error>> {
// Nonce should be 0 in genesis
let nonce = self.eth_get_transaction_count(self.from_addr).await;
Expand Down
80 changes: 76 additions & 4 deletions full-node/sov-ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ 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, U128, U256,
};
use reth_rpc_types::{TransactionRequest, TypedTransactionRequest};
use reth_rpc_types::{CallRequest, TransactionRequest, TypedTransactionRequest};
use sov_evm::{CallMessage, Evm, RlpEvmTransaction};
use sov_modules_api::transaction::Transaction;
use sov_modules_api::utils::to_jsonrpsee_error_object;
Expand Down Expand Up @@ -211,6 +211,8 @@ pub mod experimental {

let raw_evm_tx = {
let mut working_set = WorkingSet::<C>::new(ethereum.storage.clone());

// set nonce if none
if transaction_request.nonce.is_none() {
let nonce = evm
.get_transaction_count(from, None, &mut working_set)
Expand All @@ -219,27 +221,43 @@ pub mod experimental {
transaction_request.nonce = Some(nonce);
}

// get current 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 (#906) is implemented
// https://github.com/Sovereign-Labs/sovereign-sdk/issues/906
// get call request to estimate gas and gas prices
let (call_request, gas_price, max_fee_per_gas) =
get_call_request_and_params(from, chain_id, &transaction_request);

// estimate gas limit
let gas_limit = U256::from(
evm.eth_estimate_gas(call_request, None, &mut working_set)?
.as_u64(),
);

// get typed transaction request
let transaction_request = match transaction_request.into_typed_request() {
Some(TypedTransactionRequest::Legacy(mut m)) => {
m.chain_id = Some(chain_id);
m.gas_limit = gas_limit;
m.gas_price = gas_price;

TypedTransactionRequest::Legacy(m)
}
Some(TypedTransactionRequest::EIP2930(mut m)) => {
m.chain_id = chain_id;
m.gas_limit = gas_limit;
m.gas_price = gas_price;

TypedTransactionRequest::EIP2930(m)
}
Some(TypedTransactionRequest::EIP1559(mut m)) => {
m.chain_id = chain_id;
m.gas_limit = gas_limit;
m.max_fee_per_gas = max_fee_per_gas;

TypedTransactionRequest::EIP1559(m)
}
Expand All @@ -251,10 +269,12 @@ pub mod experimental {
}
};

// get raw transaction
let transaction = into_transaction(transaction_request).map_err(|_| {
to_jsonrpsee_error_object("Invalid types in transaction request", ETH_RPC_ERROR)
})?;

// sign transaction
let signed_tx = ethereum
.eth_rpc_config
.eth_signer
Expand Down Expand Up @@ -338,4 +358,56 @@ pub mod experimental {
let bytes: [u8; 16] = bytes[16..].try_into()?;
Ok(u128::from_be_bytes(bytes))
}

fn get_call_request_and_params(
from: reth_primitives::H160,
chain_id: u64,
transaction_request: &TransactionRequest,
) -> (CallRequest, U128, U128) {
// TODO: we need an oracle to fetch the gas price of the current chain
// https://github.com/Sovereign-Labs/sovereign-sdk/issues/883
let gas_price = transaction_request.gas_price.unwrap_or_default();
let max_fee_per_gas = transaction_request.max_fee_per_gas.unwrap_or_default();

// TODO: Generate call request better according to the transaction type
// https://github.com/Sovereign-Labs/sovereign-sdk/issues/946
let call_request = CallRequest {
from: Some(from),
to: transaction_request.to,
gas: transaction_request.gas,
gas_price: {
if transaction_request.max_priority_fee_per_gas.is_some() {
// eip 1559
None
} else {
// legacy
Some(U256::from(gas_price))
}
},
max_fee_per_gas: Some(U256::from(max_fee_per_gas)),
value: transaction_request.value,
input: transaction_request.data.clone().into(),
nonce: transaction_request.nonce,
chain_id: Some(chain_id.into()),
access_list: transaction_request.access_list.clone(),
max_priority_fee_per_gas: {
if transaction_request.max_priority_fee_per_gas.is_some() {
// eip 1559
Some(U256::from(
transaction_request
.max_priority_fee_per_gas
.unwrap_or(max_fee_per_gas),
))
} else {
// legacy
None
}
},
transaction_type: None,
blob_versioned_hashes: vec![],
max_fee_per_blob_gas: None,
};

(call_request, gas_price, max_fee_per_gas)
}
}
4 changes: 4 additions & 0 deletions module-system/module-implementations/sov-evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ mod experimental {
Block, BlockEnv, Receipt, SealedBlock, TransactionSignedAndRecovered,
};

// Gas per transaction not creating a contract.
pub(crate) const MIN_TRANSACTION_GAS: u64 = 21_000u64;
pub(crate) const MIN_CREATE_GAS: u64 = 53_000u64;

/// Evm account.
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub struct AccountData {
Expand Down
Loading

0 comments on commit 91c3423

Please sign in to comment.