use std::collections::HashMap;
use ethrex_common::{Address, types::TxKind};
use ethrex_crypto::NativeCrypto;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use crate::{rpc::RpcApiContext, types::transaction::RpcTransaction, utils::RpcErr};
type MempoolContentEntry = HashMap<Address, HashMap<u64, RpcTransaction>>;
#[derive(Serialize, Deserialize)]
pub struct MempoolContent {
pub pending: MempoolContentEntry,
pub queued: MempoolContentEntry,
}
#[derive(Serialize, Deserialize)]
struct MempoolStatus {
pending: String,
queued: String,
}
type MempoolContentByNonce = HashMap<u64, RpcTransaction>;
#[derive(Serialize, Deserialize)]
pub struct MempoolContentFrom {
pub pending: MempoolContentByNonce,
pub queued: MempoolContentByNonce,
}
type MempoolInspectEntry = HashMap<Address, HashMap<u64, String>>;
#[derive(Serialize, Deserialize)]
pub struct MempoolInspect {
pub pending: MempoolInspectEntry,
pub queued: MempoolInspectEntry,
}
pub fn content(context: RpcApiContext) -> Result<Value, RpcErr> {
let transactions = context.blockchain.mempool.content()?;
let mut mempool_content = MempoolContentEntry::new();
for tx in transactions {
let sender_entry = mempool_content
.entry(tx.sender(&NativeCrypto)?)
.or_default();
sender_entry.insert(tx.nonce(), RpcTransaction::build(tx, None, None, None)?);
}
let response = MempoolContent {
pending: mempool_content,
queued: MempoolContentEntry::new(),
};
Ok(serde_json::to_value(response)?)
}
pub fn status(context: RpcApiContext) -> Result<Value, RpcErr> {
let pending = context.blockchain.mempool.status()?;
let queued = 0;
let response = MempoolStatus {
pending: format!("{pending:#x}"),
queued: format!("{queued:#x}"),
};
Ok(serde_json::to_value(response)?)
}
pub fn content_from(params: &Option<Vec<Value>>, context: RpcApiContext) -> Result<Value, RpcErr> {
let params = params
.as_ref()
.ok_or(RpcErr::BadParams("No params provided".to_owned()))?;
if params.len() != 1 {
return Err(RpcErr::BadParams(format!(
"Expected one param and {} were provided",
params.len()
)));
}
let address: Address = serde_json::from_value(params[0].clone())?;
let transactions = context.blockchain.mempool.content()?;
let mut by_nonce: MempoolContentByNonce = HashMap::new();
for tx in transactions {
if tx.sender(&NativeCrypto)? == address {
by_nonce.insert(tx.nonce(), RpcTransaction::build(tx, None, None, None)?);
}
}
let response = MempoolContentFrom {
pending: by_nonce,
queued: HashMap::new(),
};
Ok(serde_json::to_value(response)?)
}
pub fn inspect(context: RpcApiContext) -> Result<Value, RpcErr> {
let transactions = context.blockchain.mempool.content()?;
let mut pending: MempoolInspectEntry = HashMap::new();
for tx in transactions {
let sender = tx.sender(&NativeCrypto)?;
let gas_price = tx.gas_price();
let summary = match tx.to() {
TxKind::Call(to) => format!(
"{to:#x}: {} wei + {} gas × {} wei",
tx.value(),
tx.gas_limit(),
gas_price
),
TxKind::Create => format!(
"contract creation: {} wei + {} gas × {} wei",
tx.value(),
tx.gas_limit(),
gas_price
),
};
pending
.entry(sender)
.or_default()
.insert(tx.nonce(), summary);
}
let response = MempoolInspect {
pending,
queued: HashMap::new(),
};
Ok(serde_json::to_value(response)?)
}