diff --git a/evm_rpc_client/src/lib.rs b/evm_rpc_client/src/lib.rs index 9487ca30..e266d8ca 100644 --- a/evm_rpc_client/src/lib.rs +++ b/evm_rpc_client/src/lib.rs @@ -130,7 +130,6 @@ use evm_rpc_types::{ use ic_error_types::RejectCode; #[cfg(feature = "alloy")] pub use request::alloy::AlloyResponseConverter; -pub use request::CandidResponseConverter; use request::{ CallRequest, CallRequestBuilder, EvmRpcResponseConverter, FeeHistoryRequest, FeeHistoryRequestBuilder, GetBlockByNumberRequest, GetBlockByNumberRequestBuilder, @@ -139,6 +138,7 @@ use request::{ GetTransactionReceiptRequestBuilder, JsonRequest, JsonRequestBuilder, Request, RequestBuilder, SendRawTransactionRequest, SendRawTransactionRequestBuilder, }; +pub use request::{CandidResponseConverter, EvmRpcConfig}; pub use runtime::{IcRuntime, Runtime}; use serde::de::DeserializeOwned; use std::sync::Arc; diff --git a/evm_rpc_client/src/request/mod.rs b/evm_rpc_client/src/request/mod.rs index dc3e5086..244a9aff 100644 --- a/evm_rpc_client/src/request/mod.rs +++ b/evm_rpc_client/src/request/mod.rs @@ -4,8 +4,8 @@ pub(crate) mod alloy; use crate::{EvmRpcClient, Runtime}; use candid::CandidType; use evm_rpc_types::{ - BlockTag, CallArgs, FeeHistoryArgs, GetLogsArgs, GetLogsRpcConfig, GetTransactionCountArgs, - Hex, Hex20, Hex32, MultiRpcResult, Nat256, RpcConfig, RpcServices, + BlockTag, CallArgs, ConsensusStrategy, FeeHistoryArgs, GetLogsArgs, GetLogsRpcConfig, + GetTransactionCountArgs, Hex, Hex20, Hex32, MultiRpcResult, Nat256, RpcConfig, RpcServices, }; use ic_error_types::RejectCode; use serde::de::DeserializeOwned; @@ -531,6 +531,73 @@ impl } } +/// Common behavior for the RPC config for EVM RPC canister endpoints. +pub trait EvmRpcConfig { + /// Return a new RPC config with the given response size estimate. + fn with_response_size_estimate(self, response_size_estimate: u64) -> Self; + + /// Return a new RPC config with the given response consensys. + fn with_response_consensus(self, response_consensus: ConsensusStrategy) -> Self; +} + +impl EvmRpcConfig for RpcConfig { + fn with_response_size_estimate(self, response_size_estimate: u64) -> Self { + Self { + response_size_estimate: Some(response_size_estimate), + ..self + } + } + + fn with_response_consensus(self, response_consensus: ConsensusStrategy) -> Self { + Self { + response_consensus: Some(response_consensus), + ..self + } + } +} + +impl EvmRpcConfig for GetLogsRpcConfig { + fn with_response_size_estimate(self, response_size_estimate: u64) -> Self { + Self { + response_size_estimate: Some(response_size_estimate), + ..self + } + } + + fn with_response_consensus(self, response_consensus: ConsensusStrategy) -> Self { + Self { + response_consensus: Some(response_consensus), + ..self + } + } +} + +impl + RequestBuilder +{ + /// Change the response size estimate to use for that request. + pub fn with_response_size_estimate(mut self, response_size_estimate: u64) -> Self { + self.request.rpc_config = Some( + self.request + .rpc_config + .unwrap_or_default() + .with_response_size_estimate(response_size_estimate), + ); + self + } + + /// Change the consensus strategy to use for that request. + pub fn with_response_consensus(mut self, response_consensus: ConsensusStrategy) -> Self { + self.request.rpc_config = Some( + self.request + .rpc_config + .unwrap_or_default() + .with_response_consensus(response_consensus), + ); + self + } +} + /// A request which can be executed with `EvmRpcClient::execute_request` or `EvmRpcClient::execute_query_request`. pub struct Request { pub(super) endpoint: EvmRpcEndpoint, diff --git a/tests/tests.rs b/tests/tests.rs index 67878010..878b57b7 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1270,15 +1270,15 @@ async fn candid_rpc_should_return_3_out_of_4_transaction_count() { setup .client(mocks) .with_rpc_sources(RpcServices::EthMainnet(None)) - .with_consensus_strategy(ConsensusStrategy::Threshold { - total: Some(4), - min: 3, - }) .build() .get_transaction_count(( address!("0xdac17f958d2ee523a2206206994597c13d831ec7"), BlockNumberOrTag::Latest, )) + .with_response_consensus(ConsensusStrategy::Threshold { + total: Some(4), + min: 3, + }) .send() .await } @@ -1432,15 +1432,15 @@ async fn candid_rpc_should_return_inconsistent_results_with_consensus_error() { let result = setup .client(mocks) .with_rpc_sources(RpcServices::EthMainnet(None)) - .with_consensus_strategy(ConsensusStrategy::Threshold { - total: Some(3), - min: 2, - }) .build() .get_transaction_count(( address!("0xdac17f958d2ee523a2206206994597c13d831ec7"), BlockNumberOrTag::Latest, )) + .with_response_consensus(ConsensusStrategy::Threshold { + total: Some(3), + min: 2, + }) .send() .await .expect_inconsistent(); @@ -1683,31 +1683,40 @@ async fn candid_rpc_should_recognize_rate_limit() { #[tokio::test] async fn should_use_custom_response_size_estimate() { let setup = EvmRpcSetup::new().await.mock_api_keys().await; - let max_response_bytes = 1234; - let expected_response = r#"{"id":0,"jsonrpc":"2.0","result":[{"address":"0xdac17f958d2ee523a2206206994597c13d831ec7","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000a9d1e08c7793af67e9d92fe308d5697fb81d3e43","0x00000000000000000000000078cccfb3d517cd4ed6d045e263e134712288ace2"],"data":"0x000000000000000000000000000000000000000000000000000000003b9c6433","blockNumber":"0x11dc77e","transactionHash":"0xf3ed91a03ddf964281ac7a24351573efd535b80fc460a5c2ad2b9d23153ec678","transactionIndex":"0x65","blockHash":"0xd5c72ad752b2f0144a878594faf8bd9f570f2f72af8e7f0940d3545a6388f629","logIndex":"0xe8","removed":false}]}"#; + let [max_response_bytes_1, max_response_bytes_2] = [1234_u64, 5678]; let mocks = MockHttpOutcallsBuilder::new() .given( - JsonRpcRequestMatcher::with_method("eth_getLogs") - .with_id(0_u64) - .with_params(json!([{ - "address" : ["0xdac17f958d2ee523a2206206994597c13d831ec7"], - "fromBlock": "latest", - "toBlock": "latest", - }])) - .with_max_response_bytes(max_response_bytes), + get_logs_request(BlockNumberOrTag::Latest, BlockNumberOrTag::Latest) + .with_max_response_bytes(max_response_bytes_1) + .with_id(0_u64), + ) + .respond_with(get_logs_response().with_id(0_u64)) + .given( + get_logs_request(BlockNumberOrTag::Latest, BlockNumberOrTag::Latest) + .with_max_response_bytes(max_response_bytes_2) + .with_id(1_u64), ) - .respond_with(JsonRpcResponse::from(expected_response)); + .respond_with(get_logs_response().with_id(1_u64)); let client = setup .client(mocks) .with_rpc_sources(RpcServices::EthMainnet(Some(vec![ EthMainnetService::Cloudflare, ]))) - .with_response_size_estimate(max_response_bytes) + .with_response_size_estimate(max_response_bytes_1) .build(); + + let response = client + .get_logs(vec![address!("0xdAC17F958D2ee523a2206206994597C13D831ec7")]) + .send() + .await + .expect_consistent(); + assert_matches!(response, Ok(_)); + let response = client .get_logs(vec![address!("0xdAC17F958D2ee523a2206206994597C13D831ec7")]) + .with_response_size_estimate(max_response_bytes_2) .send() .await .expect_consistent();