mirror of
https://github.com/vacp2p/de-mls.git
synced 2026-01-09 15:18:00 -05:00
Interactive CLI for demo (#17)
* delete pks * refactor * update ciphersuite * add draft cli interface * add ui * change to read file * fix problem with threads, add error handler * add graceful shutdown
This commit is contained in:
committed by
GitHub
parent
62f15d2381
commit
4774e574d2
20
Cargo.toml
20
Cargo.toml
@@ -18,8 +18,12 @@ openmls_rust_crypto = "=0.2.0"
|
||||
openmls_traits = "=0.2.0"
|
||||
|
||||
# waku-bindings = "0.6.0"
|
||||
bus = "=2.4.1"
|
||||
tokio = { version = "=1.38.0", features = ["macros", "rt-multi-thread"] }
|
||||
tokio = { version = "=1.38.0", features = [
|
||||
"macros",
|
||||
"rt-multi-thread",
|
||||
"full",
|
||||
] }
|
||||
tokio-util = "=0.7.11"
|
||||
alloy = { git = "https://github.com/alloy-rs/alloy", features = [
|
||||
"providers",
|
||||
"node-bindings",
|
||||
@@ -27,14 +31,24 @@ alloy = { git = "https://github.com/alloy-rs/alloy", features = [
|
||||
"transports",
|
||||
"k256",
|
||||
] }
|
||||
fred = { version = "=9.0.3", features = ["subscriber-client"] }
|
||||
|
||||
rand = "=0.8.5"
|
||||
serde_json = "=1.0"
|
||||
url = "=2.5.2"
|
||||
tls_codec = "=0.3.0"
|
||||
hex = "=0.4.3"
|
||||
|
||||
anyhow = "=1.0.71"
|
||||
shlex = "=1.3.0"
|
||||
clap = { version = "=4.5.8", features = ["derive"] }
|
||||
|
||||
anyhow = "=1.0.81"
|
||||
thiserror = "=1.0.61"
|
||||
|
||||
crossterm = "=0.27.0"
|
||||
ratatui = "=0.27.0"
|
||||
textwrap = "=0.16.1"
|
||||
|
||||
ds = { path = "ds" }
|
||||
sc_key_store = { path = "sc_key_store" }
|
||||
mls_crypto = { path = "mls_crypto" }
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -127,8 +127,8 @@ pub mod DeploymentConfig {
|
||||
b"`\x80`@R4\x80\x15`\x0FW`\0\x80\xFD[P`\x046\x10`FW`\x005`\xE0\x1C\x80c\x12\x90\r\xA8\x14`KW\x80c\xD7\xB6WE\x14`\x8FW\x80c\xF8\xA8\xFDm\x14`\xD2W\x80c\xF8\xCC\xBFG\x14`\xD4W[`\0\x80\xFD[`@\x80Q` \x80\x82\x01\x83R`\0\x90\x91R\x81Q\x80\x82\x01\x83R`\x0ETs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x90\x81\x90R\x91Q\x91\x82R\x01[`@Q\x80\x91\x03\x90\xF3[`\rT`\xAE\x90s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81V[`@Qs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x90\x91\x16\x81R` \x01`\x86V[\0[`\x0CT`\xE0\x90`\xFF\x16\x81V[`@Q\x90\x15\x15\x81R` \x01`\x86V",
|
||||
);
|
||||
/**```solidity
|
||||
struct NetworkConfig { address deployer; }
|
||||
```*/
|
||||
struct NetworkConfig { address deployer; }
|
||||
```*/
|
||||
#[allow(non_camel_case_types, non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct NetworkConfig {
|
||||
@@ -143,9 +143,7 @@ struct NetworkConfig { address deployer; }
|
||||
type UnderlyingRustTuple<'a> = (alloy::sol_types::private::Address,);
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -182,49 +180,37 @@ struct NetworkConfig { address deployer; }
|
||||
}
|
||||
#[inline]
|
||||
fn stv_abi_encoded_size(&self) -> usize {
|
||||
let tuple = <UnderlyingRustTuple<
|
||||
'_,
|
||||
> as ::core::convert::From<Self>>::from(self.clone());
|
||||
<UnderlyingSolTuple<
|
||||
'_,
|
||||
> as alloy_sol_types::SolType>::abi_encoded_size(&tuple)
|
||||
let tuple =
|
||||
<UnderlyingRustTuple<'_> as ::core::convert::From<Self>>::from(self.clone());
|
||||
<UnderlyingSolTuple<'_> as alloy_sol_types::SolType>::abi_encoded_size(&tuple)
|
||||
}
|
||||
#[inline]
|
||||
fn stv_eip712_data_word(&self) -> alloy_sol_types::Word {
|
||||
<Self as alloy_sol_types::SolStruct>::eip712_hash_struct(self)
|
||||
}
|
||||
#[inline]
|
||||
fn stv_abi_encode_packed_to(
|
||||
&self,
|
||||
out: &mut alloy_sol_types::private::Vec<u8>,
|
||||
) {
|
||||
let tuple = <UnderlyingRustTuple<
|
||||
'_,
|
||||
> as ::core::convert::From<Self>>::from(self.clone());
|
||||
<UnderlyingSolTuple<
|
||||
'_,
|
||||
> as alloy_sol_types::SolType>::abi_encode_packed_to(&tuple, out)
|
||||
fn stv_abi_encode_packed_to(&self, out: &mut alloy_sol_types::private::Vec<u8>) {
|
||||
let tuple =
|
||||
<UnderlyingRustTuple<'_> as ::core::convert::From<Self>>::from(self.clone());
|
||||
<UnderlyingSolTuple<'_> as alloy_sol_types::SolType>::abi_encode_packed_to(
|
||||
&tuple, out,
|
||||
)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl alloy_sol_types::SolType for NetworkConfig {
|
||||
type RustType = Self;
|
||||
type Token<'a> = <UnderlyingSolTuple<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Token<'a> = <UnderlyingSolTuple<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
const SOL_NAME: &'static str = <Self as alloy_sol_types::SolStruct>::NAME;
|
||||
const ENCODED_SIZE: Option<usize> = <UnderlyingSolTuple<
|
||||
'_,
|
||||
> as alloy_sol_types::SolType>::ENCODED_SIZE;
|
||||
const ENCODED_SIZE: Option<usize> =
|
||||
<UnderlyingSolTuple<'_> as alloy_sol_types::SolType>::ENCODED_SIZE;
|
||||
#[inline]
|
||||
fn valid_token(token: &Self::Token<'_>) -> bool {
|
||||
<UnderlyingSolTuple<'_> as alloy_sol_types::SolType>::valid_token(token)
|
||||
}
|
||||
#[inline]
|
||||
fn detokenize(token: Self::Token<'_>) -> Self::RustType {
|
||||
let tuple = <UnderlyingSolTuple<
|
||||
'_,
|
||||
> as alloy_sol_types::SolType>::detokenize(token);
|
||||
let tuple = <UnderlyingSolTuple<'_> as alloy_sol_types::SolType>::detokenize(token);
|
||||
<Self as ::core::convert::From<UnderlyingRustTuple<'_>>>::from(tuple)
|
||||
}
|
||||
}
|
||||
@@ -233,14 +219,12 @@ struct NetworkConfig { address deployer; }
|
||||
const NAME: &'static str = "NetworkConfig";
|
||||
#[inline]
|
||||
fn eip712_root_type() -> alloy_sol_types::private::Cow<'static, str> {
|
||||
alloy_sol_types::private::Cow::Borrowed(
|
||||
"NetworkConfig(address deployer)",
|
||||
)
|
||||
alloy_sol_types::private::Cow::Borrowed("NetworkConfig(address deployer)")
|
||||
}
|
||||
#[inline]
|
||||
fn eip712_components() -> alloy_sol_types::private::Vec<
|
||||
alloy_sol_types::private::Cow<'static, str>,
|
||||
> {
|
||||
fn eip712_components(
|
||||
) -> alloy_sol_types::private::Vec<alloy_sol_types::private::Cow<'static, str>>
|
||||
{
|
||||
alloy_sol_types::private::Vec::new()
|
||||
}
|
||||
#[inline]
|
||||
@@ -250,10 +234,10 @@ struct NetworkConfig { address deployer; }
|
||||
#[inline]
|
||||
fn eip712_encode_data(&self) -> alloy_sol_types::private::Vec<u8> {
|
||||
<alloy::sol_types::sol_data::Address as alloy_sol_types::SolType>::eip712_data_word(
|
||||
&self.deployer,
|
||||
)
|
||||
.0
|
||||
.to_vec()
|
||||
&self.deployer,
|
||||
)
|
||||
.0
|
||||
.to_vec()
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
@@ -270,33 +254,24 @@ struct NetworkConfig { address deployer; }
|
||||
rust: &Self::RustType,
|
||||
out: &mut alloy_sol_types::private::Vec<u8>,
|
||||
) {
|
||||
out.reserve(
|
||||
<Self as alloy_sol_types::EventTopic>::topic_preimage_length(rust),
|
||||
);
|
||||
out.reserve(<Self as alloy_sol_types::EventTopic>::topic_preimage_length(rust));
|
||||
<alloy::sol_types::sol_data::Address as alloy_sol_types::EventTopic>::encode_topic_preimage(
|
||||
&rust.deployer,
|
||||
out,
|
||||
);
|
||||
}
|
||||
#[inline]
|
||||
fn encode_topic(
|
||||
rust: &Self::RustType,
|
||||
) -> alloy_sol_types::abi::token::WordToken {
|
||||
fn encode_topic(rust: &Self::RustType) -> alloy_sol_types::abi::token::WordToken {
|
||||
let mut out = alloy_sol_types::private::Vec::new();
|
||||
<Self as alloy_sol_types::EventTopic>::encode_topic_preimage(
|
||||
rust,
|
||||
&mut out,
|
||||
);
|
||||
alloy_sol_types::abi::token::WordToken(
|
||||
alloy_sol_types::private::keccak256(out),
|
||||
)
|
||||
<Self as alloy_sol_types::EventTopic>::encode_topic_preimage(rust, &mut out);
|
||||
alloy_sol_types::abi::token::WordToken(alloy_sol_types::private::keccak256(out))
|
||||
}
|
||||
}
|
||||
};
|
||||
/**Custom error with signature `DeploymentConfig_InvalidDeployerAddress()` and selector `0x80585b44`.
|
||||
```solidity
|
||||
error DeploymentConfig_InvalidDeployerAddress();
|
||||
```*/
|
||||
```solidity
|
||||
error DeploymentConfig_InvalidDeployerAddress();
|
||||
```*/
|
||||
#[allow(non_camel_case_types, non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct DeploymentConfig_InvalidDeployerAddress {}
|
||||
@@ -309,9 +284,7 @@ error DeploymentConfig_InvalidDeployerAddress();
|
||||
type UnderlyingRustTuple<'a> = ();
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -320,16 +293,14 @@ error DeploymentConfig_InvalidDeployerAddress();
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<DeploymentConfig_InvalidDeployerAddress>
|
||||
for UnderlyingRustTuple<'_> {
|
||||
impl ::core::convert::From<DeploymentConfig_InvalidDeployerAddress> for UnderlyingRustTuple<'_> {
|
||||
fn from(value: DeploymentConfig_InvalidDeployerAddress) -> Self {
|
||||
()
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>>
|
||||
for DeploymentConfig_InvalidDeployerAddress {
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>> for DeploymentConfig_InvalidDeployerAddress {
|
||||
fn from(tuple: UnderlyingRustTuple<'_>) -> Self {
|
||||
Self {}
|
||||
}
|
||||
@@ -337,9 +308,7 @@ error DeploymentConfig_InvalidDeployerAddress();
|
||||
#[automatically_derived]
|
||||
impl alloy_sol_types::SolError for DeploymentConfig_InvalidDeployerAddress {
|
||||
type Parameters<'a> = UnderlyingSolTuple<'a>;
|
||||
type Token<'a> = <Self::Parameters<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Token<'a> = <Self::Parameters<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
const SIGNATURE: &'static str = "DeploymentConfig_InvalidDeployerAddress()";
|
||||
const SELECTOR: [u8; 4] = [128u8, 88u8, 91u8, 68u8];
|
||||
#[inline]
|
||||
@@ -355,9 +324,9 @@ error DeploymentConfig_InvalidDeployerAddress();
|
||||
}
|
||||
};
|
||||
/**Custom error with signature `DeploymentConfig_NoConfigForChain(uint256)` and selector `0x0b13dbff`.
|
||||
```solidity
|
||||
error DeploymentConfig_NoConfigForChain(uint256);
|
||||
```*/
|
||||
```solidity
|
||||
error DeploymentConfig_NoConfigForChain(uint256);
|
||||
```*/
|
||||
#[allow(non_camel_case_types, non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct DeploymentConfig_NoConfigForChain {
|
||||
@@ -372,9 +341,7 @@ error DeploymentConfig_NoConfigForChain(uint256);
|
||||
type UnderlyingRustTuple<'a> = (alloy::sol_types::private::U256,);
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -383,16 +350,14 @@ error DeploymentConfig_NoConfigForChain(uint256);
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<DeploymentConfig_NoConfigForChain>
|
||||
for UnderlyingRustTuple<'_> {
|
||||
impl ::core::convert::From<DeploymentConfig_NoConfigForChain> for UnderlyingRustTuple<'_> {
|
||||
fn from(value: DeploymentConfig_NoConfigForChain) -> Self {
|
||||
(value._0,)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>>
|
||||
for DeploymentConfig_NoConfigForChain {
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>> for DeploymentConfig_NoConfigForChain {
|
||||
fn from(tuple: UnderlyingRustTuple<'_>) -> Self {
|
||||
Self { _0: tuple.0 }
|
||||
}
|
||||
@@ -400,9 +365,7 @@ error DeploymentConfig_NoConfigForChain(uint256);
|
||||
#[automatically_derived]
|
||||
impl alloy_sol_types::SolError for DeploymentConfig_NoConfigForChain {
|
||||
type Parameters<'a> = UnderlyingSolTuple<'a>;
|
||||
type Token<'a> = <Self::Parameters<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Token<'a> = <Self::Parameters<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
const SIGNATURE: &'static str = "DeploymentConfig_NoConfigForChain(uint256)";
|
||||
const SELECTOR: [u8; 4] = [11u8, 19u8, 219u8, 255u8];
|
||||
#[inline]
|
||||
@@ -414,17 +377,17 @@ error DeploymentConfig_NoConfigForChain(uint256);
|
||||
#[inline]
|
||||
fn tokenize(&self) -> Self::Token<'_> {
|
||||
(
|
||||
<alloy::sol_types::sol_data::Uint<
|
||||
256,
|
||||
> as alloy_sol_types::SolType>::tokenize(&self._0),
|
||||
<alloy::sol_types::sol_data::Uint<256> as alloy_sol_types::SolType>::tokenize(
|
||||
&self._0,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
/**Constructor`.
|
||||
```solidity
|
||||
constructor(address _broadcaster);
|
||||
```*/
|
||||
```solidity
|
||||
constructor(address _broadcaster);
|
||||
```*/
|
||||
#[allow(non_camel_case_types, non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct constructorCall {
|
||||
@@ -439,9 +402,7 @@ constructor(address _broadcaster);
|
||||
type UnderlyingRustTuple<'a> = (alloy::sol_types::private::Address,);
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -459,16 +420,16 @@ constructor(address _broadcaster);
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>> for constructorCall {
|
||||
fn from(tuple: UnderlyingRustTuple<'_>) -> Self {
|
||||
Self { _broadcaster: tuple.0 }
|
||||
Self {
|
||||
_broadcaster: tuple.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl alloy_sol_types::SolConstructor for constructorCall {
|
||||
type Parameters<'a> = (alloy::sol_types::sol_data::Address,);
|
||||
type Token<'a> = <Self::Parameters<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Token<'a> = <Self::Parameters<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
#[inline]
|
||||
fn new<'a>(
|
||||
tuple: <Self::Parameters<'a> as alloy_sol_types::SolType>::RustType,
|
||||
@@ -486,9 +447,9 @@ constructor(address _broadcaster);
|
||||
}
|
||||
};
|
||||
/**Function with signature `IS_SCRIPT()` and selector `0xf8ccbf47`.
|
||||
```solidity
|
||||
function IS_SCRIPT() external view returns (bool);
|
||||
```*/
|
||||
```solidity
|
||||
function IS_SCRIPT() external view returns (bool);
|
||||
```*/
|
||||
#[allow(non_camel_case_types, non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct IS_SCRIPTCall {}
|
||||
@@ -508,9 +469,7 @@ function IS_SCRIPT() external view returns (bool);
|
||||
type UnderlyingRustTuple<'a> = ();
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -539,9 +498,7 @@ function IS_SCRIPT() external view returns (bool);
|
||||
type UnderlyingRustTuple<'a> = (bool,);
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -566,14 +523,10 @@ function IS_SCRIPT() external view returns (bool);
|
||||
#[automatically_derived]
|
||||
impl alloy_sol_types::SolCall for IS_SCRIPTCall {
|
||||
type Parameters<'a> = ();
|
||||
type Token<'a> = <Self::Parameters<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Token<'a> = <Self::Parameters<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Return = IS_SCRIPTReturn;
|
||||
type ReturnTuple<'a> = (alloy::sol_types::sol_data::Bool,);
|
||||
type ReturnToken<'a> = <Self::ReturnTuple<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type ReturnToken<'a> = <Self::ReturnTuple<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
const SIGNATURE: &'static str = "IS_SCRIPT()";
|
||||
const SELECTOR: [u8; 4] = [248u8, 204u8, 191u8, 71u8];
|
||||
#[inline]
|
||||
@@ -591,17 +544,17 @@ function IS_SCRIPT() external view returns (bool);
|
||||
data: &[u8],
|
||||
validate: bool,
|
||||
) -> alloy_sol_types::Result<Self::Return> {
|
||||
<Self::ReturnTuple<
|
||||
'_,
|
||||
> as alloy_sol_types::SolType>::abi_decode_sequence(data, validate)
|
||||
.map(Into::into)
|
||||
<Self::ReturnTuple<'_> as alloy_sol_types::SolType>::abi_decode_sequence(
|
||||
data, validate,
|
||||
)
|
||||
.map(Into::into)
|
||||
}
|
||||
}
|
||||
};
|
||||
/**Function with signature `activeNetworkConfig()` and selector `0xd7b65745`.
|
||||
```solidity
|
||||
function activeNetworkConfig() external view returns (address deployer);
|
||||
```*/
|
||||
```solidity
|
||||
function activeNetworkConfig() external view returns (address deployer);
|
||||
```*/
|
||||
#[allow(non_camel_case_types, non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct activeNetworkConfigCall {}
|
||||
@@ -621,9 +574,7 @@ function activeNetworkConfig() external view returns (address deployer);
|
||||
type UnderlyingRustTuple<'a> = ();
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -632,16 +583,14 @@ function activeNetworkConfig() external view returns (address deployer);
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<activeNetworkConfigCall>
|
||||
for UnderlyingRustTuple<'_> {
|
||||
impl ::core::convert::From<activeNetworkConfigCall> for UnderlyingRustTuple<'_> {
|
||||
fn from(value: activeNetworkConfigCall) -> Self {
|
||||
()
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>>
|
||||
for activeNetworkConfigCall {
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>> for activeNetworkConfigCall {
|
||||
fn from(tuple: UnderlyingRustTuple<'_>) -> Self {
|
||||
Self {}
|
||||
}
|
||||
@@ -654,9 +603,7 @@ function activeNetworkConfig() external view returns (address deployer);
|
||||
type UnderlyingRustTuple<'a> = (alloy::sol_types::private::Address,);
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -665,16 +612,14 @@ function activeNetworkConfig() external view returns (address deployer);
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<activeNetworkConfigReturn>
|
||||
for UnderlyingRustTuple<'_> {
|
||||
impl ::core::convert::From<activeNetworkConfigReturn> for UnderlyingRustTuple<'_> {
|
||||
fn from(value: activeNetworkConfigReturn) -> Self {
|
||||
(value.deployer,)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>>
|
||||
for activeNetworkConfigReturn {
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>> for activeNetworkConfigReturn {
|
||||
fn from(tuple: UnderlyingRustTuple<'_>) -> Self {
|
||||
Self { deployer: tuple.0 }
|
||||
}
|
||||
@@ -683,14 +628,10 @@ function activeNetworkConfig() external view returns (address deployer);
|
||||
#[automatically_derived]
|
||||
impl alloy_sol_types::SolCall for activeNetworkConfigCall {
|
||||
type Parameters<'a> = ();
|
||||
type Token<'a> = <Self::Parameters<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Token<'a> = <Self::Parameters<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Return = activeNetworkConfigReturn;
|
||||
type ReturnTuple<'a> = (alloy::sol_types::sol_data::Address,);
|
||||
type ReturnToken<'a> = <Self::ReturnTuple<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type ReturnToken<'a> = <Self::ReturnTuple<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
const SIGNATURE: &'static str = "activeNetworkConfig()";
|
||||
const SELECTOR: [u8; 4] = [215u8, 182u8, 87u8, 69u8];
|
||||
#[inline]
|
||||
@@ -708,17 +649,17 @@ function activeNetworkConfig() external view returns (address deployer);
|
||||
data: &[u8],
|
||||
validate: bool,
|
||||
) -> alloy_sol_types::Result<Self::Return> {
|
||||
<Self::ReturnTuple<
|
||||
'_,
|
||||
> as alloy_sol_types::SolType>::abi_decode_sequence(data, validate)
|
||||
.map(Into::into)
|
||||
<Self::ReturnTuple<'_> as alloy_sol_types::SolType>::abi_decode_sequence(
|
||||
data, validate,
|
||||
)
|
||||
.map(Into::into)
|
||||
}
|
||||
}
|
||||
};
|
||||
/**Function with signature `getOrCreateAnvilEthConfig()` and selector `0x12900da8`.
|
||||
```solidity
|
||||
function getOrCreateAnvilEthConfig() external view returns (NetworkConfig memory);
|
||||
```*/
|
||||
```solidity
|
||||
function getOrCreateAnvilEthConfig() external view returns (NetworkConfig memory);
|
||||
```*/
|
||||
#[allow(non_camel_case_types, non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct getOrCreateAnvilEthConfigCall {}
|
||||
@@ -738,9 +679,7 @@ function getOrCreateAnvilEthConfig() external view returns (NetworkConfig memory
|
||||
type UnderlyingRustTuple<'a> = ();
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -749,16 +688,14 @@ function getOrCreateAnvilEthConfig() external view returns (NetworkConfig memory
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<getOrCreateAnvilEthConfigCall>
|
||||
for UnderlyingRustTuple<'_> {
|
||||
impl ::core::convert::From<getOrCreateAnvilEthConfigCall> for UnderlyingRustTuple<'_> {
|
||||
fn from(value: getOrCreateAnvilEthConfigCall) -> Self {
|
||||
()
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>>
|
||||
for getOrCreateAnvilEthConfigCall {
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>> for getOrCreateAnvilEthConfigCall {
|
||||
fn from(tuple: UnderlyingRustTuple<'_>) -> Self {
|
||||
Self {}
|
||||
}
|
||||
@@ -768,14 +705,11 @@ function getOrCreateAnvilEthConfig() external view returns (NetworkConfig memory
|
||||
#[doc(hidden)]
|
||||
type UnderlyingSolTuple<'a> = (NetworkConfig,);
|
||||
#[doc(hidden)]
|
||||
type UnderlyingRustTuple<'a> = (
|
||||
<NetworkConfig as alloy::sol_types::SolType>::RustType,
|
||||
);
|
||||
type UnderlyingRustTuple<'a> =
|
||||
(<NetworkConfig as alloy::sol_types::SolType>::RustType,);
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -784,16 +718,14 @@ function getOrCreateAnvilEthConfig() external view returns (NetworkConfig memory
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<getOrCreateAnvilEthConfigReturn>
|
||||
for UnderlyingRustTuple<'_> {
|
||||
impl ::core::convert::From<getOrCreateAnvilEthConfigReturn> for UnderlyingRustTuple<'_> {
|
||||
fn from(value: getOrCreateAnvilEthConfigReturn) -> Self {
|
||||
(value._0,)
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
#[doc(hidden)]
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>>
|
||||
for getOrCreateAnvilEthConfigReturn {
|
||||
impl ::core::convert::From<UnderlyingRustTuple<'_>> for getOrCreateAnvilEthConfigReturn {
|
||||
fn from(tuple: UnderlyingRustTuple<'_>) -> Self {
|
||||
Self { _0: tuple.0 }
|
||||
}
|
||||
@@ -802,14 +734,10 @@ function getOrCreateAnvilEthConfig() external view returns (NetworkConfig memory
|
||||
#[automatically_derived]
|
||||
impl alloy_sol_types::SolCall for getOrCreateAnvilEthConfigCall {
|
||||
type Parameters<'a> = ();
|
||||
type Token<'a> = <Self::Parameters<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Token<'a> = <Self::Parameters<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Return = getOrCreateAnvilEthConfigReturn;
|
||||
type ReturnTuple<'a> = (NetworkConfig,);
|
||||
type ReturnToken<'a> = <Self::ReturnTuple<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type ReturnToken<'a> = <Self::ReturnTuple<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
const SIGNATURE: &'static str = "getOrCreateAnvilEthConfig()";
|
||||
const SELECTOR: [u8; 4] = [18u8, 144u8, 13u8, 168u8];
|
||||
#[inline]
|
||||
@@ -827,17 +755,17 @@ function getOrCreateAnvilEthConfig() external view returns (NetworkConfig memory
|
||||
data: &[u8],
|
||||
validate: bool,
|
||||
) -> alloy_sol_types::Result<Self::Return> {
|
||||
<Self::ReturnTuple<
|
||||
'_,
|
||||
> as alloy_sol_types::SolType>::abi_decode_sequence(data, validate)
|
||||
.map(Into::into)
|
||||
<Self::ReturnTuple<'_> as alloy_sol_types::SolType>::abi_decode_sequence(
|
||||
data, validate,
|
||||
)
|
||||
.map(Into::into)
|
||||
}
|
||||
}
|
||||
};
|
||||
/**Function with signature `test()` and selector `0xf8a8fd6d`.
|
||||
```solidity
|
||||
function test() external;
|
||||
```*/
|
||||
```solidity
|
||||
function test() external;
|
||||
```*/
|
||||
#[allow(non_camel_case_types, non_snake_case)]
|
||||
#[derive(Clone)]
|
||||
pub struct testCall {}
|
||||
@@ -855,9 +783,7 @@ function test() external;
|
||||
type UnderlyingRustTuple<'a> = ();
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -886,9 +812,7 @@ function test() external;
|
||||
type UnderlyingRustTuple<'a> = ();
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code, unreachable_patterns)]
|
||||
fn _type_assertion(
|
||||
_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>,
|
||||
) {
|
||||
fn _type_assertion(_t: alloy_sol_types::private::AssertTypeEq<UnderlyingRustTuple>) {
|
||||
match _t {
|
||||
alloy_sol_types::private::AssertTypeEq::<
|
||||
<UnderlyingSolTuple as alloy_sol_types::SolType>::RustType,
|
||||
@@ -913,14 +837,10 @@ function test() external;
|
||||
#[automatically_derived]
|
||||
impl alloy_sol_types::SolCall for testCall {
|
||||
type Parameters<'a> = ();
|
||||
type Token<'a> = <Self::Parameters<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Token<'a> = <Self::Parameters<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type Return = testReturn;
|
||||
type ReturnTuple<'a> = ();
|
||||
type ReturnToken<'a> = <Self::ReturnTuple<
|
||||
'a,
|
||||
> as alloy_sol_types::SolType>::Token<'a>;
|
||||
type ReturnToken<'a> = <Self::ReturnTuple<'a> as alloy_sol_types::SolType>::Token<'a>;
|
||||
const SIGNATURE: &'static str = "test()";
|
||||
const SELECTOR: [u8; 4] = [248u8, 168u8, 253u8, 109u8];
|
||||
#[inline]
|
||||
@@ -938,10 +858,10 @@ function test() external;
|
||||
data: &[u8],
|
||||
validate: bool,
|
||||
) -> alloy_sol_types::Result<Self::Return> {
|
||||
<Self::ReturnTuple<
|
||||
'_,
|
||||
> as alloy_sol_types::SolType>::abi_decode_sequence(data, validate)
|
||||
.map(Into::into)
|
||||
<Self::ReturnTuple<'_> as alloy_sol_types::SolType>::abi_decode_sequence(
|
||||
data, validate,
|
||||
)
|
||||
.map(Into::into)
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -975,9 +895,7 @@ function test() external;
|
||||
#[inline]
|
||||
fn selector(&self) -> [u8; 4] {
|
||||
match self {
|
||||
Self::IS_SCRIPT(_) => {
|
||||
<IS_SCRIPTCall as alloy_sol_types::SolCall>::SELECTOR
|
||||
}
|
||||
Self::IS_SCRIPT(_) => <IS_SCRIPTCall as alloy_sol_types::SolCall>::SELECTOR,
|
||||
Self::activeNetworkConfig(_) => {
|
||||
<activeNetworkConfigCall as alloy_sol_types::SolCall>::SELECTOR
|
||||
}
|
||||
@@ -1005,17 +923,17 @@ function test() external;
|
||||
static DECODE_SHIMS: &[fn(
|
||||
&[u8],
|
||||
bool,
|
||||
) -> alloy_sol_types::Result<DeploymentConfigCalls>] = &[
|
||||
)
|
||||
-> alloy_sol_types::Result<DeploymentConfigCalls>] = &[
|
||||
{
|
||||
fn getOrCreateAnvilEthConfig(
|
||||
data: &[u8],
|
||||
validate: bool,
|
||||
) -> alloy_sol_types::Result<DeploymentConfigCalls> {
|
||||
<getOrCreateAnvilEthConfigCall as alloy_sol_types::SolCall>::abi_decode_raw(
|
||||
data,
|
||||
validate,
|
||||
)
|
||||
.map(DeploymentConfigCalls::getOrCreateAnvilEthConfig)
|
||||
data, validate,
|
||||
)
|
||||
.map(DeploymentConfigCalls::getOrCreateAnvilEthConfig)
|
||||
}
|
||||
getOrCreateAnvilEthConfig
|
||||
},
|
||||
@@ -1025,10 +943,9 @@ function test() external;
|
||||
validate: bool,
|
||||
) -> alloy_sol_types::Result<DeploymentConfigCalls> {
|
||||
<activeNetworkConfigCall as alloy_sol_types::SolCall>::abi_decode_raw(
|
||||
data,
|
||||
validate,
|
||||
)
|
||||
.map(DeploymentConfigCalls::activeNetworkConfig)
|
||||
data, validate,
|
||||
)
|
||||
.map(DeploymentConfigCalls::activeNetworkConfig)
|
||||
}
|
||||
activeNetworkConfig
|
||||
},
|
||||
@@ -1037,10 +954,7 @@ function test() external;
|
||||
data: &[u8],
|
||||
validate: bool,
|
||||
) -> alloy_sol_types::Result<DeploymentConfigCalls> {
|
||||
<testCall as alloy_sol_types::SolCall>::abi_decode_raw(
|
||||
data,
|
||||
validate,
|
||||
)
|
||||
<testCall as alloy_sol_types::SolCall>::abi_decode_raw(data, validate)
|
||||
.map(DeploymentConfigCalls::test)
|
||||
}
|
||||
test
|
||||
@@ -1050,22 +964,17 @@ function test() external;
|
||||
data: &[u8],
|
||||
validate: bool,
|
||||
) -> alloy_sol_types::Result<DeploymentConfigCalls> {
|
||||
<IS_SCRIPTCall as alloy_sol_types::SolCall>::abi_decode_raw(
|
||||
data,
|
||||
validate,
|
||||
)
|
||||
<IS_SCRIPTCall as alloy_sol_types::SolCall>::abi_decode_raw(data, validate)
|
||||
.map(DeploymentConfigCalls::IS_SCRIPT)
|
||||
}
|
||||
IS_SCRIPT
|
||||
},
|
||||
];
|
||||
let Ok(idx) = Self::SELECTORS.binary_search(&selector) else {
|
||||
return Err(
|
||||
alloy_sol_types::Error::unknown_selector(
|
||||
<Self as alloy_sol_types::SolInterface>::NAME,
|
||||
selector,
|
||||
),
|
||||
);
|
||||
return Err(alloy_sol_types::Error::unknown_selector(
|
||||
<Self as alloy_sol_types::SolInterface>::NAME,
|
||||
selector,
|
||||
));
|
||||
};
|
||||
(unsafe { DECODE_SHIMS.get_unchecked(idx) })(data, validate)
|
||||
}
|
||||
@@ -1076,9 +985,7 @@ function test() external;
|
||||
<IS_SCRIPTCall as alloy_sol_types::SolCall>::abi_encoded_size(inner)
|
||||
}
|
||||
Self::activeNetworkConfig(inner) => {
|
||||
<activeNetworkConfigCall as alloy_sol_types::SolCall>::abi_encoded_size(
|
||||
inner,
|
||||
)
|
||||
<activeNetworkConfigCall as alloy_sol_types::SolCall>::abi_encoded_size(inner)
|
||||
}
|
||||
Self::getOrCreateAnvilEthConfig(inner) => {
|
||||
<getOrCreateAnvilEthConfigCall as alloy_sol_types::SolCall>::abi_encoded_size(
|
||||
@@ -1094,21 +1001,16 @@ function test() external;
|
||||
fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec<u8>) {
|
||||
match self {
|
||||
Self::IS_SCRIPT(inner) => {
|
||||
<IS_SCRIPTCall as alloy_sol_types::SolCall>::abi_encode_raw(
|
||||
inner,
|
||||
out,
|
||||
)
|
||||
<IS_SCRIPTCall as alloy_sol_types::SolCall>::abi_encode_raw(inner, out)
|
||||
}
|
||||
Self::activeNetworkConfig(inner) => {
|
||||
<activeNetworkConfigCall as alloy_sol_types::SolCall>::abi_encode_raw(
|
||||
inner,
|
||||
out,
|
||||
inner, out,
|
||||
)
|
||||
}
|
||||
Self::getOrCreateAnvilEthConfig(inner) => {
|
||||
<getOrCreateAnvilEthConfigCall as alloy_sol_types::SolCall>::abi_encode_raw(
|
||||
inner,
|
||||
out,
|
||||
inner, out,
|
||||
)
|
||||
}
|
||||
Self::test(inner) => {
|
||||
@@ -1130,10 +1032,8 @@ function test() external;
|
||||
/// No guarantees are made about the order of the selectors.
|
||||
///
|
||||
/// Prefer using `SolInterface` methods instead.
|
||||
pub const SELECTORS: &'static [[u8; 4usize]] = &[
|
||||
[11u8, 19u8, 219u8, 255u8],
|
||||
[128u8, 88u8, 91u8, 68u8],
|
||||
];
|
||||
pub const SELECTORS: &'static [[u8; 4usize]] =
|
||||
&[[11u8, 19u8, 219u8, 255u8], [128u8, 88u8, 91u8, 68u8]];
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl alloy_sol_types::SolInterface for DeploymentConfigErrors {
|
||||
@@ -1169,7 +1069,8 @@ function test() external;
|
||||
static DECODE_SHIMS: &[fn(
|
||||
&[u8],
|
||||
bool,
|
||||
) -> alloy_sol_types::Result<DeploymentConfigErrors>] = &[
|
||||
)
|
||||
-> alloy_sol_types::Result<DeploymentConfigErrors>] = &[
|
||||
{
|
||||
fn DeploymentConfig_NoConfigForChain(
|
||||
data: &[u8],
|
||||
@@ -1202,12 +1103,10 @@ function test() external;
|
||||
},
|
||||
];
|
||||
let Ok(idx) = Self::SELECTORS.binary_search(&selector) else {
|
||||
return Err(
|
||||
alloy_sol_types::Error::unknown_selector(
|
||||
<Self as alloy_sol_types::SolInterface>::NAME,
|
||||
selector,
|
||||
),
|
||||
);
|
||||
return Err(alloy_sol_types::Error::unknown_selector(
|
||||
<Self as alloy_sol_types::SolInterface>::NAME,
|
||||
selector,
|
||||
));
|
||||
};
|
||||
(unsafe { DECODE_SHIMS.get_unchecked(idx) })(data, validate)
|
||||
}
|
||||
@@ -1247,7 +1146,7 @@ function test() external;
|
||||
use alloy::contract as alloy_contract;
|
||||
/**Creates a new wrapper around an on-chain [`DeploymentConfig`](self) contract instance.
|
||||
|
||||
See the [wrapper's documentation](`DeploymentConfigInstance`) for more details.*/
|
||||
See the [wrapper's documentation](`DeploymentConfigInstance`) for more details.*/
|
||||
#[inline]
|
||||
pub const fn new<
|
||||
T: alloy_contract::private::Transport + ::core::clone::Clone,
|
||||
@@ -1261,9 +1160,9 @@ See the [wrapper's documentation](`DeploymentConfigInstance`) for more details.*
|
||||
}
|
||||
/**Deploys this contract using the given `provider` and constructor arguments, if any.
|
||||
|
||||
Returns a new instance of the contract, if the deployment was successful.
|
||||
Returns a new instance of the contract, if the deployment was successful.
|
||||
|
||||
For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/
|
||||
For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/
|
||||
#[inline]
|
||||
pub fn deploy<
|
||||
T: alloy_contract::private::Transport + ::core::clone::Clone,
|
||||
@@ -1272,16 +1171,15 @@ For more fine-grained control over the deployment process, use [`deploy_builder`
|
||||
>(
|
||||
provider: P,
|
||||
_broadcaster: alloy::sol_types::private::Address,
|
||||
) -> impl ::core::future::Future<
|
||||
Output = alloy_contract::Result<DeploymentConfigInstance<T, P, N>>,
|
||||
> {
|
||||
) -> impl ::core::future::Future<Output = alloy_contract::Result<DeploymentConfigInstance<T, P, N>>>
|
||||
{
|
||||
DeploymentConfigInstance::<T, P, N>::deploy(provider, _broadcaster)
|
||||
}
|
||||
/**Creates a `RawCallBuilder` for deploying this contract using the given `provider`
|
||||
and constructor arguments, if any.
|
||||
and constructor arguments, if any.
|
||||
|
||||
This is a simple wrapper around creating a `RawCallBuilder` with the data set to
|
||||
the bytecode concatenated with the constructor's ABI-encoded arguments.*/
|
||||
This is a simple wrapper around creating a `RawCallBuilder` with the data set to
|
||||
the bytecode concatenated with the constructor's ABI-encoded arguments.*/
|
||||
#[inline]
|
||||
pub fn deploy_builder<
|
||||
T: alloy_contract::private::Transport + ::core::clone::Clone,
|
||||
@@ -1295,15 +1193,15 @@ the bytecode concatenated with the constructor's ABI-encoded arguments.*/
|
||||
}
|
||||
/**A [`DeploymentConfig`](self) instance.
|
||||
|
||||
Contains type-safe methods for interacting with an on-chain instance of the
|
||||
[`DeploymentConfig`](self) contract located at a given `address`, using a given
|
||||
provider `P`.
|
||||
Contains type-safe methods for interacting with an on-chain instance of the
|
||||
[`DeploymentConfig`](self) contract located at a given `address`, using a given
|
||||
provider `P`.
|
||||
|
||||
If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!)
|
||||
documentation on how to provide it), the `deploy` and `deploy_builder` methods can
|
||||
be used to deploy a new instance of the contract.
|
||||
If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!)
|
||||
documentation on how to provide it), the `deploy` and `deploy_builder` methods can
|
||||
be used to deploy a new instance of the contract.
|
||||
|
||||
See the [module-level documentation](self) for all the available methods.*/
|
||||
See the [module-level documentation](self) for all the available methods.*/
|
||||
#[derive(Clone)]
|
||||
pub struct DeploymentConfigInstance<T, P, N = alloy_contract::private::Ethereum> {
|
||||
address: alloy_sol_types::private::Address,
|
||||
@@ -1314,24 +1212,24 @@ See the [module-level documentation](self) for all the available methods.*/
|
||||
impl<T, P, N> ::core::fmt::Debug for DeploymentConfigInstance<T, P, N> {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
f.debug_tuple("DeploymentConfigInstance").field(&self.address).finish()
|
||||
f.debug_tuple("DeploymentConfigInstance")
|
||||
.field(&self.address)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
/// Instantiation and getters/setters.
|
||||
#[automatically_derived]
|
||||
impl<
|
||||
T: alloy_contract::private::Transport + ::core::clone::Clone,
|
||||
P: alloy_contract::private::Provider<T, N>,
|
||||
N: alloy_contract::private::Network,
|
||||
> DeploymentConfigInstance<T, P, N> {
|
||||
T: alloy_contract::private::Transport + ::core::clone::Clone,
|
||||
P: alloy_contract::private::Provider<T, N>,
|
||||
N: alloy_contract::private::Network,
|
||||
> DeploymentConfigInstance<T, P, N>
|
||||
{
|
||||
/**Creates a new wrapper around an on-chain [`DeploymentConfig`](self) contract instance.
|
||||
|
||||
See the [wrapper's documentation](`DeploymentConfigInstance`) for more details.*/
|
||||
See the [wrapper's documentation](`DeploymentConfigInstance`) for more details.*/
|
||||
#[inline]
|
||||
pub const fn new(
|
||||
address: alloy_sol_types::private::Address,
|
||||
provider: P,
|
||||
) -> Self {
|
||||
pub const fn new(address: alloy_sol_types::private::Address, provider: P) -> Self {
|
||||
Self {
|
||||
address,
|
||||
provider,
|
||||
@@ -1340,9 +1238,9 @@ See the [wrapper's documentation](`DeploymentConfigInstance`) for more details.*
|
||||
}
|
||||
/**Deploys this contract using the given `provider` and constructor arguments, if any.
|
||||
|
||||
Returns a new instance of the contract, if the deployment was successful.
|
||||
Returns a new instance of the contract, if the deployment was successful.
|
||||
|
||||
For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/
|
||||
For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/
|
||||
#[inline]
|
||||
pub async fn deploy(
|
||||
provider: P,
|
||||
@@ -1353,10 +1251,10 @@ For more fine-grained control over the deployment process, use [`deploy_builder`
|
||||
Ok(Self::new(contract_address, call_builder.provider))
|
||||
}
|
||||
/**Creates a `RawCallBuilder` for deploying this contract using the given `provider`
|
||||
and constructor arguments, if any.
|
||||
and constructor arguments, if any.
|
||||
|
||||
This is a simple wrapper around creating a `RawCallBuilder` with the data set to
|
||||
the bytecode concatenated with the constructor's ABI-encoded arguments.*/
|
||||
This is a simple wrapper around creating a `RawCallBuilder` with the data set to
|
||||
the bytecode concatenated with the constructor's ABI-encoded arguments.*/
|
||||
#[inline]
|
||||
pub fn deploy_builder(
|
||||
provider: P,
|
||||
@@ -1366,12 +1264,11 @@ the bytecode concatenated with the constructor's ABI-encoded arguments.*/
|
||||
provider,
|
||||
[
|
||||
&BYTECODE[..],
|
||||
&alloy_sol_types::SolConstructor::abi_encode(
|
||||
&constructorCall { _broadcaster },
|
||||
)[..],
|
||||
&alloy_sol_types::SolConstructor::abi_encode(&constructorCall { _broadcaster })
|
||||
[..],
|
||||
]
|
||||
.concat()
|
||||
.into(),
|
||||
.concat()
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
/// Returns a reference to the address.
|
||||
@@ -1409,10 +1306,11 @@ the bytecode concatenated with the constructor's ABI-encoded arguments.*/
|
||||
/// Function calls.
|
||||
#[automatically_derived]
|
||||
impl<
|
||||
T: alloy_contract::private::Transport + ::core::clone::Clone,
|
||||
P: alloy_contract::private::Provider<T, N>,
|
||||
N: alloy_contract::private::Network,
|
||||
> DeploymentConfigInstance<T, P, N> {
|
||||
T: alloy_contract::private::Transport + ::core::clone::Clone,
|
||||
P: alloy_contract::private::Provider<T, N>,
|
||||
N: alloy_contract::private::Network,
|
||||
> DeploymentConfigInstance<T, P, N>
|
||||
{
|
||||
/// Creates a new call builder using this contract instance's provider and address.
|
||||
///
|
||||
/// Note that the call can be any function call, not just those defined in this
|
||||
@@ -1424,9 +1322,7 @@ the bytecode concatenated with the constructor's ABI-encoded arguments.*/
|
||||
alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call)
|
||||
}
|
||||
///Creates a new call builder for the [`IS_SCRIPT`] function.
|
||||
pub fn IS_SCRIPT(
|
||||
&self,
|
||||
) -> alloy_contract::SolCallBuilder<T, &P, IS_SCRIPTCall, N> {
|
||||
pub fn IS_SCRIPT(&self) -> alloy_contract::SolCallBuilder<T, &P, IS_SCRIPTCall, N> {
|
||||
self.call_builder(&IS_SCRIPTCall {})
|
||||
}
|
||||
///Creates a new call builder for the [`activeNetworkConfig`] function.
|
||||
@@ -1449,10 +1345,11 @@ the bytecode concatenated with the constructor's ABI-encoded arguments.*/
|
||||
/// Event filters.
|
||||
#[automatically_derived]
|
||||
impl<
|
||||
T: alloy_contract::private::Transport + ::core::clone::Clone,
|
||||
P: alloy_contract::private::Provider<T, N>,
|
||||
N: alloy_contract::private::Network,
|
||||
> DeploymentConfigInstance<T, P, N> {
|
||||
T: alloy_contract::private::Transport + ::core::clone::Clone,
|
||||
P: alloy_contract::private::Provider<T, N>,
|
||||
N: alloy_contract::private::Network,
|
||||
> DeploymentConfigInstance<T, P, N>
|
||||
{
|
||||
/// Creates a new event filter using this contract instance's provider and address.
|
||||
///
|
||||
/// Note that the type can be any event, not just those defined in this contract.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -15,9 +15,11 @@ tokio = "=1.38.0"
|
||||
openmls = { version = "=0.5.0", features = ["test-utils"] }
|
||||
rand = { version = "^0.8" }
|
||||
|
||||
anyhow = "=1.0.71"
|
||||
anyhow = "=1.0.81"
|
||||
thiserror = "=1.0.61"
|
||||
|
||||
tls_codec = "=0.3.0"
|
||||
serde_json = "=1.0"
|
||||
serde = "=1.0.204"
|
||||
|
||||
sc_key_store = { path = "../sc_key_store" }
|
||||
|
||||
57
ds/src/ds.rs
57
ds/src/ds.rs
@@ -4,36 +4,44 @@ use fred::{
|
||||
prelude::*,
|
||||
types::Message,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::broadcast::{error::RecvError, Receiver};
|
||||
|
||||
use openmls::{
|
||||
framing::{MlsMessageIn, MlsMessageOut},
|
||||
prelude::{TlsDeserializeTrait, TlsSerializeTrait},
|
||||
};
|
||||
use openmls::{framing::MlsMessageOut, prelude::TlsSerializeTrait};
|
||||
// use waku_bindings::*;
|
||||
|
||||
pub struct RClient {
|
||||
group_id: String,
|
||||
client: RedisClient,
|
||||
sub_client: SubscriberClient,
|
||||
broadcaster: Receiver<Message>,
|
||||
// broadcaster: Receiver<Message>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct SenderStruct {
|
||||
pub sender: String,
|
||||
pub msg: Vec<u8>,
|
||||
}
|
||||
|
||||
impl RClient {
|
||||
pub async fn new_for_group(group_id: String) -> Result<Self, DeliveryServiceError> {
|
||||
pub async fn new_for_group(
|
||||
group_id: String,
|
||||
) -> Result<(Self, Receiver<Message>), DeliveryServiceError> {
|
||||
let redis_client = RedisClient::default();
|
||||
let subscriber: SubscriberClient =
|
||||
Builder::default_centralized().build_subscriber_client()?;
|
||||
redis_client.init().await?;
|
||||
subscriber.init().await?;
|
||||
subscriber.subscribe(group_id.clone()).await?;
|
||||
Ok(RClient {
|
||||
group_id,
|
||||
client: redis_client,
|
||||
sub_client: subscriber.clone(),
|
||||
broadcaster: subscriber.message_rx(),
|
||||
})
|
||||
Ok((
|
||||
RClient {
|
||||
group_id,
|
||||
client: redis_client,
|
||||
sub_client: subscriber.clone(),
|
||||
// broadcaster: subscriber.message_rx(),
|
||||
},
|
||||
subscriber.message_rx(),
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn remove_from_group(&mut self) -> Result<(), DeliveryServiceError> {
|
||||
@@ -43,30 +51,31 @@ impl RClient {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn msg_send(&mut self, msg: MlsMessageOut) -> Result<(), DeliveryServiceError> {
|
||||
pub async fn msg_send(
|
||||
&mut self,
|
||||
msg: MlsMessageOut,
|
||||
sender: String,
|
||||
) -> Result<(), DeliveryServiceError> {
|
||||
let buf = msg.tls_serialize_detached()?;
|
||||
|
||||
let json_value = SenderStruct { sender, msg: buf };
|
||||
let bytes = serde_json::to_vec(&json_value)?;
|
||||
self.client
|
||||
.publish(self.group_id.clone(), buf.as_slice())
|
||||
.publish(self.group_id.clone(), bytes.as_slice())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn msg_recv(&mut self) -> Result<MlsMessageIn, DeliveryServiceError> {
|
||||
// check only one message
|
||||
let msg = self.broadcaster.recv().await?;
|
||||
let bytes: Vec<u8> = msg.value.convert()?;
|
||||
let res = MlsMessageIn::tls_deserialize_bytes(bytes)?;
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum DeliveryServiceError {
|
||||
#[error("Json error: {0}")]
|
||||
JsonError(#[from] serde_json::Error),
|
||||
#[error("Redis error: {0}")]
|
||||
RedisError(#[from] RedisError),
|
||||
#[error("Tokio error: {0}")]
|
||||
TokioRecieveError(#[from] RecvError),
|
||||
TokioReceiveError(#[from] RecvError),
|
||||
#[error("Serialization problem: {0}")]
|
||||
TlsError(#[from] tls_codec::Error),
|
||||
#[error("Unknown error: {0}")]
|
||||
|
||||
@@ -9,11 +9,12 @@ edition = "2021"
|
||||
foundry-contracts.workspace = true
|
||||
openmls = { version = "=0.5.0", features = ["test-utils"] }
|
||||
openmls_basic_credential = "=0.2.0"
|
||||
tls_codec = "=0.3.0"
|
||||
|
||||
thiserror = "=1.0.61"
|
||||
anyhow = "=1.0.71"
|
||||
anyhow = "=1.0.81"
|
||||
|
||||
tls_codec = "=0.3.0"
|
||||
hex = "0.4.3"
|
||||
url = "2.5.2"
|
||||
|
||||
eyre = "=0.6"
|
||||
@@ -27,8 +28,5 @@ alloy = { git = "https://github.com/alloy-rs/alloy", features = [
|
||||
"transport-http",
|
||||
"k256",
|
||||
] }
|
||||
async-trait = "0.1.80"
|
||||
p256 = "0.13.2"
|
||||
|
||||
mls_crypto = { path = "../mls_crypto" }
|
||||
hex = "0.4.3"
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
use openmls::prelude::KeyPackage;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use mls_crypto::openmls_provider::MlsCryptoProvider;
|
||||
|
||||
use crate::{KeyStoreError, SCKeyStoreService, UserInfo, UserKeyPackages};
|
||||
|
||||
/// Public Key Storage
|
||||
/// This is a tuple struct holding a vector of `(Vec<u8>, UserInfo)` tuples,
|
||||
/// where the first value is the Ethereum wallet address of a user
|
||||
/// and the second value is the corresponding user information.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PublicKeyStorage {
|
||||
storage: HashMap<Vec<u8>, UserInfo>,
|
||||
}
|
||||
|
||||
impl From<UserKeyPackages> for UserInfo {
|
||||
fn from(mut key_packages: UserKeyPackages) -> Self {
|
||||
let key_package: KeyPackage = key_packages.0[0].1.clone();
|
||||
let id = key_package.leaf_node().credential().identity();
|
||||
let drain = key_packages.0.drain(..);
|
||||
Self {
|
||||
id: id.into(),
|
||||
key_packages: UserKeyPackages(drain.collect::<Vec<(Vec<u8>, KeyPackage)>>()),
|
||||
sign_pk: vec![0; 32],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SCKeyStoreService for &mut PublicKeyStorage {
|
||||
async fn does_user_exist(&self, id: &[u8]) -> Result<bool, KeyStoreError> {
|
||||
Ok(self.storage.contains_key(id))
|
||||
}
|
||||
|
||||
async fn add_user(
|
||||
&mut self,
|
||||
ukp: UserKeyPackages,
|
||||
sign_pk: &[u8],
|
||||
) -> Result<(), KeyStoreError> {
|
||||
if ukp.0.is_empty() {
|
||||
return Err(KeyStoreError::InvalidUserDataError(
|
||||
"no key packages".to_string(),
|
||||
));
|
||||
}
|
||||
let mut new_user_info: UserInfo = ukp.into();
|
||||
new_user_info.sign_pk.clone_from_slice(sign_pk);
|
||||
|
||||
if self.storage.contains_key(&new_user_info.id) {
|
||||
return Err(KeyStoreError::InvalidUserDataError(
|
||||
"already register".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let res = self.storage.insert(new_user_info.id.clone(), new_user_info);
|
||||
assert!(res.is_none());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn add_user_kp(&mut self, id: &[u8], ukp: UserKeyPackages) -> Result<(), KeyStoreError> {
|
||||
let user = match self.storage.get_mut(id) {
|
||||
Some(u) => u,
|
||||
None => return Err(KeyStoreError::UnknownUserError),
|
||||
};
|
||||
ukp.0
|
||||
.into_iter()
|
||||
.for_each(|value| user.key_packages.0.push(value));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_user(
|
||||
&self,
|
||||
id: &[u8],
|
||||
_crypto: &MlsCryptoProvider,
|
||||
) -> Result<UserInfo, KeyStoreError> {
|
||||
match self.storage.get(id) {
|
||||
Some(u) => Ok(u.to_owned()),
|
||||
None => Err(KeyStoreError::UnknownUserError),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_avaliable_user_kp(
|
||||
&mut self,
|
||||
id: &[u8],
|
||||
_crypto: &MlsCryptoProvider,
|
||||
) -> Result<KeyPackage, KeyStoreError> {
|
||||
let user = match self.storage.get_mut(id) {
|
||||
Some(u) => u,
|
||||
None => return Err(KeyStoreError::UnknownUserError),
|
||||
};
|
||||
match user.key_packages.0.pop() {
|
||||
Some(c) => Ok(c.1),
|
||||
None => Err(KeyStoreError::InvalidUserDataError(
|
||||
"No more keypackage available".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,7 +191,7 @@ mod test {
|
||||
use openmls::prelude::*;
|
||||
use openmls_basic_credential::SignatureKeyPair;
|
||||
|
||||
use mls_crypto::openmls_provider::MlsCryptoProvider;
|
||||
use mls_crypto::openmls_provider::{MlsCryptoProvider, CIPHERSUITE};
|
||||
|
||||
use crate::{sc_ks::*, UserKeyPackages};
|
||||
|
||||
@@ -199,7 +199,7 @@ mod test {
|
||||
address: Address,
|
||||
crypto: &MlsCryptoProvider,
|
||||
) -> (UserKeyPackages, SignatureKeyPair) {
|
||||
let ciphersuite = Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256;
|
||||
let ciphersuite = CIPHERSUITE;
|
||||
let signature_keys = SignatureKeyPair::new(ciphersuite.signature_algorithm()).unwrap();
|
||||
let credential = Credential::new(address.to_vec(), CredentialType::Basic).unwrap();
|
||||
|
||||
|
||||
297
src/cli.rs
Normal file
297
src/cli.rs
Normal file
@@ -0,0 +1,297 @@
|
||||
use alloy::{
|
||||
hex::FromHexError,
|
||||
network::EthereumWallet,
|
||||
primitives::Address,
|
||||
signers::local::{LocalSignerError, PrivateKeySigner},
|
||||
};
|
||||
use clap::{arg, command, Parser, Subcommand};
|
||||
use crossterm::{
|
||||
event::{self, Event, KeyCode},
|
||||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
|
||||
use fred::error::RedisError;
|
||||
use ratatui::{
|
||||
backend::CrosstermBackend,
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style},
|
||||
text::Text,
|
||||
widgets::{Block, Borders, List, ListItem, Paragraph, Wrap},
|
||||
Frame, Terminal,
|
||||
};
|
||||
use std::{
|
||||
io,
|
||||
io::{Read, Write},
|
||||
str::FromStr,
|
||||
string::FromUtf8Error,
|
||||
sync::Arc,
|
||||
};
|
||||
use tokio::{
|
||||
sync::mpsc::error::SendError,
|
||||
sync::mpsc::{Receiver, Sender},
|
||||
sync::Mutex,
|
||||
task::JoinError,
|
||||
};
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use url::Url;
|
||||
|
||||
use crate::user::UserError;
|
||||
use ds::ds::DeliveryServiceError;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
pub struct Args {
|
||||
/// User private key that correspond to Ethereum wallet
|
||||
#[arg(short = 'K', long)]
|
||||
user_priv_key: String,
|
||||
|
||||
/// Rpc url
|
||||
#[arg(short = 'U', long,
|
||||
default_value_t = Url::from_str("http://localhost:8545").unwrap())]
|
||||
pub storage_url: Url,
|
||||
|
||||
/// Storage contract address
|
||||
#[arg(short = 'S', long)]
|
||||
pub storage_addr: String,
|
||||
}
|
||||
|
||||
pub enum Msg {
|
||||
Input(Message),
|
||||
Refresh(String),
|
||||
Exit,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Message {
|
||||
Incoming(String, String, String),
|
||||
Mine(String, String, String),
|
||||
System(String),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
pub fn get_user_data(args: &Args) -> Result<(Address, EthereumWallet, Address), CliError> {
|
||||
let signer = PrivateKeySigner::from_str(&args.user_priv_key)?;
|
||||
let user_address = signer.address();
|
||||
let wallet = EthereumWallet::from(signer);
|
||||
let storage_address = Address::from_str(&args.storage_addr)?;
|
||||
Ok((user_address, wallet, storage_address))
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(multicall = true)]
|
||||
pub struct Cli {
|
||||
#[command(subcommand)]
|
||||
pub command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand, Clone)]
|
||||
pub enum Commands {
|
||||
CreateGroup {
|
||||
group_name: String,
|
||||
},
|
||||
Invite {
|
||||
group_name: String,
|
||||
user_wallet: String,
|
||||
},
|
||||
JoinGroup {
|
||||
group_name: String,
|
||||
},
|
||||
SendMessage {
|
||||
group_name: String,
|
||||
msg: Vec<String>,
|
||||
},
|
||||
// RemoveUser { user_wallet: String },
|
||||
Exit,
|
||||
}
|
||||
|
||||
pub fn readline() -> Result<String, CliError> {
|
||||
write!(std::io::stdout(), "$ ")?;
|
||||
std::io::stdout().flush()?;
|
||||
let mut buffer = String::new();
|
||||
std::io::stdin().read_to_string(&mut buffer)?;
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
pub async fn event_handler(
|
||||
messages_tx: Sender<Msg>,
|
||||
cli_tx: Sender<Commands>,
|
||||
token: CancellationToken,
|
||||
) -> Result<(), CliError> {
|
||||
let mut input = String::new();
|
||||
loop {
|
||||
if let Event::Key(key) = tokio::task::spawn_blocking(event::read).await?? {
|
||||
match key.code {
|
||||
KeyCode::Char(c) => {
|
||||
input.push(c);
|
||||
}
|
||||
KeyCode::Backspace => {
|
||||
input.pop();
|
||||
}
|
||||
KeyCode::Enter => {
|
||||
let line: String = std::mem::take(&mut input);
|
||||
let args = shlex::split(&line).ok_or(CliError::SplitLineError)?;
|
||||
let cli = Cli::try_parse_from(args);
|
||||
if cli.is_err() {
|
||||
messages_tx
|
||||
.send(Msg::Input(Message::System("Unknown command".to_string())))
|
||||
.await?;
|
||||
continue;
|
||||
}
|
||||
cli_tx.send(cli.unwrap().command).await?;
|
||||
}
|
||||
KeyCode::Esc => {
|
||||
messages_tx.send(Msg::Exit).await?;
|
||||
token.cancel();
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
messages_tx.send(Msg::Refresh(input.clone())).await?;
|
||||
}
|
||||
}
|
||||
Ok::<_, CliError>(())
|
||||
}
|
||||
|
||||
pub fn ui(f: &mut Frame, messages: &[Message], input: &str) {
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.constraints([Constraint::Min(1), Constraint::Length(3)].as_ref())
|
||||
.split(f.size());
|
||||
|
||||
let message_items: Vec<ListItem> = messages
|
||||
.iter()
|
||||
.map(|message| {
|
||||
let (content, style) = match message {
|
||||
Message::Incoming(group, from, msg) => (
|
||||
format!("[0x{}]@{}: {}", from, group, msg),
|
||||
Style::default().fg(Color::LightGreen),
|
||||
),
|
||||
Message::Mine(group, from, msg) => (
|
||||
format!("[0x{}]@{}: {}", from, group, msg),
|
||||
Style::default()
|
||||
.fg(Color::LightGreen)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Message::System(msg) => (format!("[System]: {}", msg), Style::default()),
|
||||
Message::Error(msg) => (msg.clone(), Style::default().fg(Color::LightRed)),
|
||||
};
|
||||
ListItem::new(content).style(style)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let messages_history = List::new(message_items).block(
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title("messages history"),
|
||||
);
|
||||
|
||||
let input_line = Paragraph::new(Text::raw(input))
|
||||
.style(
|
||||
Style::default()
|
||||
.fg(Color::Yellow)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
)
|
||||
.block(Block::default().borders(Borders::ALL).title("input line"))
|
||||
.wrap(Wrap { trim: false });
|
||||
|
||||
f.render_widget(messages_history, chunks[0]);
|
||||
f.render_widget(input_line, chunks[1]);
|
||||
}
|
||||
|
||||
pub async fn terminal_handler(
|
||||
mut messages_rx: Receiver<Msg>,
|
||||
token: CancellationToken,
|
||||
) -> Result<(), CliError> {
|
||||
enable_raw_mode()?;
|
||||
let mut stdout = io::stdout();
|
||||
execute!(stdout, EnterAlternateScreen)?;
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let terminal = Arc::new(Mutex::new(Terminal::new(backend)?));
|
||||
|
||||
let messages = Arc::new(Mutex::new(vec![]));
|
||||
let input = Arc::new(Mutex::new(String::new()));
|
||||
|
||||
let messages_clone = Arc::clone(&messages);
|
||||
let input_clone = Arc::clone(&input);
|
||||
while let Some(msg) = messages_rx.recv().await {
|
||||
match msg {
|
||||
Msg::Input(m) => {
|
||||
let mut messages = messages_clone.lock().await;
|
||||
messages.push(m);
|
||||
if messages.len() == 100 {
|
||||
messages.remove(0);
|
||||
}
|
||||
}
|
||||
Msg::Refresh(i) => {
|
||||
let mut input = input_clone.lock().await;
|
||||
*input = i;
|
||||
}
|
||||
Msg::Exit => {
|
||||
token.cancel();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
let messages = Arc::clone(&messages_clone);
|
||||
let input = Arc::clone(&input_clone);
|
||||
let terminal = Arc::clone(&terminal);
|
||||
tokio::task::spawn_blocking(move || {
|
||||
let messages = messages.blocking_lock();
|
||||
let input = input.blocking_lock();
|
||||
terminal
|
||||
.blocking_lock()
|
||||
.draw(|f| ui(f, &messages, &input))
|
||||
.unwrap();
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
|
||||
// Restore terminal
|
||||
disable_raw_mode()?;
|
||||
let mut terminal_lock = terminal.lock().await;
|
||||
execute!(terminal_lock.backend_mut(), LeaveAlternateScreen)?;
|
||||
terminal_lock.show_cursor()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum CliError {
|
||||
#[error("Can't split the line")]
|
||||
SplitLineError,
|
||||
#[error("Unknown message type")]
|
||||
UnknownMsgError,
|
||||
|
||||
#[error(transparent)]
|
||||
UserError(#[from] UserError),
|
||||
#[error(transparent)]
|
||||
DeliveryServiceError(#[from] DeliveryServiceError),
|
||||
|
||||
#[error("Unable to parce the address: {0}")]
|
||||
AlloyFromHexError(#[from] FromHexError),
|
||||
#[error("Unable to parce the signer: {0}")]
|
||||
AlloyParceSignerError(#[from] LocalSignerError),
|
||||
#[error("Problem from std::io library: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
#[error("Parse String UTF8 error: {0}")]
|
||||
ParseUTF8Error(#[from] FromUtf8Error),
|
||||
#[error("Parse String error: {0}")]
|
||||
StringError(#[from] core::convert::Infallible),
|
||||
|
||||
#[error("Can't send control message into channel: {0}")]
|
||||
SendMsgError(#[from] SendError<Msg>),
|
||||
#[error("Can't send bytes into channel: {0}")]
|
||||
SendVecError(#[from] SendError<Vec<u8>>),
|
||||
#[error("Can't send command into channel: {0}")]
|
||||
SendCommandError(#[from] SendError<Commands>),
|
||||
|
||||
#[error(transparent)]
|
||||
ClapError(#[from] clap::error::Error),
|
||||
#[error("Redis error: {0}")]
|
||||
RedisError(#[from] RedisError),
|
||||
#[error("Failed from tokio join: {0}")]
|
||||
TokioJoinError(#[from] JoinError),
|
||||
|
||||
#[error("Unknown error: {0}")]
|
||||
AnyHowError(anyhow::Error),
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Conversation {
|
||||
messages: Vec<ConversationMessage>,
|
||||
@@ -5,10 +7,21 @@ pub struct Conversation {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ConversationMessage {
|
||||
pub group: String,
|
||||
pub author: String,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl Display for ConversationMessage {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(
|
||||
f,
|
||||
"Group: {:#?}\nAuthor: {:#?}\nMessage: {:#?}",
|
||||
self.group, self.author, self.message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Conversation {
|
||||
/// Add a message string to the conversation list.
|
||||
pub fn add(&mut self, conversation_message: ConversationMessage) {
|
||||
@@ -29,7 +42,11 @@ impl Conversation {
|
||||
}
|
||||
|
||||
impl ConversationMessage {
|
||||
pub fn new(message: String, author: String) -> Self {
|
||||
Self { author, message }
|
||||
pub fn new(group: String, author: String, message: String) -> Self {
|
||||
Self {
|
||||
group,
|
||||
author,
|
||||
message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use hex;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use openmls::credentials::CredentialWithKey;
|
||||
use openmls::key_packages::*;
|
||||
use openmls::prelude::*;
|
||||
use openmls::{credentials::CredentialWithKey, key_packages::*, prelude::*};
|
||||
use openmls_basic_credential::SignatureKeyPair;
|
||||
use openmls_rust_crypto::MemoryKeyStoreError;
|
||||
use openmls_traits::types::Ciphersuite;
|
||||
@@ -69,13 +68,15 @@ impl Identity {
|
||||
pub fn identity(&self) -> Vec<u8> {
|
||||
self.credential_with_key.credential.identity().to_vec()
|
||||
}
|
||||
|
||||
pub fn signature_pub_key(&self) -> Vec<u8> {
|
||||
self.signer.public().to_vec()
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for Identity {
|
||||
fn to_string(&self) -> String {
|
||||
std::str::from_utf8(self.credential_with_key.credential.identity())
|
||||
.unwrap()
|
||||
.to_string()
|
||||
hex::encode(self.credential_with_key.credential.identity())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod cli;
|
||||
pub mod conversation;
|
||||
pub mod identity;
|
||||
pub mod user;
|
||||
|
||||
355
src/main.rs
355
src/main.rs
@@ -1,198 +1,189 @@
|
||||
use alloy::{primitives::Address, providers::ProviderBuilder};
|
||||
use bus::Bus;
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
use alloy::providers::ProviderBuilder;
|
||||
use clap::Parser;
|
||||
use openmls::framing::MlsMessageIn;
|
||||
use std::{error::Error, fs::File, io::Read};
|
||||
use tls_codec::Deserialize;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use openmls::framing::{MlsMessageIn, MlsMessageInBody};
|
||||
|
||||
use de_mls::{get_contract_address, user::User};
|
||||
use sc_key_store::sc_ks::*;
|
||||
use de_mls::{
|
||||
cli::*,
|
||||
user::{User, UserError},
|
||||
};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let storage_address = Address::from_str("0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512").unwrap();
|
||||
let (alice_address, alice_wallet) = alice_addr_test();
|
||||
let alice_provider = ProviderBuilder::new()
|
||||
async fn main() -> Result<(), Box<dyn Error>> {
|
||||
let token = CancellationToken::new();
|
||||
|
||||
let (cli_tx, mut cli_gr_rx) = mpsc::channel::<Commands>(100);
|
||||
|
||||
let args = Args::parse();
|
||||
let (user_address, wallet, storage_address) = get_user_data(&args)?;
|
||||
|
||||
let client_provider = ProviderBuilder::new()
|
||||
.with_recommended_fillers()
|
||||
.wallet(alice_wallet)
|
||||
.on_http(Url::from_str("http://localhost:8545").unwrap());
|
||||
.wallet(wallet)
|
||||
.on_http(args.storage_url);
|
||||
|
||||
let (bob_address, bob_wallet) = bob_addr_test();
|
||||
let bob_provider = ProviderBuilder::new()
|
||||
.with_recommended_fillers()
|
||||
.wallet(bob_wallet)
|
||||
.on_http(Url::from_str("http://localhost:8545").unwrap());
|
||||
|
||||
// This channel for message before adding to group.
|
||||
// Message are still encrypted, but this channel not attached to any group
|
||||
let mut m: Bus<MlsMessageIn> = Bus::new(10);
|
||||
let mut a_r = m.add_rx();
|
||||
let mut b_r = m.add_rx();
|
||||
|
||||
//// Create user Alice
|
||||
println!("Start Register Alice");
|
||||
let res = User::new(
|
||||
alice_address.as_slice(),
|
||||
alice_provider.clone(),
|
||||
//// Create user
|
||||
let mut user = User::new(
|
||||
user_address.as_slice(),
|
||||
client_provider.clone(),
|
||||
storage_address,
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_ok());
|
||||
let mut a_user = res.unwrap();
|
||||
let res = a_user.register().await;
|
||||
assert!(res.is_ok());
|
||||
println!("Register Alice successfully");
|
||||
//////
|
||||
.await?;
|
||||
|
||||
//// Create user Bob
|
||||
println!("Start Register Bob");
|
||||
let res = User::new(
|
||||
bob_address.as_slice(),
|
||||
bob_provider.clone(),
|
||||
storage_address,
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_ok());
|
||||
let mut b_user = res.unwrap();
|
||||
let res = b_user.register().await;
|
||||
assert!(res.is_ok());
|
||||
println!("Register Bob successfully");
|
||||
//////
|
||||
let (messages_tx, messages_rx) = mpsc::channel::<Msg>(100);
|
||||
messages_tx
|
||||
.send(Msg::Input(Message::System(format!(
|
||||
"Hello, {:}",
|
||||
user_address
|
||||
))))
|
||||
.await?;
|
||||
|
||||
//// Alice create group: Alice_Group
|
||||
println!("Start create group");
|
||||
let group_name = String::from_str("Alice_Group").unwrap();
|
||||
let res = a_user.create_group(group_name.clone()).await;
|
||||
assert!(res.is_ok());
|
||||
println!("Create group successfully");
|
||||
//////
|
||||
let messages_tx2 = messages_tx.clone();
|
||||
let event_token = token.clone();
|
||||
let h1 = tokio::spawn(async move { event_handler(messages_tx2, cli_tx, event_token).await });
|
||||
|
||||
//// Alice invite Bob
|
||||
println!("Alice inviting Bob");
|
||||
let welcome = a_user
|
||||
.invite(b_user.user_wallet_address().as_slice(), group_name.clone())
|
||||
.await;
|
||||
assert!(welcome.is_ok());
|
||||
// Alice should skip message with invite update because she already update her instance
|
||||
// It is failed because of wrong epoch
|
||||
let res = a_user.recieve_msg(group_name.clone()).await;
|
||||
assert!(res.is_err());
|
||||
let res_msg_tx = messages_tx.clone();
|
||||
let main_token = token.clone();
|
||||
let h2 = tokio::spawn(async move {
|
||||
let (redis_tx, mut redis_rx) = mpsc::channel::<Vec<u8>>(100);
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(val) = redis_rx.recv() =>{
|
||||
let res = user.receive_msg(val).await;
|
||||
match res {
|
||||
Ok(msg) => {
|
||||
match msg {
|
||||
Some(m) => res_msg_tx.send(Msg::Input(Message::Incoming(m.group, m.author, m.message))).await?,
|
||||
None => continue
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
res_msg_tx
|
||||
.send(Msg::Input(Message::Error(err.to_string())))
|
||||
.await?;
|
||||
},
|
||||
};
|
||||
}
|
||||
Some(command) = cli_gr_rx.recv() => {
|
||||
// res_msg_tx.send(Msg::Input(Message::System(format!("Get command: {:?}", command)))).await?;
|
||||
match command {
|
||||
Commands::CreateGroup { group_name } => {
|
||||
let res = user.create_group(group_name.clone()).await;
|
||||
match res {
|
||||
Ok(mut br) => {
|
||||
let msg = format!("Successfully create group: {:?}", group_name.clone());
|
||||
res_msg_tx.send(Msg::Input(Message::System(msg))).await?;
|
||||
|
||||
//// Send welcome message to system broadcast. Only Bob can use it
|
||||
m.broadcast(welcome.unwrap());
|
||||
let _ = a_r.recv();
|
||||
let welc = b_r.recv();
|
||||
assert!(welc.is_ok());
|
||||
let _ = match welc.unwrap().extract() {
|
||||
MlsMessageInBody::Welcome(welcome) => {
|
||||
let res = b_user.join_group(welcome).await;
|
||||
assert!(res.is_ok());
|
||||
Ok(())
|
||||
let redis_tx = redis_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(msg) = br.recv().await {
|
||||
let bytes: Vec<u8> = msg.value.convert()?;
|
||||
redis_tx.send(bytes).await?;
|
||||
}
|
||||
Ok::<_, CliError>(())
|
||||
});
|
||||
},
|
||||
Err(err) => {
|
||||
res_msg_tx
|
||||
.send(Msg::Input(Message::Error(err.to_string())))
|
||||
.await?;
|
||||
},
|
||||
};
|
||||
},
|
||||
Commands::Invite { group_name, user_wallet } => {
|
||||
let res = user.invite(user_wallet, group_name.clone()).await;
|
||||
match res {
|
||||
Ok(_) => {
|
||||
let msg = format!("Invite {:} to the group {:}\n",
|
||||
user_address, group_name
|
||||
);
|
||||
res_msg_tx.send(Msg::Input(Message::System(msg))).await?;
|
||||
},
|
||||
Err(err) => {
|
||||
res_msg_tx
|
||||
.send(Msg::Input(Message::Error(err.to_string())))
|
||||
.await?;
|
||||
},
|
||||
};
|
||||
},
|
||||
Commands::JoinGroup { group_name } => {
|
||||
let mut file = File::open(format!("invite_{group_name}.txt"))?;
|
||||
let mut welcome = String::new();
|
||||
file.read_to_string(&mut welcome).unwrap();
|
||||
|
||||
let wbytes = hex::decode(welcome).unwrap();
|
||||
let welc = MlsMessageIn::tls_deserialize_bytes(wbytes).unwrap();
|
||||
let welcome = welc.into_welcome();
|
||||
if welcome.is_some() {
|
||||
let res = user.join_group(welcome.unwrap()).await;
|
||||
match res {
|
||||
Ok(mut buf) => {
|
||||
let msg = format!("Succesfully join to the group: {:#?}", buf.1);
|
||||
res_msg_tx.send(Msg::Input(Message::System(msg))).await?;
|
||||
|
||||
let redis_tx = redis_tx.clone();
|
||||
tokio::spawn(async move {
|
||||
while let Ok(msg) = buf.0.recv().await {
|
||||
let bytes: Vec<u8> = msg.value.convert()?;
|
||||
redis_tx.send(bytes).await?;
|
||||
}
|
||||
Ok::<_, CliError>(())
|
||||
});
|
||||
},
|
||||
Err(err) => {
|
||||
res_msg_tx
|
||||
.send(Msg::Input(Message::Error(err.to_string())))
|
||||
.await?;
|
||||
},
|
||||
};
|
||||
} else {
|
||||
res_msg_tx
|
||||
.send(Msg::Input(Message::Error(UserError::EmptyWelcomeMessageError.to_string())))
|
||||
.await?;
|
||||
}
|
||||
|
||||
},
|
||||
Commands::SendMessage { group_name, msg } => {
|
||||
let message = msg.join(" ");
|
||||
let res = user.send_msg(&message, group_name.clone(), user.identity.to_string()).await;
|
||||
match res {
|
||||
Ok(_) => {
|
||||
res_msg_tx.send(Msg::Input(Message::Mine(group_name, user.identity.to_string(), message ))).await?;
|
||||
},
|
||||
Err(err) => {
|
||||
res_msg_tx
|
||||
.send(Msg::Input(Message::Error(err.to_string())))
|
||||
.await?;
|
||||
},
|
||||
};
|
||||
},
|
||||
Commands::Exit => {
|
||||
res_msg_tx.send(Msg::Input(Message::System("Bye!".to_string()))).await?;
|
||||
break
|
||||
},
|
||||
}
|
||||
}
|
||||
_ = main_token.cancelled() => {
|
||||
break;
|
||||
}
|
||||
else => {
|
||||
res_msg_tx.send(Msg::Input(Message::System("Something went wrong".to_string()))).await?;
|
||||
break
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => Err("do nothing".to_string()),
|
||||
};
|
||||
println!("Bob successfully join to the group");
|
||||
/////
|
||||
Ok::<_, CliError>(())
|
||||
});
|
||||
|
||||
//// Bob send message and Alice recieve it
|
||||
let res = b_user.send_msg("Hi!", group_name.clone()).await;
|
||||
assert!(res.is_ok());
|
||||
let h3 = tokio::spawn(async move { terminal_handler(messages_rx, token).await });
|
||||
|
||||
// Bob also get the message but he cant decrypt it (regarding the mls rfc)
|
||||
let res = b_user.recieve_msg(group_name.clone()).await;
|
||||
// Expected error with invalid decryption
|
||||
assert!(res.is_err());
|
||||
let handler_res = tokio::join!(h1, h2, h3);
|
||||
handler_res.0??;
|
||||
handler_res.1??;
|
||||
handler_res.2??;
|
||||
|
||||
let res = a_user.recieve_msg(group_name.clone()).await;
|
||||
assert!(res.is_ok());
|
||||
/////
|
||||
|
||||
//// Alice send message and Bob recieve it
|
||||
let res = a_user.send_msg("Hi Bob!", group_name.clone()).await;
|
||||
assert!(res.is_ok());
|
||||
|
||||
let res = a_user.recieve_msg(group_name.clone()).await;
|
||||
assert!(res.is_err());
|
||||
|
||||
let res = b_user.recieve_msg(group_name.clone()).await;
|
||||
assert!(res.is_ok());
|
||||
/////
|
||||
|
||||
let msg = a_user.read_msgs(group_name.clone());
|
||||
println!("Alice recieve_msgs: {:#?}", msg);
|
||||
let msg = b_user.read_msgs(group_name.clone());
|
||||
println!("Bob recieve_msgs: {:#?}", msg);
|
||||
|
||||
let (carla_address, carla_wallet) = carla_addr_test();
|
||||
let carla_provider = ProviderBuilder::new()
|
||||
.with_recommended_fillers()
|
||||
.wallet(carla_wallet)
|
||||
.on_http(Url::from_str("http://localhost:8545").unwrap());
|
||||
|
||||
let mut c_r = m.add_rx();
|
||||
//// Create user Alice
|
||||
println!("Start Register Carla");
|
||||
let res = User::new(
|
||||
carla_address.as_slice(),
|
||||
carla_provider.clone(),
|
||||
storage_address,
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_ok());
|
||||
let mut c_user = res.unwrap();
|
||||
let res = c_user.register().await;
|
||||
assert!(res.is_ok());
|
||||
println!("Register Carla successfully");
|
||||
//////
|
||||
|
||||
//// Alice invite Carla
|
||||
println!("Alice inviting Carla");
|
||||
let welcome = a_user
|
||||
.invite(c_user.user_wallet_address().as_slice(), group_name.clone())
|
||||
.await;
|
||||
assert!(welcome.is_ok());
|
||||
// Alice should skip message with invite update because she already update her instance
|
||||
// It is failed because of wrong epoch
|
||||
let res = a_user.recieve_msg(group_name.clone()).await;
|
||||
assert!(res.is_err());
|
||||
let res = b_user.recieve_msg(group_name.clone()).await;
|
||||
assert!(res.is_ok());
|
||||
|
||||
//// Send welcome message to system broadcast. Only Bob can use it
|
||||
m.broadcast(welcome.unwrap());
|
||||
let _ = a_r.recv();
|
||||
let _ = b_r.recv();
|
||||
let welc = c_r.recv();
|
||||
assert!(welc.is_ok());
|
||||
let _ = match welc.unwrap().extract() {
|
||||
MlsMessageInBody::Welcome(welcome) => {
|
||||
let res = c_user.join_group(welcome).await;
|
||||
assert!(res.is_ok());
|
||||
Ok(())
|
||||
}
|
||||
_ => Err("do nothing".to_string()),
|
||||
};
|
||||
println!("Carla successfully join to the group");
|
||||
/////
|
||||
|
||||
//// Carla send message and Alice and Bob recieve it
|
||||
let res = c_user.send_msg("Hi all!", group_name.clone()).await;
|
||||
assert!(res.is_ok());
|
||||
|
||||
let res = c_user.recieve_msg(group_name.clone()).await;
|
||||
assert!(res.is_err());
|
||||
|
||||
let res = a_user.recieve_msg(group_name.clone()).await;
|
||||
assert!(res.is_ok());
|
||||
|
||||
let res = b_user.recieve_msg(group_name.clone()).await;
|
||||
assert!(res.is_ok());
|
||||
////
|
||||
|
||||
let msg = a_user.read_msgs(group_name.clone());
|
||||
println!("Alice recieve_msgs: {:#?}", msg);
|
||||
let msg = b_user.read_msgs(group_name.clone());
|
||||
println!("Bob recieve_msgs: {:#?}", msg);
|
||||
let msg = c_user.read_msgs(group_name.clone());
|
||||
println!("Carla recieve_msgs: {:#?}", msg);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
271
src/user.rs
271
src/user.rs
@@ -1,16 +1,30 @@
|
||||
use std::{
|
||||
borrow::BorrowMut, cell::RefCell, collections::HashMap, str, str::Utf8Error,
|
||||
string::FromUtf8Error,
|
||||
use alloy::{
|
||||
hex::{self, FromHexError, ToHexExt},
|
||||
network::Network,
|
||||
primitives::Address,
|
||||
providers::Provider,
|
||||
transports::Transport,
|
||||
};
|
||||
|
||||
use alloy::{network::Network, primitives::Address, providers::Provider, transports::Transport};
|
||||
use fred::types::Message;
|
||||
use openmls::{group::*, prelude::*};
|
||||
use openmls_rust_crypto::MemoryKeyStoreError;
|
||||
use std::{
|
||||
borrow::BorrowMut,
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
fmt::Display,
|
||||
fs::File,
|
||||
io::Write,
|
||||
str::{from_utf8, FromStr, Utf8Error},
|
||||
string::FromUtf8Error,
|
||||
};
|
||||
use tokio::sync::broadcast::Receiver;
|
||||
|
||||
use ds::ds::*;
|
||||
use mls_crypto::openmls_provider::*;
|
||||
use sc_key_store::{local_ks::LocalCache, sc_ks::ScKeyStorage, *};
|
||||
// use waku_bindings::*;
|
||||
//
|
||||
|
||||
use crate::conversation::*;
|
||||
use crate::identity::{Identity, IdentityError};
|
||||
@@ -19,14 +33,20 @@ pub struct Group {
|
||||
group_name: String,
|
||||
conversation: Conversation,
|
||||
mls_group: RefCell<MlsGroup>,
|
||||
epoch: GroupEpoch,
|
||||
rc_client: RClient,
|
||||
// pubsub_topic: WakuPubSubTopic,
|
||||
// content_topics: Vec<WakuContentTopic>,
|
||||
}
|
||||
impl Display for Group {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "Group: {:#?}", self.group_name)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct User<T, P, N> {
|
||||
pub(crate) identity: Identity,
|
||||
pub(crate) groups: HashMap<String, Group>,
|
||||
pub identity: Identity,
|
||||
pub groups: HashMap<String, Group>,
|
||||
provider: MlsCryptoProvider,
|
||||
sc_ks: ScKeyStorage<T, P, N>,
|
||||
local_ks: LocalCache,
|
||||
@@ -47,25 +67,26 @@ where
|
||||
) -> Result<Self, UserError> {
|
||||
let crypto = MlsCryptoProvider::default();
|
||||
let id = Identity::new(CIPHERSUITE, &crypto, user_wallet_address)?;
|
||||
Ok(User {
|
||||
let mut user = User {
|
||||
groups: HashMap::new(),
|
||||
identity: id,
|
||||
provider: crypto,
|
||||
local_ks: LocalCache::empty_key_store(user_wallet_address),
|
||||
sc_ks: ScKeyStorage::new(provider, sc_storage_address),
|
||||
// contacts: HashMap::new(),
|
||||
})
|
||||
};
|
||||
user.register().await?;
|
||||
Ok(user)
|
||||
}
|
||||
|
||||
pub fn user_wallet_address(&self) -> Vec<u8> {
|
||||
self.identity.identity()
|
||||
}
|
||||
|
||||
pub async fn create_group(&mut self, group_name: String) -> Result<(), UserError> {
|
||||
pub async fn create_group(
|
||||
&mut self,
|
||||
group_name: String,
|
||||
) -> Result<Receiver<Message>, UserError> {
|
||||
let group_id = group_name.as_bytes();
|
||||
|
||||
if self.groups.contains_key(&group_name) {
|
||||
return Err(UserError::UnknownGroupError(group_name));
|
||||
return Err(UserError::AlreadyExistedGroupError(group_name));
|
||||
}
|
||||
|
||||
let group_config = MlsGroupConfig::builder()
|
||||
@@ -80,21 +101,23 @@ where
|
||||
self.identity.credential_with_key.clone(),
|
||||
)?;
|
||||
|
||||
let rc = RClient::new_for_group(group_name.clone()).await?;
|
||||
let (rc, broadcaster) = RClient::new_for_group(group_name.clone()).await?;
|
||||
let epoch = mls_group.epoch();
|
||||
let group = Group {
|
||||
group_name: group_name.clone(),
|
||||
conversation: Conversation::default(),
|
||||
mls_group: RefCell::new(mls_group),
|
||||
epoch,
|
||||
rc_client: rc,
|
||||
// pubsub_topic: WakuPubSubTopic::new(),
|
||||
// content_topics: Vec::new(),
|
||||
};
|
||||
|
||||
self.groups.insert(group_name, group);
|
||||
Ok(())
|
||||
Ok(broadcaster)
|
||||
}
|
||||
|
||||
pub async fn register(&mut self) -> Result<(), UserError> {
|
||||
async fn register(&mut self) -> Result<(), UserError> {
|
||||
let kp = self.key_packages();
|
||||
self.sc_ks
|
||||
.borrow_mut()
|
||||
@@ -114,9 +137,11 @@ where
|
||||
|
||||
pub async fn invite(
|
||||
&mut self,
|
||||
user_wallet_address: &[u8],
|
||||
user_wallet: String,
|
||||
group_name: String,
|
||||
) -> Result<MlsMessageIn, UserError> {
|
||||
) -> Result<(), UserError> {
|
||||
let user_address = Address::from_str(&user_wallet)?;
|
||||
let user_wallet_address = user_address.as_slice();
|
||||
// First we need to get the key package for {id} from the DS.
|
||||
if !self
|
||||
.sc_ks
|
||||
@@ -146,71 +171,70 @@ where
|
||||
&[joiner_key_package],
|
||||
)?;
|
||||
|
||||
group.rc_client.msg_send(out_messages).await?;
|
||||
group
|
||||
.rc_client
|
||||
.msg_send(out_messages, self.identity.to_string())
|
||||
.await?;
|
||||
// Second, process the invitation on our end.
|
||||
group
|
||||
.mls_group
|
||||
.borrow_mut()
|
||||
.merge_pending_commit(&self.provider)?;
|
||||
|
||||
group.epoch = group.mls_group.borrow_mut().epoch();
|
||||
// Put sending welcome by p2p here
|
||||
let bytes = welcome.tls_serialize_detached()?;
|
||||
let string = bytes.encode_hex();
|
||||
|
||||
Ok(welcome.into())
|
||||
let mut file = File::create(format!("invite_{group_name}.txt"))?;
|
||||
file.write_all(string.as_bytes())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn recieve_msg(&mut self, group_name: String) -> Result<(), UserError> {
|
||||
pub async fn receive_msg(
|
||||
&mut self,
|
||||
msg_bytes: Vec<u8>,
|
||||
) -> Result<Option<ConversationMessage>, UserError> {
|
||||
let buf: SenderStruct = serde_json::from_slice(&msg_bytes)?;
|
||||
if buf.sender == self.identity.to_string() {
|
||||
return Ok(None);
|
||||
}
|
||||
let res = MlsMessageIn::tls_deserialize_bytes(&buf.msg)?;
|
||||
let msg = match res.extract() {
|
||||
MlsMessageInBody::PrivateMessage(message) => {
|
||||
self.process_protocol_msg(message.into())?
|
||||
}
|
||||
MlsMessageInBody::PublicMessage(message) => {
|
||||
self.process_protocol_msg(message.into())?
|
||||
}
|
||||
_ => return Err(UserError::MessageTypeError),
|
||||
};
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
pub fn process_protocol_msg(
|
||||
&mut self,
|
||||
message: ProtocolMessage,
|
||||
) -> Result<Option<ConversationMessage>, UserError> {
|
||||
let group_name = from_utf8(message.group_id().as_slice())?.to_string();
|
||||
let group = match self.groups.get_mut(&group_name) {
|
||||
Some(g) => g,
|
||||
None => return Err(UserError::UnknownGroupError(group_name)),
|
||||
};
|
||||
|
||||
let msg = group.rc_client.msg_recv().await?;
|
||||
|
||||
match msg.extract() {
|
||||
MlsMessageInBody::Welcome(_welcome) => {
|
||||
// Now irrelevant because message are attached to group
|
||||
// self.join_group(welcome, Rc::clone(&group.ds_node))?;
|
||||
}
|
||||
MlsMessageInBody::PrivateMessage(message) => {
|
||||
self.process_protocol_msg(message.into())?;
|
||||
}
|
||||
MlsMessageInBody::PublicMessage(message) => {
|
||||
self.process_protocol_msg(message.into())?;
|
||||
}
|
||||
_ => return Err(UserError::MessageTypeError),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_protocol_msg(&mut self, message: ProtocolMessage) -> Result<(), UserError> {
|
||||
let group_name = str::from_utf8(message.group_id().as_slice())?;
|
||||
let group = match self.groups.get_mut(group_name) {
|
||||
Some(g) => g,
|
||||
None => return Err(UserError::UnknownGroupError(group_name.to_string())),
|
||||
};
|
||||
let mut mls_group = group.mls_group.borrow_mut();
|
||||
|
||||
let processed_message = mls_group.process_message(&self.provider, message)?;
|
||||
|
||||
let processed_message_credential: Credential = processed_message.credential().clone();
|
||||
|
||||
match processed_message.into_content() {
|
||||
ProcessedMessageContent::ApplicationMessage(application_message) => {
|
||||
let sender_name = {
|
||||
let user_id = mls_group.members().find_map(|m| {
|
||||
if m.credential.identity()
|
||||
== processed_message_credential.identity()
|
||||
&& (self
|
||||
.identity
|
||||
.credential_with_key
|
||||
.signature_key
|
||||
.as_slice()
|
||||
if m.credential.identity() == processed_message_credential.identity()
|
||||
&& (self.identity.credential_with_key.signature_key.as_slice()
|
||||
!= m.signature_key.as_slice())
|
||||
{
|
||||
println!("process ApplicationMessage: read sender name from credential identity for group {} ", group.group_name);
|
||||
Some(
|
||||
format!("{:?}", m.credential.identity())
|
||||
)
|
||||
Some(hex::encode(m.credential.identity()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -219,10 +243,12 @@ where
|
||||
};
|
||||
|
||||
let conversation_message = ConversationMessage::new(
|
||||
String::from_utf8(application_message.into_bytes())?,
|
||||
group_name,
|
||||
sender_name,
|
||||
String::from_utf8(application_message.into_bytes())?,
|
||||
);
|
||||
group.conversation.add(conversation_message);
|
||||
group.conversation.add(conversation_message.clone());
|
||||
return Ok(Some(conversation_message));
|
||||
}
|
||||
ProcessedMessageContent::ProposalMessage(_proposal_ptr) => (),
|
||||
ProcessedMessageContent::ExternalJoinProposalMessage(_external_proposal_ptr) => (),
|
||||
@@ -232,20 +258,23 @@ where
|
||||
remove_proposal = true;
|
||||
}
|
||||
mls_group.merge_staged_commit(&self.provider, *commit_ptr)?;
|
||||
group.epoch = group.mls_group.borrow_mut().epoch();
|
||||
if remove_proposal {
|
||||
println!(
|
||||
"update::Processing StagedCommitMessage removing {} from group {} ",
|
||||
self.identity.to_string(),
|
||||
group.group_name
|
||||
);
|
||||
return Ok(());
|
||||
// here we need to remove group instance locally and
|
||||
// also remove correspond key package from local storage ans sc storage
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub async fn send_msg(&mut self, msg: &str, group_name: String) -> Result<(), UserError> {
|
||||
pub async fn send_msg(
|
||||
&mut self,
|
||||
msg: &str,
|
||||
group_name: String,
|
||||
sender: String,
|
||||
) -> Result<(), UserError> {
|
||||
let group = match self.groups.get_mut(&group_name) {
|
||||
Some(g) => g,
|
||||
None => return Err(UserError::UnknownGroupError(group_name)),
|
||||
@@ -257,11 +286,14 @@ where
|
||||
msg.as_bytes(),
|
||||
)?;
|
||||
|
||||
group.rc_client.msg_send(message_out).await?;
|
||||
group.rc_client.msg_send(message_out, sender).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn join_group(&mut self, welcome: Welcome) -> Result<(), UserError> {
|
||||
pub async fn join_group(
|
||||
&mut self,
|
||||
welcome: Welcome,
|
||||
) -> Result<(Receiver<Message>, String), UserError> {
|
||||
let group_config = MlsGroupConfig::builder()
|
||||
.use_ratchet_tree_extension(true)
|
||||
.build();
|
||||
@@ -271,47 +303,49 @@ where
|
||||
let group_id = mls_group.group_id().to_vec();
|
||||
let group_name = String::from_utf8(group_id)?;
|
||||
|
||||
let rc = RClient::new_for_group(group_name.clone()).await?;
|
||||
let (rc, br) = RClient::new_for_group(group_name.clone()).await?;
|
||||
let epoch = mls_group.epoch();
|
||||
let group = Group {
|
||||
group_name: group_name.clone(),
|
||||
conversation: Conversation::default(),
|
||||
mls_group: RefCell::new(mls_group),
|
||||
epoch,
|
||||
rc_client: rc,
|
||||
};
|
||||
|
||||
match self.groups.insert(group_name, group) {
|
||||
match self.groups.insert(group_name.clone(), group) {
|
||||
Some(old) => Err(UserError::AlreadyExistedGroupError(old.group_name)),
|
||||
None => Ok(()),
|
||||
None => Ok((br, group_name)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn remove(&mut self, name: String, group_name: String) -> Result<(), UserError> {
|
||||
// Get the group ID
|
||||
let group = match self.groups.get_mut(&group_name) {
|
||||
Some(g) => g,
|
||||
None => return Err(UserError::UnknownGroupError(group_name)),
|
||||
};
|
||||
// pub async fn remove(&mut self, name: String, group_name: String) -> Result<(), UserError> {
|
||||
// // Get the group ID
|
||||
// let group = match self.groups.get_mut(&group_name) {
|
||||
// Some(g) => g,
|
||||
// None => return Err(UserError::UnknownGroupError(group_name)),
|
||||
// };
|
||||
|
||||
// Get the user leaf index
|
||||
let leaf_index = group.find_member_index(name)?;
|
||||
// // Get the user leaf index
|
||||
// let leaf_index = group.find_member_index(name)?;
|
||||
|
||||
// Remove operation on the mls group
|
||||
let (remove_message, _welcome, _group_info) = group.mls_group.borrow_mut().remove_members(
|
||||
&self.provider,
|
||||
&self.identity.signer,
|
||||
&[leaf_index],
|
||||
)?;
|
||||
// // Remove operation on the mls group
|
||||
// let (remove_message, _welcome, _group_info) = group.mls_group.borrow_mut().remove_members(
|
||||
// &self.provider,
|
||||
// &self.identity.signer,
|
||||
// &[leaf_index],
|
||||
// )?;
|
||||
|
||||
group.rc_client.msg_send(remove_message).await?;
|
||||
// group.rc_client.msg_send(remove_message).await?;
|
||||
|
||||
// Second, process the removal on our end.
|
||||
group
|
||||
.mls_group
|
||||
.borrow_mut()
|
||||
.merge_pending_commit(&self.provider)?;
|
||||
// // Second, process the removal on our end.
|
||||
// group
|
||||
// .mls_group
|
||||
// .borrow_mut()
|
||||
// .merge_pending_commit(&self.provider)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
/// Return the last 100 messages sent to the group.
|
||||
pub fn read_msgs(
|
||||
@@ -327,30 +361,45 @@ where
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub fn group_members(&self, group_name: String) -> Result<Vec<String>, UserError> {
|
||||
let group = match self.groups.get(&group_name) {
|
||||
Some(g) => g,
|
||||
None => return Err(UserError::UnknownGroupError(group_name)),
|
||||
};
|
||||
Ok(group.group_members(self.identity.signature_pub_key().as_slice()))
|
||||
}
|
||||
|
||||
pub fn user_groups(&self) -> Result<Vec<String>, UserError> {
|
||||
if self.groups.is_empty() {
|
||||
return Ok(Vec::default());
|
||||
}
|
||||
Ok(self.groups.keys().map(|k| k.to_owned()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl Group {
|
||||
/// Get a member
|
||||
fn find_member_index(&self, name: String) -> Result<LeafNodeIndex, GroupError> {
|
||||
fn find_member_index(&self, user_id: String) -> Result<LeafNodeIndex, GroupError> {
|
||||
let member = self
|
||||
.mls_group
|
||||
.borrow()
|
||||
.members()
|
||||
.find(|m| m.credential.identity().eq(name.as_bytes()));
|
||||
.find(|m| m.credential.identity().eq(user_id.as_bytes()));
|
||||
|
||||
match member {
|
||||
Some(m) => Ok(m.index),
|
||||
None => Err(GroupError::UnknownGroupMemberError(name)),
|
||||
None => Err(GroupError::UnknownGroupMemberError(user_id)),
|
||||
}
|
||||
}
|
||||
|
||||
fn group_members(&self, user_signature: &[u8]) -> Vec<Vec<u8>> {
|
||||
pub fn group_members(&self, user_signature: &[u8]) -> Vec<String> {
|
||||
self.mls_group
|
||||
.borrow()
|
||||
.members()
|
||||
.filter(|m| m.signature_key == user_signature)
|
||||
.map(|m| m.credential.identity().to_vec())
|
||||
.collect::<Vec<Vec<u8>>>()
|
||||
.map(|m| hex::encode(m.credential.identity()))
|
||||
.collect::<Vec<String>>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,6 +419,9 @@ pub enum UserError {
|
||||
MessageTypeError,
|
||||
#[error("Unknown user")]
|
||||
UnknownUserError,
|
||||
#[error("Empty welcome message")]
|
||||
EmptyWelcomeMessageError,
|
||||
|
||||
#[error("Delivery Service error: {0}")]
|
||||
DeliveryServiceError(#[from] DeliveryServiceError),
|
||||
#[error(transparent)]
|
||||
@@ -378,6 +430,7 @@ pub enum UserError {
|
||||
KeyStoreError(#[from] KeyStoreError),
|
||||
#[error("Identity error: {0}")]
|
||||
IdentityError(#[from] IdentityError),
|
||||
|
||||
#[error("Something wrong while creating Mls group: {0}")]
|
||||
MlsGroupCreationError(#[from] NewGroupError<MemoryKeyStoreError>),
|
||||
#[error("Something wrong while adding member to Mls group: {0}")]
|
||||
@@ -394,10 +447,20 @@ pub enum UserError {
|
||||
MlsWelcomeError(#[from] WelcomeError<MemoryKeyStoreError>),
|
||||
#[error("Failed to remove member from group: {0}")]
|
||||
MlsRemoveMembersError(#[from] RemoveMembersError<MemoryKeyStoreError>),
|
||||
|
||||
#[error("Parse String UTF8 error: {0}")]
|
||||
ParseUTF8Error(#[from] FromUtf8Error),
|
||||
#[error("Parse str UTF8 error: {0}")]
|
||||
ParseStrUTF8Error(#[from] Utf8Error),
|
||||
#[error("Json error: {0}")]
|
||||
JsonError(#[from] serde_json::Error),
|
||||
#[error("Serialization problem: {0}")]
|
||||
TlsError(#[from] tls_codec::Error),
|
||||
#[error("Unable to parce the address: {0}")]
|
||||
AlloyFromHexError(#[from] FromHexError),
|
||||
#[error("Write to stdout error")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("Unknown error: {0}")]
|
||||
Other(anyhow::Error),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user