Skip to content

Commit

Permalink
Merge CallRequst and TransactionRequest RPC types
Browse files Browse the repository at this point in the history
  • Loading branch information
koushiro committed Feb 19, 2024
1 parent 7c7cfce commit 6a63efd
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 279 deletions.
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions client/rpc-core/src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ pub trait EthApi {
#[method(name = "eth_call")]
async fn call(
&self,
request: CallRequest,
request: TransactionRequest,
number_or_hash: Option<BlockNumberOrHash>,
state_overrides: Option<BTreeMap<H160, CallStateOverride>>,
) -> RpcResult<Bytes>;
Expand All @@ -198,7 +198,7 @@ pub trait EthApi {
#[method(name = "eth_estimateGas")]
async fn estimate_gas(
&self,
request: CallRequest,
request: TransactionRequest,
number_or_hash: Option<BlockNumberOrHash>,
) -> RpcResult<U256>;

Expand Down
132 changes: 2 additions & 130 deletions client/rpc-core/src/types/call_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,10 @@

use std::collections::BTreeMap;

use ethereum::AccessListItem;
use ethereum_types::{H160, H256, U256};
use ethereum_types::{H256, U256};
use serde::Deserialize;

use crate::types::{deserialize_data_or_input, Bytes};

/// Call request
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CallRequest {
/// From
pub from: Option<H160>,
/// To
pub to: Option<H160>,
/// Gas Price
pub gas_price: Option<U256>,
/// EIP-1559 Max base fee the caller is willing to pay
pub max_fee_per_gas: Option<U256>,
/// EIP-1559 Priority fee the caller is paying to the block author
pub max_priority_fee_per_gas: Option<U256>,
/// Gas
pub gas: Option<U256>,
/// Value
pub value: Option<U256>,
/// Data
#[serde(deserialize_with = "deserialize_data_or_input", flatten)]
pub data: Option<Bytes>,
/// Nonce
pub nonce: Option<U256>,
/// AccessList
pub access_list: Option<Vec<AccessListItem>>,
/// EIP-2718 type
#[serde(rename = "type")]
pub transaction_type: Option<U256>,
}
use crate::types::Bytes;

// State override
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)]
Expand All @@ -72,100 +41,3 @@ pub struct CallStateOverride {
/// executing the call.
pub state_diff: Option<BTreeMap<H256, H256>>,
}

#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;

#[test]
fn test_deserialize_with_only_input() {
let data = json!({
"from": "0x60be2d1d3665660d22ff9624b7be0551ee1ac91b",
"to": "0x13fe2d1d3665660d22ff9624b7be0551ee1ac91b",
"gasPrice": "0x10",
"maxFeePerGas": "0x20",
"maxPriorityFeePerGas": "0x30",
"gas": "0x40",
"value": "0x50",
"input": "0x123abc",
"nonce": "0x60",
"accessList": [{"address": "0x60be2d1d3665660d22ff9624b7be0551ee1ac91b", "storageKeys": []}],
"type": "0x70"
});

let request: Result<CallRequest, _> = serde_json::from_value(data);
assert!(request.is_ok());

let request = request.unwrap();
assert_eq!(request.data, Some(Bytes::from(vec![0x12, 0x3a, 0xbc])));
}

#[test]
fn test_deserialize_with_only_data() {
let data = json!({
"from": "0x60be2d1d3665660d22ff9624b7be0551ee1ac91b",
"to": "0x13fe2d1d3665660d22ff9624b7be0551ee1ac91b",
"gasPrice": "0x10",
"maxFeePerGas": "0x20",
"maxPriorityFeePerGas": "0x30",
"gas": "0x40",
"value": "0x50",
"data": "0x123abc",
"nonce": "0x60",
"accessList": [{"address": "0x60be2d1d3665660d22ff9624b7be0551ee1ac91b", "storageKeys": []}],
"type": "0x70"
});

let request: Result<CallRequest, _> = serde_json::from_value(data);
assert!(request.is_ok());

let request = request.unwrap();
assert_eq!(request.data, Some(Bytes::from(vec![0x12, 0x3a, 0xbc])));
}

#[test]
fn test_deserialize_with_data_and_input_mismatch() {
let data = json!({
"from": "0x60be2d1d3665660d22ff9624b7be0551ee1ac91b",
"to": "0x13fe2d1d3665660d22ff9624b7be0551ee1ac91b",
"gasPrice": "0x10",
"maxFeePerGas": "0x20",
"maxPriorityFeePerGas": "0x30",
"gas": "0x40",
"value": "0x50",
"data": "0x123abc",
"input": "0x456def",
"nonce": "0x60",
"accessList": [{"address": "0x60be2d1d3665660d22ff9624b7be0551ee1ac91b", "storageKeys": []}],
"type": "0x70"
});

let request: Result<CallRequest, _> = serde_json::from_value(data);
assert!(request.is_err());
}

#[test]
fn test_deserialize_with_data_and_input_equal() {
let data = json!({
"from": "0x60be2d1d3665660d22ff9624b7be0551ee1ac91b",
"to": "0x13fe2d1d3665660d22ff9624b7be0551ee1ac91b",
"gasPrice": "0x10",
"maxFeePerGas": "0x20",
"maxPriorityFeePerGas": "0x30",
"gas": "0x40",
"value": "0x50",
"data": "0x123abc",
"input": "0x123abc",
"nonce": "0x60",
"accessList": [{"address": "0x60be2d1d3665660d22ff9624b7be0551ee1ac91b", "storageKeys": []}],
"type": "0x70"
});

let request: Result<CallRequest, _> = serde_json::from_value(data);
assert!(request.is_ok());

let request = request.unwrap();
assert_eq!(request.data, Some(Bytes::from(vec![0x12, 0x3a, 0xbc])));
}
}
29 changes: 1 addition & 28 deletions client/rpc-core/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ pub mod pubsub;

use ethereum::TransactionV2 as EthereumTransaction;
use ethereum_types::H160;
use serde::{de::Error, Deserialize, Deserializer};

#[cfg(feature = "txpool")]
pub use self::txpool::{Summary, TransactionMap, TxPoolResult};
Expand All @@ -48,7 +47,7 @@ pub use self::{
block::{Block, BlockTransactions, Header, Rich, RichBlock, RichHeader},
block_number::BlockNumberOrHash,
bytes::Bytes,
call_request::{CallRequest, CallStateOverride},
call_request::CallStateOverride,
fee::{FeeHistory, FeeHistoryCache, FeeHistoryCacheItem, FeeHistoryCacheLimit},
filter::{
Filter, FilterAddress, FilterChanges, FilterPool, FilterPoolItem, FilterType,
Expand All @@ -66,32 +65,6 @@ pub use self::{
work::Work,
};

#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize)]
pub(crate) struct CallOrInputData {
data: Option<Bytes>,
input: Option<Bytes>,
}

/// Function to deserialize `data` and `input` within `TransactionRequest` and `CallRequest`.
/// It verifies that if both `data` and `input` are provided, they must be identical.
pub(crate) fn deserialize_data_or_input<'d, D: Deserializer<'d>>(
d: D,
) -> Result<Option<Bytes>, D::Error> {
let CallOrInputData { data, input } = CallOrInputData::deserialize(d)?;
match (&data, &input) {
(Some(data), Some(input)) => {
if data == input {
Ok(Some(data.clone()))
} else {
Err(D::Error::custom(
"Ambiguous value for `data` and `input`".to_string(),
))
}
}
(_, _) => Ok(data.or(input)),
}
}

/// The trait that used to build types from the `from` address and ethereum `transaction`.
pub trait BuildFrom {
fn build_from(from: H160, transaction: &EthereumTransaction) -> Self;
Expand Down
Loading

0 comments on commit 6a63efd

Please sign in to comment.