Skip to content

Commit

Permalink
refactor: move GetTransactionCountArgs and `SendRawTransactionStatu…
Browse files Browse the repository at this point in the history
…s` to `evm_rpc_types` (#270)

Follow-up on #257 to move the types `GetTransactionCountArgs` and
`SendRawTransactionStatus` to the `evm_rpc_types` crate, so that the
public API of `eth_get_transaction_count` and
`eth_send_raw_transaction`, respectively, only uses types from that
crate.
  • Loading branch information
gregorydemay authored Sep 12, 2024
1 parent a98a9bf commit 98aed25
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 133 deletions.
2 changes: 2 additions & 0 deletions evm_rpc_types/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- v1.0 Move `BlockTag` to this crate.
- v1.0 Move `FeeHistoryArgs` and `FeeHistory` to this crate.
- v1.0 Move `GetLogsArgs` and `LogEntry` to this crate.
- v1.0 Move `GetTransactionCountArgs` to this crate.
- v1.0 Move `SendRawTransactionStatus` to this crate.
- v1.0 Move `TransactionReceipt` to this crate.
10 changes: 8 additions & 2 deletions evm_rpc_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use std::str::FromStr;
mod request;
mod response;

pub use request::{FeeHistoryArgs, GetLogsArgs};
pub use response::{Block, FeeHistory, LogEntry, TransactionReceipt};
pub use request::{FeeHistoryArgs, GetLogsArgs, GetTransactionCountArgs};
pub use response::{Block, FeeHistory, LogEntry, SendRawTransactionStatus, TransactionReceipt};

#[derive(Clone, Debug, PartialEq, Eq, CandidType, Deserialize, Default)]
pub enum BlockTag {
Expand Down Expand Up @@ -126,6 +126,12 @@ macro_rules! impl_hex_string {
}
}

impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}

impl CandidType for $name {
fn _ty() -> Type {
String::_ty()
Expand Down
6 changes: 6 additions & 0 deletions evm_rpc_types/src/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,9 @@ pub struct GetLogsArgs {
/// Each topic can also be an array of DATA with "or" options.
pub topics: Option<Vec<Vec<Hex32>>>,
}

#[derive(Clone, Debug, PartialEq, Eq, CandidType, Deserialize)]
pub struct GetTransactionCountArgs {
pub address: Hex20,
pub block: BlockTag,
}
8 changes: 8 additions & 0 deletions evm_rpc_types/src/response/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,11 @@ pub struct Block {
#[serde(default)]
pub uncles: Vec<Hex32>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, CandidType)]
pub enum SendRawTransactionStatus {
Ok(Option<Hex32>),
InsufficientFunds,
NonceTooLow,
NonceTooHigh,
}
44 changes: 17 additions & 27 deletions src/candid_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ mod cketh_conversion;
use async_trait::async_trait;
use candid::Nat;
use cketh_common::{
eth_rpc::{into_nat, Hash, ProviderError, RpcError, SendRawTransactionResult, ValidationError},
eth_rpc::{ProviderError, ValidationError},
eth_rpc_client::{
providers::{RpcApi, RpcService},
requests::GetTransactionCountParams,
EthRpcClient as CkEthRpcClient, MultiCallError, RpcConfig, RpcTransport,
},
lifecycle::EthereumNetwork,
};
use ethers_core::{types::Transaction, utils::rlp};
use evm_rpc_types::Hex32;
use evm_rpc_types::{Hex, Hex32};
use ic_cdk::api::management_canister::http_request::{CanisterHttpRequestArgument, HttpResponse};

use crate::{
Expand All @@ -25,11 +24,9 @@ use crate::{
http::http_request,
providers::resolve_rpc_service,
types::{
candid_types::{self, SendRawTransactionStatus},
MetricRpcHost, MetricRpcMethod, MultiRpcResult, ResolvedRpcService, RpcMethod, RpcResult,
RpcServices,
},
util::hex_to_bytes,
};

#[derive(Clone, Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -237,20 +234,19 @@ impl CandidRpcClient {

pub async fn eth_get_transaction_count(
&self,
args: candid_types::GetTransactionCountArgs,
) -> MultiRpcResult<candid::Nat> {
let args: GetTransactionCountParams = match args.try_into() {
Ok(args) => args,
Err(err) => return MultiRpcResult::Consistent(Err(RpcError::from(err))),
args: evm_rpc_types::GetTransactionCountArgs,
) -> MultiRpcResult<evm_rpc_types::Nat256> {
use crate::candid_rpc::cketh_conversion::{
from_checked_amount_of, into_get_transaction_count_params,
};
process_result(
RpcMethod::EthGetTransactionCount,
self.client
.eth_get_transaction_count(args)
.eth_get_transaction_count(into_get_transaction_count_params(args))
.await
.reduce_with_equality(),
)
.map(|count| into_nat(count.into_inner()))
.map(from_checked_amount_of)
}

pub async fn eth_fee_history(
Expand All @@ -269,35 +265,29 @@ impl CandidRpcClient {

pub async fn eth_send_raw_transaction(
&self,
raw_signed_transaction_hex: String,
) -> MultiRpcResult<candid_types::SendRawTransactionStatus> {
raw_signed_transaction_hex: Hex,
) -> MultiRpcResult<evm_rpc_types::SendRawTransactionStatus> {
use crate::candid_rpc::cketh_conversion::from_send_raw_transaction_result;
let transaction_hash = get_transaction_hash(&raw_signed_transaction_hex);
process_result(
RpcMethod::EthSendRawTransaction,
self.client
.multi_eth_send_raw_transaction(raw_signed_transaction_hex)
.multi_eth_send_raw_transaction(raw_signed_transaction_hex.to_string())
.await,
)
.map(|result| match result {
SendRawTransactionResult::Ok => SendRawTransactionStatus::Ok(transaction_hash),
SendRawTransactionResult::InsufficientFunds => {
SendRawTransactionStatus::InsufficientFunds
}
SendRawTransactionResult::NonceTooLow => SendRawTransactionStatus::NonceTooLow,
SendRawTransactionResult::NonceTooHigh => SendRawTransactionStatus::NonceTooHigh,
})
.map(|result| from_send_raw_transaction_result(transaction_hash.clone(), result))
}
}

fn get_transaction_hash(raw_signed_transaction_hex: &str) -> Option<Hash> {
let bytes = hex_to_bytes(raw_signed_transaction_hex)?;
let transaction: Transaction = rlp::decode(&bytes).ok()?;
Some(Hash(transaction.hash.0))
fn get_transaction_hash(raw_signed_transaction_hex: &Hex) -> Option<Hex32> {
let transaction: Transaction = rlp::decode(raw_signed_transaction_hex.as_ref()).ok()?;
Some(Hex32::from(transaction.hash.0))
}

#[cfg(test)]
mod test {
use super::*;
use cketh_common::eth_rpc::RpcError;

#[test]
fn test_process_result_mapping() {
Expand Down
31 changes: 30 additions & 1 deletion src/candid_rpc/cketh_conversion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ pub(super) fn from_fee_history(
}
}

pub(super) fn into_get_transaction_count_params(
value: evm_rpc_types::GetTransactionCountArgs,
) -> cketh_common::eth_rpc_client::requests::GetTransactionCountParams {
cketh_common::eth_rpc_client::requests::GetTransactionCountParams {
address: cketh_common::address::Address::new(value.address.into()),
block: into_block_spec(value.block),
}
}

pub(super) fn from_transaction_receipt(
value: cketh_common::eth_rpc_client::responses::TransactionReceipt,
) -> evm_rpc_types::TransactionReceipt {
Expand Down Expand Up @@ -157,6 +166,26 @@ pub(super) fn from_block(value: cketh_common::eth_rpc::Block) -> evm_rpc_types::
}
}

pub(super) fn from_send_raw_transaction_result(
transaction_hash: Option<Hex32>,
value: cketh_common::eth_rpc::SendRawTransactionResult,
) -> evm_rpc_types::SendRawTransactionStatus {
match value {
cketh_common::eth_rpc::SendRawTransactionResult::Ok => {
evm_rpc_types::SendRawTransactionStatus::Ok(transaction_hash)
}
cketh_common::eth_rpc::SendRawTransactionResult::InsufficientFunds => {
evm_rpc_types::SendRawTransactionStatus::InsufficientFunds
}
cketh_common::eth_rpc::SendRawTransactionResult::NonceTooLow => {
evm_rpc_types::SendRawTransactionStatus::NonceTooLow
}
cketh_common::eth_rpc::SendRawTransactionResult::NonceTooHigh => {
evm_rpc_types::SendRawTransactionStatus::NonceTooHigh
}
}
}

pub(super) fn into_hash(value: Hex32) -> Hash {
Hash(value.into())
}
Expand All @@ -165,7 +194,7 @@ fn into_checked_amount_of<Unit>(value: Nat256) -> CheckedAmountOf<Unit> {
CheckedAmountOf::from_be_bytes(value.into_be_bytes())
}

fn from_checked_amount_of<Unit>(value: CheckedAmountOf<Unit>) -> Nat256 {
pub(super) fn from_checked_amount_of<Unit>(value: CheckedAmountOf<Unit>) -> Nat256 {
Nat256::from_be_bytes(value.to_be_bytes())
}

Expand Down
10 changes: 5 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use ic_nervous_system_common::serve_metrics;
use evm_rpc::{
http::{json_rpc_request, transform_http_request},
memory::UNSTABLE_METRICS,
types::{candid_types, InitArgs, MetricRpcMethod, Metrics, MultiRpcResult, RpcServices},
types::{InitArgs, MetricRpcMethod, Metrics, MultiRpcResult, RpcServices},
};
use evm_rpc_types::Hex32;

Expand Down Expand Up @@ -83,8 +83,8 @@ pub async fn eth_get_transaction_receipt(
pub async fn eth_get_transaction_count(
source: RpcServices,
config: Option<RpcConfig>,
args: candid_types::GetTransactionCountArgs,
) -> MultiRpcResult<candid::Nat> {
args: evm_rpc_types::GetTransactionCountArgs,
) -> MultiRpcResult<evm_rpc_types::Nat256> {
match CandidRpcClient::new(source, config) {
Ok(source) => source.eth_get_transaction_count(args).await,
Err(err) => Err(err).into(),
Expand All @@ -109,8 +109,8 @@ pub async fn eth_fee_history(
pub async fn eth_send_raw_transaction(
source: RpcServices,
config: Option<RpcConfig>,
raw_signed_transaction_hex: String,
) -> MultiRpcResult<candid_types::SendRawTransactionStatus> {
raw_signed_transaction_hex: evm_rpc_types::Hex,
) -> MultiRpcResult<evm_rpc_types::SendRawTransactionStatus> {
match CandidRpcClient::new(source, config) {
Ok(source) => {
source
Expand Down
64 changes: 0 additions & 64 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,70 +443,6 @@ pub enum RpcServices {
OptimismMainnet(Option<Vec<L2MainnetService>>),
}

pub mod candid_types {
use std::str::FromStr;

use candid::CandidType;
use cketh_common::{address::Address, eth_rpc::ValidationError, numeric::BlockNumber};
use serde::Deserialize;

pub use cketh_common::eth_rpc::Hash;

#[derive(Clone, Debug, PartialEq, Eq, CandidType, Deserialize, Default)]
pub enum BlockTag {
#[default]
Latest,
Finalized,
Safe,
Earliest,
Pending,
Number(BlockNumber),
}

impl From<BlockTag> for cketh_common::eth_rpc::BlockSpec {
fn from(value: BlockTag) -> Self {
use cketh_common::eth_rpc::{self, BlockSpec};
match value {
BlockTag::Number(n) => BlockSpec::Number(n),
BlockTag::Latest => BlockSpec::Tag(eth_rpc::BlockTag::Latest),
BlockTag::Safe => BlockSpec::Tag(eth_rpc::BlockTag::Safe),
BlockTag::Finalized => BlockSpec::Tag(eth_rpc::BlockTag::Finalized),
BlockTag::Earliest => BlockSpec::Tag(eth_rpc::BlockTag::Earliest),
BlockTag::Pending => BlockSpec::Tag(eth_rpc::BlockTag::Pending),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, CandidType, Deserialize)]
pub struct GetTransactionCountArgs {
pub address: String,
pub block: BlockTag,
}

impl TryFrom<GetTransactionCountArgs>
for cketh_common::eth_rpc_client::requests::GetTransactionCountParams
{
type Error = ValidationError;
fn try_from(value: GetTransactionCountArgs) -> Result<Self, Self::Error> {
Ok(
cketh_common::eth_rpc_client::requests::GetTransactionCountParams {
address: Address::from_str(&value.address)
.map_err(|_| ValidationError::InvalidHex(value.address))?,
block: value.block.into(),
},
)
}
}

#[derive(Debug, Clone, PartialEq, Eq, CandidType, Deserialize)]
pub enum SendRawTransactionStatus {
Ok(Option<Hash>),
InsufficientFunds,
NonceTooLow,
NonceTooHigh,
}
}

#[cfg(test)]
mod test {
use cketh_common::{
Expand Down
Loading

0 comments on commit 98aed25

Please sign in to comment.