rpc: add missing fields in send_transaction (#1976)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Bharath Vedartham
2023-04-02 21:17:45 +05:30
committed by GitHub
parent 7c6c0b41e8
commit 481f60acee
7 changed files with 130 additions and 14 deletions

View File

@@ -12,6 +12,7 @@ use crate::{
EthApi,
};
use ethers_core::utils::get_contract_address;
use reth_network_api::NetworkInfo;
use reth_primitives::{AccessList, BlockId, BlockNumberOrTag, U256};
use reth_provider::{BlockProvider, EvmEnvProvider, StateProvider, StateProviderFactory};
use reth_revm::{
@@ -34,7 +35,7 @@ impl<Client, Pool, Network> EthApi<Client, Pool, Network>
where
Pool: TransactionPool + Clone + 'static,
Client: BlockProvider + StateProviderFactory + EvmEnvProvider + 'static,
Network: Send + Sync + 'static,
Network: NetworkInfo + Send + Sync + 'static,
{
/// Estimate gas needed for execution of the `request` at the [BlockId].
pub(crate) async fn estimate_gas_at(

View File

@@ -23,6 +23,7 @@ use reth_rpc_types::{
};
use reth_transaction_pool::TransactionPool;
use reth_network_api::NetworkInfo;
use serde_json::Value;
use std::collections::BTreeMap;
use tracing::trace;
@@ -33,7 +34,7 @@ where
Self: EthApiSpec + EthTransactions,
Pool: TransactionPool + 'static,
Client: BlockProvider + HeaderProvider + StateProviderFactory + EvmEnvProvider + 'static,
Network: Send + Sync + 'static,
Network: NetworkInfo + Send + Sync + 'static,
{
/// Handler for: `eth_protocolVersion`
async fn protocol_version(&self) -> Result<U64> {

View File

@@ -1,7 +1,7 @@
//! Contains RPC handler implementations specific to state.
use crate::{
eth::error::{EthApiError, EthResult},
eth::error::{EthApiError, EthResult, InvalidTransactionError},
EthApi,
};
use reth_primitives::{
@@ -12,10 +12,12 @@ use reth_provider::{
AccountProvider, BlockProvider, EvmEnvProvider, StateProvider, StateProviderFactory,
};
use reth_rpc_types::{EIP1186AccountProofResponse, StorageProof};
use reth_transaction_pool::{PoolTransaction, TransactionPool};
impl<Client, Pool, Network> EthApi<Client, Pool, Network>
where
Client: BlockProvider + StateProviderFactory + EvmEnvProvider + 'static,
Pool: TransactionPool + Clone + 'static,
{
pub(crate) fn get_code(&self, address: Address, block_id: Option<BlockId>) -> EthResult<Bytes> {
let state = self.state_at_block_id_or_latest(block_id)?;
@@ -29,14 +31,43 @@ where
Ok(balance)
}
/// Returns the number of transactions sent from an address at the given block identifier.
///
/// If this is [BlockNumberOrTag::Pending] then this will look up the highest transaction in
/// pool and return the next nonce (highest + 1).
pub(crate) fn get_transaction_count(
&self,
address: Address,
block_id: Option<BlockId>,
) -> EthResult<U256> {
if let Some(BlockId::Number(BlockNumberOrTag::Pending)) = block_id {
// lookup transactions in pool
let address_txs = self.pool().get_transactions_by_sender(address);
if address_txs.is_empty() {
// get max transaction with the highest nonce
let highest_nonce_tx = address_txs
.into_iter()
.reduce(|accum, item| {
if item.transaction.nonce() > accum.transaction.nonce() {
item
} else {
accum
}
})
.expect("Not empty; qed");
let tx_count = highest_nonce_tx
.transaction
.nonce()
.checked_add(1)
.ok_or(InvalidTransactionError::NonceMaxValue)?;
return Ok(U256::from(tx_count))
}
}
let state = self.state_at_block_id_or_latest(block_id)?;
let nonce = U256::from(state.account_nonce(address)?.unwrap_or_default());
Ok(nonce)
Ok(U256::from(state.account_nonce(address)?.unwrap_or_default()))
}
pub(crate) fn storage_at(

View File

@@ -5,9 +5,10 @@ use crate::{
revm_utils::{inspect, prepare_call_env, transact},
utils::recover_raw_transaction,
},
EthApi,
EthApi, EthApiSpec,
};
use async_trait::async_trait;
use reth_network_api::NetworkInfo;
use reth_primitives::{
Address, BlockId, BlockNumberOrTag, Bytes, FromRecoveredTransaction, IntoRecoveredTransaction,
Receipt, Transaction as PrimitiveTransaction,
@@ -111,7 +112,7 @@ impl<Client, Pool, Network> EthTransactions for EthApi<Client, Pool, Network>
where
Pool: TransactionPool + Clone + 'static,
Client: BlockProvider + StateProviderFactory + EvmEnvProvider + 'static,
Network: Send + Sync + 'static,
Network: NetworkInfo + Send + Sync + 'static,
{
fn state_at(&self, at: BlockId) -> EthResult<StateProviderBox<'_>> {
self.state_at_block_id(at)
@@ -224,19 +225,69 @@ where
Ok(hash)
}
async fn send_transaction(&self, request: TransactionRequest) -> EthResult<H256> {
async fn send_transaction(&self, mut request: TransactionRequest) -> EthResult<H256> {
let from = match request.from {
Some(from) => from,
None => return Err(SignError::NoAccount.into()),
};
// set nonce if not already set before
if request.nonce.is_none() {
let nonce =
self.get_transaction_count(from, Some(BlockId::Number(BlockNumberOrTag::Pending)))?;
request.nonce = Some(nonce);
}
let chain_id = self.chain_id();
// TODO: we need an oracle to fetch the gas price of the current chain
let gas_price = request.gas_price.unwrap_or_default();
let max_fee_per_gas = request.max_fee_per_gas.unwrap_or_default();
let estimated_gas = self
.estimate_gas_at(
CallRequest {
from: Some(from),
to: request.to,
gas: request.gas,
gas_price: Some(U256::from(gas_price)),
max_fee_per_gas: Some(U256::from(max_fee_per_gas)),
value: request.value,
data: request.data.clone(),
nonce: request.nonce,
chain_id: Some(chain_id),
access_list: request.access_list.clone(),
max_priority_fee_per_gas: Some(U256::from(max_fee_per_gas)),
},
BlockId::Number(BlockNumberOrTag::Pending),
)
.await?;
let gas_limit = estimated_gas;
let transaction = match request.into_typed_request() {
Some(tx) => tx,
Some(TypedTransactionRequest::Legacy(mut m)) => {
m.chain_id = Some(chain_id.as_u64());
m.gas_limit = gas_limit;
m.gas_price = gas_price;
TypedTransactionRequest::Legacy(m)
}
Some(TypedTransactionRequest::EIP2930(mut m)) => {
m.chain_id = chain_id.as_u64();
m.gas_limit = gas_limit;
m.gas_price = gas_price;
TypedTransactionRequest::EIP2930(m)
}
Some(TypedTransactionRequest::EIP1559(mut m)) => {
m.chain_id = chain_id.as_u64();
m.gas_limit = gas_limit;
m.max_fee_per_gas = max_fee_per_gas;
TypedTransactionRequest::EIP1559(m)
}
None => return Err(EthApiError::ConflictingFeeFieldsInRequest),
};
// TODO we need to update additional settings in the transaction: nonce, gaslimit, chainid,
// gasprice
let signed_tx = self.sign_request(&from, transaction)?;
let recovered =
@@ -534,6 +585,7 @@ impl From<TransactionSource> for Transaction {
mod tests {
use super::*;
use crate::{eth::cache::EthStateCache, EthApi};
use reth_network_api::test_utils::NoopNetwork;
use reth_primitives::{hex_literal::hex, Bytes};
use reth_provider::test_utils::NoopProvider;
use reth_transaction_pool::{test_utils::testing_pool, TransactionPool};
@@ -541,13 +593,14 @@ mod tests {
#[tokio::test]
async fn send_raw_transaction() {
let noop_provider = NoopProvider::default();
let noop_network_provider = NoopNetwork::default();
let pool = testing_pool();
let eth_api = EthApi::new(
noop_provider,
pool.clone(),
(),
noop_network_provider,
EthStateCache::spawn(NoopProvider::default(), Default::default()),
);

View File

@@ -96,7 +96,7 @@ use crate::{
pool::PoolInner,
traits::{NewTransactionEvent, PoolSize},
};
use reth_primitives::{TxHash, U256};
use reth_primitives::{Address, TxHash, U256};
use reth_provider::StateProviderFactory;
use std::{collections::HashMap, sync::Arc};
use tokio::sync::mpsc::Receiver;
@@ -325,6 +325,18 @@ where
fn on_propagated(&self, txs: PropagatedTransactions) {
self.inner().on_propagated(txs)
}
fn get_transactions_by_sender(
&self,
sender: Address,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>> {
self.pool
.pooled_transactions()
.iter()
.filter(|tx| tx.transaction.sender().eq(&sender))
.map(Arc::clone)
.collect()
}
}
impl<V: TransactionValidator, T: TransactionOrdering> Clone for Pool<V, T> {

View File

@@ -374,6 +374,18 @@ where
self.pool.read().get(tx_hash)
}
/// Returns all transactions of the address
pub(crate) fn get_transactions_by_sender(
&self,
sender: Address,
) -> Vec<Arc<ValidPoolTransaction<T::Transaction>>> {
self.pooled_transactions()
.iter()
.filter(|tx| tx.transaction.sender().eq(&sender))
.map(Arc::clone)
.collect()
}
/// Returns all the transactions belonging to the hashes.
///
/// If no transaction exists, it is skipped.

View File

@@ -145,6 +145,12 @@ pub trait TransactionPool: Send + Sync + Clone {
///
/// Consumer: P2P
fn on_propagated(&self, txs: PropagatedTransactions);
/// Returns all transactions sent by a given user
fn get_transactions_by_sender(
&self,
sender: Address,
) -> Vec<Arc<ValidPoolTransaction<Self::Transaction>>>;
}
/// Represents a transaction that was propagated over the network.