Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Move InstallArgs and Provider to the evm_rpc_types crate #299

Merged
merged 3 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion Cargo.lock

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

28 changes: 15 additions & 13 deletions evm_rpc_types/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,25 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [1.0.0] - 2024-10-07

### Added

- v1.0 `Nat256`: transparent wrapper around a `Nat` to guarantee that it fits in 256 bits.
- v1.0 `HexByte`, `Hex20`, `Hex32`, `Hex256` and `Hex` : Candid types wrapping an amount of bytes (`u8` for `HexByte`,
- v1.0.0 Move `InstallArgs` and associated types to this crate.
- v1.0.0 Move `Provider` and associated types to this crate.
- v1.0.0 `Nat256`: transparent wrapper around a `Nat` to guarantee that it fits in 256 bits.
- v1.0.0 `HexByte`, `Hex20`, `Hex32`, `Hex256` and `Hex` : Candid types wrapping an amount of bytes (`u8` for `HexByte`,
`[u8; N]` for `HexN`, and `Vec<u8>` for `Hex`) that can be represented as an hexadecimal string (prefixed by `0x`)
when serialized.
- v1.0 Move `Block` to this crate.
- 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 `RpcConfig` to this crate.
- v1.0 Move `SendRawTransactionStatus` to this crate.
- v1.0 Move `TransactionReceipt` to this crate.
- v1.0 Move providers-related types `EthMainnetService`, `EthSepoliaService`, `HttpHeader`, `L2MainnetService`,
- v1.0.0 Move `Block` to this crate.
- v1.0.0 Move `BlockTag` to this crate.
- v1.0.0 Move `FeeHistoryArgs` and `FeeHistory` to this crate.
- v1.0.0 Move `GetLogsArgs` and `LogEntry` to this crate.
- v1.0.0 Move `GetTransactionCountArgs` to this crate.
- v1.0.0 Move `RpcConfig` to this crate.
- v1.0.0 Move `SendRawTransactionStatus` to this crate.
- v1.0.0 Move `TransactionReceipt` to this crate.
- v1.0.0 Move providers-related types `EthMainnetService`, `EthSepoliaService`, `HttpHeader`, `L2MainnetService`,
`RpcApi`, `RpcConfig`, `RpcService`, `RpcServices` to this crate.
- v1.0 Move result-related types `HttpOutcallError`, `JsonRpcError`, `MultiRpcResult`, `ProviderError`, `RpcError`,
- v1.0.0 Move result-related types `HttpOutcallError`, `JsonRpcError`, `MultiRpcResult`, `ProviderError`, `RpcError`,
`RpcResult`, `ValidationError` to this crate.
9 changes: 7 additions & 2 deletions evm_rpc_types/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
[package]
name = "evm_rpc_types"
version = "0.1.0"
version = "1.0.0"
description = "Candid types for interacting with the EVM RPC canister"
authors = ["DFINITY Foundation"]
license = "Apache-2.0"
readme = "README.md"
authors = ["DFINITY Foundation"]
edition = "2021"
include = ["src", "Cargo.toml", "CHANGELOG.md", "LICENSE", "README.md"]
repository = "https://github.com/dfinity/ic"
documentation = "https://docs.rs/evm_rpc_types"


[dependencies]
candid = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions evm_rpc_types/LICENSE
6 changes: 4 additions & 2 deletions evm_rpc_types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[cfg(test)]
mod tests;

mod lifecycle;
mod request;
mod response;
mod result;
Expand All @@ -14,15 +15,16 @@ use serde::{Deserialize, Serialize};
use std::fmt::Formatter;
use std::str::FromStr;

pub use lifecycle::{InstallArgs, LogFilter, RegexString};
pub use request::{BlockTag, FeeHistoryArgs, GetLogsArgs, GetTransactionCountArgs};
pub use response::{Block, FeeHistory, LogEntry, SendRawTransactionStatus, TransactionReceipt};
pub use result::{
HttpOutcallError, JsonRpcError, MultiRpcResult, ProviderError, RpcError, RpcResult,
ValidationError,
};
pub use rpc_client::{
ConsensusStrategy, EthMainnetService, EthSepoliaService, HttpHeader, L2MainnetService, RpcApi,
RpcConfig, RpcService, RpcServices,
ConsensusStrategy, EthMainnetService, EthSepoliaService, HttpHeader, L2MainnetService,
Provider, RpcAccess, RpcApi, RpcAuth, RpcConfig, RpcService, RpcServices,
};

/// A `Nat` that is guaranteed to fit in 256 bits.
Expand Down
22 changes: 22 additions & 0 deletions evm_rpc_types/src/lifecycle/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use candid::{CandidType, Principal};
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Default, CandidType, Deserialize)]
pub struct InstallArgs {
pub demo: Option<bool>,
#[serde(rename = "manageApiKeys")]
pub manage_api_keys: Option<Vec<Principal>>,
#[serde(rename = "logFilter")]
pub log_filter: Option<LogFilter>,
}

#[derive(Clone, Debug, PartialEq, Eq, CandidType, Serialize, Deserialize)]
pub enum LogFilter {
ShowAll,
HideAll,
ShowPattern(RegexString),
HidePattern(RegexString),
}

#[derive(Clone, Debug, PartialEq, Eq, CandidType, Serialize, Deserialize)]
pub struct RegexString(pub String);
37 changes: 36 additions & 1 deletion evm_rpc_types/src/rpc_client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pub enum RpcService {
OptimismMainnet(L2MainnetService),
}

impl std::fmt::Debug for RpcService {
impl Debug for RpcService {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RpcService::Provider(provider_id) => write!(f, "Provider({})", provider_id),
Expand All @@ -168,3 +168,38 @@ impl std::fmt::Debug for RpcService {
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, CandidType, Serialize)]
pub struct Provider {
#[serde(rename = "providerId")]
pub provider_id: u64,
#[serde(rename = "chainId")]
pub chain_id: u64,
pub access: RpcAccess,
pub alias: Option<RpcService>,
}

#[derive(Debug, Clone, PartialEq, Eq, CandidType, Serialize)]
pub enum RpcAccess {
Authenticated {
auth: RpcAuth,
/// Public URL to use when the API key is not available.
#[serde(rename = "publicUrl")]
public_url: Option<String>,
},
Unauthenticated {
#[serde(rename = "publicUrl")]
public_url: String,
},
}

#[derive(Debug, Clone, PartialEq, Eq, CandidType, Serialize)]
pub enum RpcAuth {
/// API key will be used in an Authorization header as Bearer token, e.g.,
/// `Authorization: Bearer API_KEY`
BearerToken { url: String },
UrlParameter {
#[serde(rename = "urlPattern")]
url_pattern: String,
},
}
41 changes: 35 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use evm_rpc::memory::{
};
use evm_rpc::metrics::encode_metrics;
use evm_rpc::providers::{find_provider, resolve_rpc_service, PROVIDERS, SERVICE_PROVIDER_MAP};
use evm_rpc::types::{InstallArgs, Provider, ProviderId, RpcAccess};
use evm_rpc::types::{LogFilter, Provider, ProviderId, RpcAccess, RpcAuth};
use evm_rpc::{
http::{json_rpc_request, transform_http_request},
http_types,
Expand Down Expand Up @@ -151,8 +151,37 @@ fn request_cost(

#[query(name = "getProviders")]
#[candid_method(query, rename = "getProviders")]
fn get_providers() -> Vec<Provider> {
PROVIDERS.to_vec()
fn get_providers() -> Vec<evm_rpc_types::Provider> {
fn into_provider(provider: Provider) -> evm_rpc_types::Provider {
evm_rpc_types::Provider {
provider_id: provider.provider_id,
chain_id: provider.chain_id,
access: match provider.access {
RpcAccess::Authenticated { auth, public_url } => {
evm_rpc_types::RpcAccess::Authenticated {
auth: match auth {
RpcAuth::BearerToken { url } => evm_rpc_types::RpcAuth::BearerToken {
url: url.to_string(),
},
RpcAuth::UrlParameter { url_pattern } => {
evm_rpc_types::RpcAuth::UrlParameter {
url_pattern: url_pattern.to_string(),
}
}
},
public_url: public_url.map(|s| s.to_string()),
}
}
RpcAccess::Unauthenticated { public_url } => {
evm_rpc_types::RpcAccess::Unauthenticated {
public_url: public_url.to_string(),
}
}
},
alias: provider.alias,
}
}
PROVIDERS.iter().cloned().map(into_provider).collect()
}

#[query(name = "getServiceProviderMap")]
Expand Down Expand Up @@ -214,20 +243,20 @@ fn transform(args: TransformArgs) -> HttpResponse {
}

#[ic_cdk::init]
fn init(args: InstallArgs) {
fn init(args: evm_rpc_types::InstallArgs) {
post_upgrade(args);
}

#[ic_cdk::post_upgrade]
fn post_upgrade(args: InstallArgs) {
fn post_upgrade(args: evm_rpc_types::InstallArgs) {
if let Some(demo) = args.demo {
set_demo_active(demo);
}
if let Some(principals) = args.manage_api_keys {
set_api_key_principals(principals);
}
if let Some(filter) = args.log_filter {
set_log_filter(filter)
set_log_filter(LogFilter::from(filter))
}
}

Expand Down
70 changes: 36 additions & 34 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::constants::{API_KEY_MAX_SIZE, API_KEY_REPLACE_STRING, MESSAGE_FILTER_
use crate::memory::get_api_key;
use crate::util::hostname_from_url;
use crate::validate::validate_api_key;
use candid::{CandidType, Principal};
use candid::CandidType;
use ic_cdk::api::management_canister::http_request::HttpHeader;
use ic_stable_structures::storable::Bound;
use ic_stable_structures::Storable;
Expand All @@ -13,15 +13,6 @@ use std::collections::HashMap;
use std::fmt;
use zeroize::{Zeroize, ZeroizeOnDrop};

#[derive(Clone, Debug, Default, CandidType, Deserialize)]
pub struct InstallArgs {
pub demo: Option<bool>,
#[serde(rename = "manageApiKeys")]
pub manage_api_keys: Option<Vec<Principal>>,
#[serde(rename = "logFilter")]
pub log_filter: Option<LogFilter>,
}

pub enum ResolvedRpcService {
Api(evm_rpc_types::RpcApi),
Provider(Provider),
Expand Down Expand Up @@ -223,11 +214,9 @@ impl<'a> From<&'a ConstHeader> for HttpHeader {
}

/// Internal RPC provider representation.
#[derive(Debug, Clone, PartialEq, Eq, CandidType, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Provider {
#[serde(rename = "providerId")]
pub provider_id: ProviderId,
#[serde(rename = "chainId")]
pub chain_id: u64,
pub access: RpcAccess,
pub alias: Option<evm_rpc_types::RpcService>,
Expand Down Expand Up @@ -280,16 +269,14 @@ impl Provider {
}
}

#[derive(Debug, Clone, PartialEq, Eq, CandidType, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RpcAccess {
Authenticated {
auth: RpcAuth,
/// Public URL to use when the API key is not available.
#[serde(rename = "publicUrl")]
public_url: Option<&'static str>,
},
Unauthenticated {
#[serde(rename = "publicUrl")]
public_url: &'static str,
},
}
Expand All @@ -303,7 +290,7 @@ impl RpcAccess {
}
}

#[derive(Clone, Debug, PartialEq, Eq, CandidType, Serialize, Deserialize, Default)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum LogFilter {
#[default]
ShowAll,
Expand All @@ -312,25 +299,39 @@ pub enum LogFilter {
HidePattern(RegexString),
}

#[derive(Clone, Debug, PartialEq, Eq, CandidType, Serialize, Deserialize, Default)]
impl From<evm_rpc_types::LogFilter> for LogFilter {
fn from(value: evm_rpc_types::LogFilter) -> Self {
match value {
evm_rpc_types::LogFilter::ShowAll => LogFilter::ShowAll,
evm_rpc_types::LogFilter::HideAll => LogFilter::HideAll,
evm_rpc_types::LogFilter::ShowPattern(regex) => LogFilter::ShowPattern(regex.into()),
evm_rpc_types::LogFilter::HidePattern(regex) => LogFilter::HidePattern(regex.into()),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct RegexString(String);

impl From<evm_rpc_types::RegexString> for RegexString {
fn from(value: evm_rpc_types::RegexString) -> Self {
RegexString(value.0)
}
}

impl From<&str> for RegexString {
fn from(value: &str) -> Self {
RegexString(value.to_string())
}
}

impl RegexString {
pub fn try_is_valid(&self, value: &str) -> Result<bool, regex::Error> {
// Currently only used in the local replica. This can be optimized if eventually used in production.
Ok(Regex::new(&self.0)?.is_match(value))
}
}

impl<T> From<T> for RegexString
where
T: Into<String>,
{
fn from(value: T) -> Self {
RegexString(value.into())
}
}

impl LogFilter {
pub fn is_match(&self, message: &str) -> bool {
match self {
Expand All @@ -347,28 +348,29 @@ impl LogFilter {
}

impl Storable for LogFilter {
fn from_bytes(bytes: Cow<[u8]>) -> Self {
serde_json::from_slice(&bytes).expect("Error while deserializing `MessageFilter`")
}
fn to_bytes(&self) -> Cow<[u8]> {
serde_json::to_vec(self)
.expect("Error while serializing `MessageFilter`")
.expect("Error while serializing `LogFilter`")
.into()
}
fn from_bytes(bytes: Cow<[u8]>) -> Self {
serde_json::from_slice(&bytes).expect("Error while deserializing `LogFilter`")
}

const BOUND: Bound = Bound::Bounded {
max_size: MESSAGE_FILTER_MAX_SIZE,
is_fixed_size: true,
};
}

#[derive(Debug, Clone, PartialEq, Eq, CandidType, Serialize)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RpcAuth {
/// API key will be used in an Authorization header as Bearer token, e.g.,
/// `Authorization: Bearer API_KEY`
BearerToken { url: &'static str },
BearerToken {
url: &'static str,
},
UrlParameter {
#[serde(rename = "urlPattern")]
url_pattern: &'static str,
},
}
Expand Down
Loading