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

feat: Choose a consensus strategy #286

Merged
merged 10 commits into from
Sep 24, 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
1 change: 1 addition & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ ic-config = { git = "https://github.com/dfinity/ic", rev = "release-2023-09-27_2
ic-crypto-test-utils-reproducible-rng = { git = "https://github.com/dfinity/ic", rev = "release-2024-09-12_01-30-base" }
ic-state-machine-tests = { git = "https://github.com/dfinity/ic", rev = "release-2023-09-27_23-01" }
ic-test-utilities-load-wasm = { git = "https://github.com/dfinity/ic", rev = "release-2023-09-27_23-01" }
maplit = "1"
proptest = { workspace = true }
serde_bytes = { workspace = true }
rand = "0.8"
Expand All @@ -80,6 +81,7 @@ proptest = "1.5.0"
serde = "1.0"
serde_json = "1.0"
serde_bytes = "0.11.15"
strum = { version = "0.26", features = ["derive"] }

[workspace]
members = ["e2e/rust", "evm_rpc_types"]
7 changes: 6 additions & 1 deletion candid/evm_rpc.did
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ type ProviderError = variant {
MissingRequiredProvider;
ProviderNotFound;
NoPermission;
InvalidRpcConfig : text ;
};
type ProviderId = nat64;
type ChainId = nat64;
Expand Down Expand Up @@ -178,7 +179,11 @@ type SendRawTransactionResult = variant {
};
type RequestResult = variant { Ok : text; Err : RpcError };
type RequestCostResult = variant { Ok : nat; Err : RpcError };
type RpcConfig = record { responseSizeEstimate : opt nat64 };
type RpcConfig = record { responseSizeEstimate : opt nat64; responseConsensus : opt ConsensusStrategy };
type ConsensusStrategy = variant {
Equality;
Threshold : record { num_providers : opt nat; min_num_ok : nat };
};
type RpcError = variant {
JsonRpcError : JsonRpcError;
ProviderError : ProviderError;
Expand Down
1 change: 1 addition & 0 deletions evm_rpc_types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ hex = { workspace = true }
ic-cdk = { workspace = true }
num-bigint = { workspace = true }
serde = { workspace = true }
strum = { workspace = true }

[dev-dependencies]
proptest = { workspace = true }
4 changes: 2 additions & 2 deletions evm_rpc_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ pub use result::{
ValidationError,
};
pub use rpc_client::{
EthMainnetService, EthSepoliaService, HttpHeader, L2MainnetService, RpcApi, RpcConfig,
RpcService, RpcServices,
ConsensusStrategy, EthMainnetService, EthSepoliaService, HttpHeader, L2MainnetService, RpcApi,
RpcConfig, RpcService, RpcServices,
};

#[derive(Clone, Debug, PartialEq, Eq, CandidType, Deserialize, Default)]
Expand Down
1 change: 1 addition & 0 deletions evm_rpc_types/src/result/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ pub enum ProviderError {
TooFewCycles { expected: u128, received: u128 },
ProviderNotFound,
MissingRequiredProvider,
InvalidRpcConfig(String),
}

#[derive(Clone, Debug, Eq, PartialEq, CandidType, Deserialize)]
Expand Down
87 changes: 83 additions & 4 deletions evm_rpc_types/src/rpc_client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,37 @@
pub use ic_cdk::api::management_canister::http_request::HttpHeader;
use std::fmt::Debug;

use candid::{CandidType, Deserialize};
use serde::Serialize;
use strum::VariantArray;

#[derive(Clone, Debug, PartialEq, Eq, Default, CandidType, Deserialize)]
pub struct RpcConfig {
#[serde(rename = "responseSizeEstimate")]
pub response_size_estimate: Option<u64>,

#[serde(rename = "responseConsensus")]
pub response_consensus: Option<ConsensusStrategy>,
}

#[derive(Clone, Debug, PartialEq, Eq, Default, CandidType, Deserialize)]
pub enum ConsensusStrategy {
/// All providers must return the same non-error result.
#[default]
Equality,
Threshold {
/// Number of providers to be queried:
/// * If `None`, will be set to the number of providers manually specified in `RpcServices`.
/// * If `Some`, must correspond to the number of manually specified providers in `RpcServices`;
/// or if they are none indicating that default providers should be used, select the corresponding number of providers.
num_providers: Option<u8>,

/// Minimum number of providers that must return the same (non-error) result.
min_num_ok: u8,
},
}

#[derive(Clone, CandidType, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, CandidType, Deserialize)]
pub enum RpcServices {
Custom {
#[serde(rename = "chainId")]
Expand All @@ -29,8 +51,25 @@ pub struct RpcApi {
pub headers: Option<Vec<HttpHeader>>,
}

impl Debug for RpcApi {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "RpcApi {{ url: ***, headers: *** }}",) //URL or header value could contain API keys
}
}

#[derive(
Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize, Deserialize, CandidType,
Clone,
Copy,
Debug,
PartialEq,
Eq,
Ord,
PartialOrd,
Hash,
Serialize,
Deserialize,
CandidType,
VariantArray,
)]
pub enum EthMainnetService {
Alchemy,
Expand All @@ -41,8 +80,25 @@ pub enum EthMainnetService {
Llama,
}

impl EthMainnetService {
pub const fn all() -> &'static [Self] {
EthMainnetService::VARIANTS
}
}

#[derive(
Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize, Deserialize, CandidType,
Clone,
Copy,
Debug,
PartialEq,
Eq,
Ord,
PartialOrd,
Hash,
Serialize,
Deserialize,
CandidType,
VariantArray,
)]
pub enum EthSepoliaService {
Alchemy,
Expand All @@ -52,8 +108,25 @@ pub enum EthSepoliaService {
Sepolia,
}

impl EthSepoliaService {
pub const fn all() -> &'static [Self] {
EthSepoliaService::VARIANTS
}
}

#[derive(
Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize, Deserialize, CandidType,
Clone,
Copy,
Debug,
PartialEq,
Eq,
Ord,
PartialOrd,
Hash,
Serialize,
Deserialize,
CandidType,
VariantArray,
)]
pub enum L2MainnetService {
Alchemy,
Expand All @@ -63,6 +136,12 @@ pub enum L2MainnetService {
Llama,
}

impl L2MainnetService {
pub const fn all() -> &'static [Self] {
L2MainnetService::VARIANTS
}
}

#[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize, Deserialize, CandidType)]
pub enum RpcService {
Provider(u64),
Expand Down
54 changes: 54 additions & 0 deletions src/arbitrary.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use evm_rpc_types::{EthMainnetService, EthSepoliaService, L2MainnetService, RpcApi, RpcServices};
use ic_cdk::api::management_canister::http_request::HttpHeader;
use proptest::arbitrary::any;
use proptest::collection::{vec, SizeRange};
use proptest::prelude::{Just, Strategy};
use proptest::{option, prop_oneof};

pub fn arb_rpc_services() -> impl Strategy<Value = RpcServices> {
prop_oneof![
arb_custom_rpc_services(0..=9),
option::of(arb_eth_mainnet_services()).prop_map(RpcServices::EthMainnet),
option::of(arb_eth_sepolia_services()).prop_map(RpcServices::EthSepolia),
option::of(arb_l2_mainnet_services()).prop_map(RpcServices::ArbitrumOne),
option::of(arb_l2_mainnet_services()).prop_map(RpcServices::BaseMainnet),
option::of(arb_l2_mainnet_services()).prop_map(RpcServices::OptimismMainnet),
]
}

pub fn arb_custom_rpc_services(
num_providers: impl Into<SizeRange>,
) -> impl Strategy<Value = RpcServices> {
(any::<u64>(), vec(arb_rpc_api(), num_providers))
.prop_map(|(chain_id, services)| RpcServices::Custom { chain_id, services })
}

fn arb_rpc_api() -> impl Strategy<Value = RpcApi> {
(".+", option::of(vec(arb_http_header(), 0..=10)))
.prop_map(|(url, headers)| RpcApi { url, headers })
}

fn arb_http_header() -> impl Strategy<Value = HttpHeader> {
(".+", ".+").prop_map(|(name, value)| HttpHeader { name, value })
}

fn arb_eth_mainnet_services() -> impl Strategy<Value = Vec<EthMainnetService>> {
let services = EthMainnetService::all().to_owned();
let max_num_services = services.len();
(0..=max_num_services, Just(services).prop_shuffle())
.prop_map(|(num_services, services)| services.into_iter().take(num_services).collect())
}

fn arb_eth_sepolia_services() -> impl Strategy<Value = Vec<EthSepoliaService>> {
let services = EthSepoliaService::all().to_owned();
let max_num_services = services.len();
(0..=max_num_services, Just(services).prop_shuffle())
.prop_map(|(num_services, services)| services.into_iter().take(num_services).collect())
}

fn arb_l2_mainnet_services() -> impl Strategy<Value = Vec<L2MainnetService>> {
let services = L2MainnetService::all().to_owned();
let max_num_services = services.len();
(0..=max_num_services, Just(services).prop_shuffle())
.prop_map(|(num_services, services)| services.into_iter().take(num_services).collect())
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ pub mod rpc_client;
pub mod types;
pub mod util;
pub mod validate;

#[cfg(test)]
mod arbitrary;
Loading