Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5f2fe1a
Add optional verbose rpc logging
aodhgan Dec 17, 2025
da962b1
Update crates/anvil/src/eth/macros.rs
aodhgan Dec 18, 2025
0b5e8d6
Update crates/anvil/src/config.rs
aodhgan Dec 18, 2025
b7e3016
Update crates/anvil/src/server/rpc_handlers.rs
aodhgan Dec 18, 2025
2cb4823
Update crates/anvil/src/server/rpc_handlers.rs
aodhgan Dec 18, 2025
6bab50a
Update crates/anvil/src/cmd.rs
aodhgan Dec 18, 2025
cced230
refactor: extract try_into_request helper to reduce on_call duplication
Copilot Dec 18, 2025
33ec1b6
refactor: remove unnecessary local variables in on_call
Copilot Dec 18, 2025
7204ed2
Add comprehensive documentation to RpcCallLogContext struct and methods
Copilot Dec 18, 2025
36b4836
Add documentation to execute_with_raw and log_rpc_payload methods
Copilot Dec 18, 2025
90063c1
fix macro
gawnieg Dec 19, 2025
3d0f7c9
Update crates/anvil/src/cmd.rs
aodhgan Dec 19, 2025
07deb41
Maintain backward compatibility for RpcHandler::on_call method
Copilot Dec 19, 2025
19448ec
Fix trailing whitespace in documentation
Copilot Dec 19, 2025
c829079
Remove unused rpc_logging() method from NodeConfig
Copilot Dec 19, 2025
12e5549
Optimize RPC payload logging to avoid unnecessary cloning and JSON co…
Copilot Dec 19, 2025
529990e
Address code review feedback: fix double-wrapping and reduce unnecess…
Copilot Dec 19, 2025
9838d79
Improve code clarity with better naming and explanatory comments
Copilot Dec 19, 2025
425f84c
Ensure error logging also uses lazy raw JSON construction
Copilot Dec 19, 2025
f7af368
Fix raw request reuse in RPC logging
aodhgan Dec 19, 2025
ecb181c
Update crates/anvil/src/eth/api.rs
aodhgan Dec 19, 2025
6747e9f
Update crates/anvil/src/server/rpc_handlers.rs
aodhgan Dec 19, 2025
da8fada
Update crates/anvil/src/eth/api.rs
aodhgan Dec 19, 2025
dcef0c7
Update crates/anvil/src/cmd.rs
aodhgan Dec 19, 2025
d23b049
Eliminate unnecessary Value clone in RPC payload logging (#14)
Copilot Dec 19, 2025
b66b2a9
Refactor log_rpc_payload to eliminate redundant should_log_rpc_payloa…
Copilot Dec 19, 2025
609444c
Move lazy JSON construction inside log_rpc_payload to preserve optimi…
Copilot Dec 19, 2025
14e8e1f
Add log_rpc_payload_with_serialization to defer JSON serialization un…
Copilot Dec 19, 2025
1824328
cargo fmt
gawnieg Dec 21, 2025
5b84732
Fix intra-doc links in eth api docs
aodhgan Dec 21, 2025
4f5c060
clippy changes
gawnieg Dec 21, 2025
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
33 changes: 24 additions & 9 deletions crates/anvil/server/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ use anvil_rpc::{
};
use axum::{
Json,
extract::{State, rejection::JsonRejection},
extract::{ConnectInfo, State, rejection::JsonRejection},
};
use futures::{FutureExt, future};
use std::net::SocketAddr;

/// Handles incoming JSON-RPC Request.
// NOTE: `handler` must come first because the `request` extractor consumes the request body.
pub async fn handle<Http: RpcHandler, Ws>(
State((handler, _)): State<(Http, Ws)>,
ConnectInfo(peer_addr): ConnectInfo<SocketAddr>,
request: Result<Json<Request>, JsonRejection>,
) -> Json<Response> {
Json(match request {
Ok(Json(req)) => handle_request(req, handler)
Ok(Json(req)) => handle_request(req, handler, Some(peer_addr))
.await
.unwrap_or_else(|| Response::error(RpcError::invalid_request())),
Err(err) => {
Expand All @@ -34,6 +36,7 @@ pub async fn handle<Http: RpcHandler, Ws>(
pub async fn handle_request<Handler: RpcHandler>(
req: Request,
handler: Handler,
peer_addr: Option<SocketAddr>,
) -> Option<Response> {
/// processes batch calls
fn responses_as_batch(outs: Vec<Option<RpcResponse>>) -> Option<Response> {
Expand All @@ -42,21 +45,33 @@ pub async fn handle_request<Handler: RpcHandler>(
}

match req {
Request::Single(call) => handle_call(call, handler).await.map(Response::Single),
Request::Single(call) => handle_call(call, handler, peer_addr).await.map(Response::Single),
Request::Batch(calls) => {
future::join_all(calls.into_iter().map(move |call| handle_call(call, handler.clone())))
.map(responses_as_batch)
.await
future::join_all(
calls.into_iter().map(move |call| handle_call(call, handler.clone(), peer_addr)),
)
.map(responses_as_batch)
.await
}
}
}

/// handle a single RPC method call
async fn handle_call<Handler: RpcHandler>(call: RpcCall, handler: Handler) -> Option<RpcResponse> {
async fn handle_call<Handler: RpcHandler>(
call: RpcCall,
handler: Handler,
peer_addr: Option<SocketAddr>,
) -> Option<RpcResponse> {
match call {
RpcCall::MethodCall(call) => {
trace!(target: "rpc", id = ?call.id , method = ?call.method, "handling call");
Some(handler.on_call(call).await)
trace!(
target: "rpc",
id = ?call.id ,
method = ?call.method,
?peer_addr,
"handling call"
);
Some(handler.on_call_with_addr(call, peer_addr).await)
}
RpcCall::Notification(notification) => {
trace!(target: "rpc", method = ?notification.method, "received rpc notification");
Expand Down
31 changes: 29 additions & 2 deletions crates/anvil/server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use axum::{
routing::{MethodRouter, post},
};
use serde::de::DeserializeOwned;
use std::fmt;
use std::{fmt, net::SocketAddr};
use tower_http::{cors::CorsLayer, trace::TraceLayer};

mod config;
Expand Down Expand Up @@ -97,7 +97,34 @@ pub trait RpcHandler: Clone + Send + Sync + 'static {
/// **Note**: override this function if the expected `Request` deviates from `{ "method" :
/// "<name>", "params": "<params>" }`
async fn on_call(&self, call: RpcMethodCall) -> RpcResponse {
trace!(target: "rpc", id = ?call.id , method = ?call.method, params = ?call.params, "received method call");
// Default implementation delegates to on_call_with_addr with None
self.on_call_with_addr(call, None).await
}

/// Invoked for every incoming `RpcMethodCall` with peer address information
///
/// This method is similar to [`Self::on_call`] but includes the optional peer socket address,
/// which can be useful for logging, rate limiting, or other peer-specific logic.
///
/// The default implementation attempts to deserialize a `{ "method" : "<name>", "params":
/// "<params>" }` message into the `Request` type of this handler. If a `Request` instance
/// was deserialized successfully, [`Self::on_request`] will be invoked.
///
/// **Note**: override this function if you need access to the peer address or if the expected
/// `Request` deviates from `{ "method" : "<name>", "params": "<params>" }`
async fn on_call_with_addr(
&self,
call: RpcMethodCall,
peer_addr: Option<SocketAddr>,
) -> RpcResponse {
trace!(
target: "rpc",
id = ?call.id,
method = ?call.method,
params = ?call.params,
?peer_addr,
"received method call"
);
let RpcMethodCall { method, params, id, .. } = call;

let params: serde_json::Value = params.into();
Expand Down
2 changes: 1 addition & 1 deletion crates/anvil/server/src/pubsub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ impl<Handler: PubSubRpcHandler, Connection> PubSubConnection<Handler, Connection
let handler = self.compat_helper();
self.processing.push(Box::pin(async move {
match req {
Ok(req) => handle_request(req, handler)
Ok(req) => handle_request(req, handler, None)
.await
.unwrap_or_else(|| Response::error(RpcError::invalid_request())),
Err(err) => {
Expand Down
14 changes: 13 additions & 1 deletion crates/anvil/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,17 @@ pub struct NodeArgs {
/// Path to the cache directory where states are stored.
#[arg(long, value_name = "PATH")]
pub cache_path: Option<PathBuf>,

/// Enable verbose logging of all RPC request and response payloads, including parameters and
/// results.
///
/// This CLI flag controls the initial payload-level logging state at node startup. At runtime,
/// the `anvil_setLoggingEnabled` RPC method toggles both standard RPC logging and RPC payload
/// logging together, overriding the initial CLI setting. Once the node is running, standard
/// RPC logging and RPC payload logging cannot be controlled independently; they remain
/// permanently coupled for the lifetime of the process.
#[arg(long, help_heading = "Logging options")]
pub rpc_log: bool,
}

#[cfg(windows)]
Expand Down Expand Up @@ -283,7 +294,8 @@ impl NodeArgs {
.with_disable_pool_balance_checks(self.evm.disable_pool_balance_checks)
.with_slots_in_an_epoch(self.slots_in_an_epoch)
.with_memory_limit(self.evm.memory_limit)
.with_cache_path(self.cache_path))
.with_cache_path(self.cache_path)
.with_rpc_logging(self.rpc_log))
}

fn account_generator(&self) -> AccountGenerator {
Expand Down
11 changes: 11 additions & 0 deletions crates/anvil/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ pub struct NodeConfig {
pub silent: bool,
/// The path where states are cached.
pub cache_path: Option<PathBuf>,
/// Whether RPC request/response payload logging (via `rpc_log`) is enabled.
pub rpc_log: bool,
}

impl NodeConfig {
Expand Down Expand Up @@ -501,6 +503,7 @@ impl Default for NodeConfig {
networks: Default::default(),
silent: false,
cache_path: None,
rpc_log: false,
}
}
}
Expand All @@ -512,6 +515,7 @@ impl NodeConfig {
self.memory_limit = mems_value;
self
}

/// Returns the base fee to use
pub fn get_base_fee(&self) -> u64 {
self.base_fee
Expand Down Expand Up @@ -1051,6 +1055,13 @@ impl NodeConfig {
self
}

/// Sets whether RPC payload logging is enabled.
#[must_use]
pub fn with_rpc_logging(mut self, rpc_log: bool) -> Self {
self.rpc_log = rpc_log;
self
}

/// Configures everything related to env, backend and database and returns the
/// [Backend](mem::Backend)
///
Expand Down
Loading