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 change protocol flag calling position #1039

Merged
merged 19 commits into from
Jan 16, 2025
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
196 changes: 109 additions & 87 deletions crates/context/config/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::borrow::Cow;
use std::fmt::Debug;
use std::ops::Deref;

use either::Either;
use env::Method;
use thiserror::Error;

Expand All @@ -13,16 +12,17 @@ pub mod relayer;
pub mod transport;
pub mod utils;

use config::{ClientConfig, ClientSelectedSigner, Credentials, LocalConfig};
use config::{ClientConfig, ClientSelectedSigner, Credentials};
use protocol::{icp, near, starknet, Protocol};
use transport::{Both, Transport, TransportArguments, TransportRequest, UnsupportedProtocol};

pub type LocalTransports = Both<
near::NearTransport<'static>,
Both<starknet::StarknetTransport<'static>, icp::IcpTransport<'static>>,
>;
type MaybeNear = Option<near::NearTransport<'static>>;
type MaybeStarknet = Option<starknet::StarknetTransport<'static>>;
type MaybeIcp = Option<icp::IcpTransport<'static>>;

pub type AnyTransport = Either<relayer::RelayerTransport, LocalTransports>;
pub type LocalTransports = Both<MaybeNear, Both<MaybeStarknet, MaybeIcp>>;

pub type AnyTransport = Both<LocalTransports, relayer::RelayerTransport>;

#[derive(Clone, Debug)]
pub struct Client<T> {
Expand All @@ -38,106 +38,128 @@ impl<T: Transport> Client<T> {
impl Client<AnyTransport> {
#[must_use]
pub fn from_config(config: &ClientConfig) -> Self {
let transport = match config.signer.selected {
ClientSelectedSigner::Relayer => {
Either::Left(relayer::RelayerTransport::new(&relayer::RelayerConfig {
url: config.signer.relayer.url.clone(),
}))
}
ClientSelectedSigner::Local => {
let local_client =
Self::from_local_config(&config.signer.local).expect("validation error");
let relayer = relayer::RelayerTransport::new(&relayer::RelayerConfig {
url: config.signer.relayer.url.clone(),
});

Either::Right(local_client.transport)
}
let local = Self::from_local_config(&config).expect("validation error");

let transport = Both {
left: local.transport,
right: relayer,
};

Self::new(transport)
}

pub fn from_local_config(config: &LocalConfig) -> eyre::Result<Client<LocalTransports>> {
let near_transport = near::NearTransport::new(&near::NearConfig {
networks: config
.near
.iter()
.map(|(network, config)| {
let (account_id, secret_key) = match &config.credentials {
Credentials::Near(credentials) => (
credentials.account_id.clone(),
credentials.secret_key.clone(),
),
Credentials::Starknet(_) | Credentials::Icp(_) => {
eyre::bail!(
"Expected Near credentials but got {:?}",
config.credentials
)
}
pub fn from_local_config(config: &ClientConfig) -> eyre::Result<Client<LocalTransports>> {
let mut near_transport = None;

'skipped: {
if let Some(near_config) = config.signer.local.protocols.get("near") {
let Some(e) = config.params.get("near") else {
eyre::bail!("missing config specification for `{}` signer", "near");
};

if !matches!(e.signer, ClientSelectedSigner::Local) {
break 'skipped;
}

let mut config = near::NearConfig {
networks: Default::default(),
};

for (network, signer) in &near_config.signers {
let Credentials::Near(credentials) = &signer.credentials else {
eyre::bail!("expected Near credentials but got {:?}", signer.credentials)
};
Ok((

let _ignored = config.networks.insert(
network.clone().into(),
near::NetworkConfig {
rpc_url: config.rpc_url.clone(),
account_id,
access_key: secret_key,
rpc_url: signer.rpc_url.clone(),
account_id: credentials.account_id.clone(),
access_key: credentials.secret_key.clone(),
},
))
})
.collect::<eyre::Result<_>>()?,
});
);
}

near_transport = Some(near::NearTransport::new(&config));
}
}

let mut starknet_transport = None;

'skipped: {
if let Some(starknet_config) = config.signer.local.protocols.get("starknet") {
let Some(e) = config.params.get("starknet") else {
eyre::bail!("missing config specification for `{}` signer", "starknet");
};

let starknet_transport = starknet::StarknetTransport::new(&starknet::StarknetConfig {
networks: config
.starknet
.iter()
.map(|(network, config)| {
let (account_id, secret_key) = match &config.credentials {
Credentials::Starknet(credentials) => {
(credentials.account_id, credentials.secret_key)
}
Credentials::Near(_) | Credentials::Icp(_) => {
eyre::bail!(
"Expected Starknet credentials but got {:?}",
config.credentials
)
}
if !matches!(e.signer, ClientSelectedSigner::Local) {
break 'skipped;
}

let mut config = starknet::StarknetConfig {
networks: Default::default(),
};

for (network, signer) in &starknet_config.signers {
let Credentials::Starknet(credentials) = &signer.credentials else {
eyre::bail!(
"expected Starknet credentials but got {:?}",
signer.credentials
)
};
Ok((

let _ignored = config.networks.insert(
network.clone().into(),
starknet::NetworkConfig {
rpc_url: config.rpc_url.clone(),
account_id,
access_key: secret_key,
rpc_url: signer.rpc_url.clone(),
account_id: credentials.account_id.clone(),
access_key: credentials.secret_key.clone(),
},
))
})
.collect::<eyre::Result<_>>()?,
});
);
}

starknet_transport = Some(starknet::StarknetTransport::new(&config));
}
}

let mut icp_transport = None;

let icp_transport = icp::IcpTransport::new(&icp::IcpConfig {
networks: config
.icp
.iter()
.map(|(network, config)| {
let (account_id, secret_key) = match &config.credentials {
Credentials::Icp(credentials) => (
credentials.account_id.clone(),
credentials.secret_key.clone(),
),
Credentials::Near(_) | Credentials::Starknet(_) => {
eyre::bail!("Expected ICP credentials but got {:?}", config.credentials)
}
'skipped: {
if let Some(icp_config) = config.signer.local.protocols.get("icp") {
let Some(e) = config.params.get("icp") else {
eyre::bail!("missing config specification for `{}` signer", "icp");
};

if !matches!(e.signer, ClientSelectedSigner::Local) {
break 'skipped;
}

let mut config = icp::IcpConfig {
networks: Default::default(),
};

for (network, signer) in &icp_config.signers {
let Credentials::Icp(credentials) = &signer.credentials else {
eyre::bail!("expected ICP credentials but got {:?}", signer.credentials)
};
Ok((

let _ignored = config.networks.insert(
network.clone().into(),
icp::NetworkConfig {
rpc_url: config.rpc_url.clone(),
account_id,
secret_key,
rpc_url: signer.rpc_url.clone(),
account_id: credentials.account_id.clone(),
secret_key: credentials.secret_key.clone(),
},
))
})
.collect::<eyre::Result<_>>()?,
});
);
}

icp_transport = Some(icp::IcpTransport::new(&config));
}
}

let all_transports = Both {
left: near_transport,
Expand Down
37 changes: 21 additions & 16 deletions crates/context/config/src/client/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,40 +10,45 @@ use crate::client::protocol::starknet::Credentials as StarknetCredentials;

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ClientConfig {
pub new: ClientNew,
#[serde(flatten)]
pub params: BTreeMap<String, ClientConfigParams>,
pub signer: ClientSigner,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ClientNew {
pub struct ClientConfigParams {
pub signer: ClientSelectedSigner,
pub protocol: String,
pub network: String,
pub contract_id: String,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LocalConfig {
pub near: BTreeMap<String, ClientLocalSigner>,
pub starknet: BTreeMap<String, ClientLocalSigner>,
pub icp: BTreeMap<String, ClientLocalSigner>,
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum ClientSelectedSigner {
Relayer,
#[serde(rename = "self")]
Local,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ClientSigner {
#[serde(rename = "use")]
pub selected: ClientSelectedSigner,
pub relayer: ClientRelayerSigner,
#[serde(rename = "self")]
pub local: LocalConfig,
}

#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum ClientSelectedSigner {
Relayer,
#[serde(rename = "self")]
Local,
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct LocalConfig {
#[serde(flatten)]
pub protocols: BTreeMap<String, ClientLocalConfig>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ClientLocalConfig {
#[serde(flatten)]
pub signers: BTreeMap<String, ClientLocalSigner>,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down
18 changes: 18 additions & 0 deletions crates/context/config/src/client/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,24 @@ where
}
}

impl<T: AssociatedTransport> Transport for Option<T> {
type Error = T::Error;

async fn try_send<'a>(
&self,
args: TransportArguments<'a>,
) -> Result<Result<Vec<u8>, Self::Error>, UnsupportedProtocol<'a>> {
let Some(inner) = self else {
return Err(UnsupportedProtocol {
args,
expected: Cow::Borrowed(&[]),
});
};

inner.try_send(args).await
}
}

pub trait AssociatedTransport: ProtocolTransport {
type Protocol: Protocol;

Expand Down
28 changes: 19 additions & 9 deletions crates/context/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use calimero_blobstore::{Blob, BlobManager, Size};
use calimero_context_config::client::config::ClientConfig;
use calimero_context_config::client::env::config::ContextConfig as ContextConfigEnv;
use calimero_context_config::client::env::proxy::ContextProxy;
use calimero_context_config::client::utils::humanize_iter;
use calimero_context_config::client::{AnyTransport, Client as ExternalClient};
use calimero_context_config::repr::{Repr, ReprBytes, ReprTransmute};
use calimero_context_config::types::{
Expand Down Expand Up @@ -147,12 +148,21 @@ impl ContextManager {

pub fn create_context(
&self,
protocol: &str,
seed: Option<[u8; 32]>,
application_id: ApplicationId,
identity_secret: Option<PrivateKey>,
initialization_params: Vec<u8>,
result_sender: oneshot::Sender<EyreResult<(ContextId, PublicKey)>>,
) -> EyreResult<()> {
let Some(config) = self.client_config.params.get(protocol).cloned() else {
eyre::bail!(
"unsupported protocol: {}, expected one of `{}`",
protocol,
humanize_iter(self.client_config.params.keys())
);
};

let (context_secret, identity_secret) = {
let mut rng = rand::thread_rng();

Expand Down Expand Up @@ -187,9 +197,9 @@ impl ContextManager {
&context,
identity_secret,
Some(ContextConfigParams {
protocol: self.client_config.new.protocol.as_str().into(),
network_id: self.client_config.new.network.as_str().into(),
contract_id: self.client_config.new.contract_id.as_str().into(),
protocol: config.protocol.as_str().into(),
network_id: config.network.as_str().into(),
contract_id: config.contract_id.as_str().into(),
proxy_contract: "".into(),
application_revision: 0,
members_revision: 0,
Expand Down Expand Up @@ -219,9 +229,9 @@ impl ContextManager {

this.config_client
.mutate::<ContextConfigEnv>(
this.client_config.new.protocol.as_str().into(),
this.client_config.new.network.as_str().into(),
this.client_config.new.contract_id.as_str().into(),
config.protocol.as_str().into(),
config.network.as_str().into(),
config.contract_id.as_str().into(),
)
.add_context(
context.id.rt().expect("infallible conversion"),
Expand All @@ -243,9 +253,9 @@ impl ContextManager {
let proxy_contract = this
.config_client
.query::<ContextConfigEnv>(
this.client_config.new.protocol.as_str().into(),
this.client_config.new.network.as_str().into(),
this.client_config.new.contract_id.as_str().into(),
config.protocol.as_str().into(),
config.network.as_str().into(),
config.contract_id.as_str().into(),
)
.get_proxy_contract(context.id.rt().expect("infallible conversion"))
.await?;
Expand Down
Loading
Loading