mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-29 00:58:11 -05:00
rpc: add missing fields in send_transaction (#1976)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
committed by
GitHub
parent
7c6c0b41e8
commit
481f60acee
@@ -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(
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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()),
|
||||
);
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user