Skip to content

Commit

Permalink
integration testing
Browse files Browse the repository at this point in the history
  • Loading branch information
insipx committed Jan 19, 2024
1 parent ecdbc04 commit fbc885d
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 44 deletions.
4 changes: 3 additions & 1 deletion Cargo.lock

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

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ resolver = "2"
log = "0.4"
tracing = "0.1"
tracing-subscriber = { version = "0.3.18", features = ["fmt", "env-filter"] }
serde = "1"
serde = "1.0"
serde_json = "1.0"
tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] }
async-trait = "0.1"
jsonrpsee = { version = "0.21", features = ["macros", "server", "client-core"] }
Expand All @@ -29,3 +30,4 @@ ctor = "0.2"
lib-didethresolver = { git = "https://github.com/xmtp/didethresolver", branch = "insipx/revoke-installation", package = "lib-didethresolver" }
gateway-types = { path = "./gateway-types" }
rustc-hex = "2.1"
hex = "0.4"
23 changes: 10 additions & 13 deletions gateway-types/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use lib_didethresolver::types::{Attribute, KeyEncoding, KeyPurpose, KeyType, PublicKey};
use lib_didethresolver::types::{
Attribute, KeyEncoding, KeyMetadata, KeyPurpose, KeyType, PublicKey,
};
use serde::{Deserialize, Serialize};

/// Address of the did:ethr Registry on Sepolia
Expand All @@ -8,22 +10,16 @@ pub const DID_ETH_REGISTRY: &str = "0xd1D374DDE031075157fDb64536eF5cC13Ae75000";
#[derive(Serialize, Deserialize)]
pub struct Message {
// Unique identifier for a conversation
#[serde(rename = "groupId")]
group_id: Vec<u8>,
#[serde(rename = "conversationId")]
pub conversation_id: Vec<u8>,
/// message content in bytes
payload: Vec<u8>,
signature: Signature,
}

/// A Signature containing V, R S
#[derive(Serialize, Deserialize)]
pub struct Signature {
pub payload: Vec<u8>,
/// Signature of V
pub v: u8,
pub v: Vec<u8>,
/// Signature of R
pub r: [u8; 32],
pub r: Vec<u8>,
/// Signature of S
pub s: [u8; 32],
pub s: Vec<u8>,
}

/// The XMTP-specific attribute type
Expand All @@ -39,6 +35,7 @@ impl From<XmtpAttributeType> for Attribute {
key_type: KeyType::Ed25519VerificationKey2020,
purpose: KeyPurpose::Xmtp,
encoding: KeyEncoding::Hex,
metadata: Some(KeyMetadata::Installation),
}),
}
}
Expand Down
11 changes: 6 additions & 5 deletions registry/src/contact_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
use std::str::FromStr;

use ethers::{providers::Middleware, types::Address};
use gateway_types::{Signature, XmtpAttributeType};
use ethers::{core::types::Signature, providers::Middleware, types::Address};
use gateway_types::XmtpAttributeType;
use lib_didethresolver::{did_registry::DIDRegistry, types::Attribute};

use crate::error::ContactOperationError;
Expand All @@ -30,13 +30,14 @@ where
) -> Result<(), ContactOperationError<M>> {
// for now, we will just assume the DID is a valid ethereum wallet address
// TODO: Parse or resolve the actual DID
// TODO: Remove unwraps
let address = Address::from_str(&did)?;
self.registry
.revoke_attribute_signed(
address,
signature.v,
signature.r,
signature.s,
signature.v.try_into().unwrap(),
signature.r.try_into().unwrap(),
signature.s.try_into().unwrap(),
Attribute::from(name).into(),
value.into(),
)
Expand Down
5 changes: 4 additions & 1 deletion xps-gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ gateway-types.workspace = true
rand = "0.8"
tokio-stream = { version = "0.1", features = ["net"] }
registry = { path = "../registry" }
hex.workspace = true

[dev-dependencies]
jsonrpsee = { workspacve = true, features = ["macros", "server", "client"]}
jsonrpsee = { workspace = true, features = ["macros", "server", "client"]}
tokio = { workspace = true, features = ["macros", "rt", "time"]}
futures = "0.3"
serde_json.workspace = true

3 changes: 2 additions & 1 deletion xps-gateway/src/rpc/api.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Trait Interface Definitions for XPS JSON-RPC
use ethers::core::types::Signature;
use jsonrpsee::{proc_macros::rpc, types::ErrorObjectOwned};

use gateway_types::{Message, Signature, XmtpAttributeType};
use gateway_types::{Message, XmtpAttributeType};

/// XPS JSON-RPC Interface Methods
#[rpc(server, client, namespace = "xps")]
Expand Down
17 changes: 2 additions & 15 deletions xps-gateway/src/rpc/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ use super::api::*;
use jsonrpsee::types::error::ErrorCode;

use async_trait::async_trait;
use ethers::providers::Middleware;
use ethers::{core::types::Signature, providers::Middleware};
use jsonrpsee::types::ErrorObjectOwned;
use thiserror::Error;

use gateway_types::{Message, Signature, XmtpAttributeType};
use gateway_types::{Message, XmtpAttributeType};
use registry::{error::ContactOperationError, ContactOperations};

/// Gateway Methods for XPS
Expand All @@ -26,19 +26,6 @@ impl XpsMethods {
}
}

impl XpsMethods {
/// Create a new instance of the XpsMethods struct
pub fn new() -> Self {
Self {}
}
}

impl Default for XpsMethods {
fn default() -> Self {
Self::new()
}
}

#[async_trait]
impl XpsServer for XpsMethods {
async fn send_message(&self, _message: Message) -> Result<(), ErrorObjectOwned> {
Expand Down
117 changes: 110 additions & 7 deletions xps-gateway/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,38 @@ use jsonrpsee::{
ws_client::{WsClient, WsClientBuilder},
};

use ethers::{
abi::Address,
core::utils::Anvil,
middleware::Middleware,
middleware::SignerMiddleware,
providers::{Provider, Ws},
signers::{LocalWallet, Signer as _},
utils::AnvilInstance,
};
use futures::future::FutureExt;
use std::{future::Future, time::Duration};
use lib_didethresolver::{did_registry::DIDRegistry, Resolver};
use std::{future::Future, sync::Arc, time::Duration};
use tokio::time::timeout as timeout_tokio;

use xps_gateway::{rpc::XpsClient, types::Message, XpsMethods, XpsServer, SERVER_HOST};
use xps_gateway::{
rpc::XpsClient,
types::{GatewayContext, GatewaySigner},
XpsMethods, XpsServer, SERVER_HOST,
};

const TEST_TIMEOUT: Duration = Duration::from_secs(10);

#[cfg(test)]
mod it {
use ethers::{abi::Bytes, types::U256};
use gateway_types::{Message, XmtpAttributeType};

use super::*;

#[tokio::test]
async fn test_say_hello() -> Result<(), Error> {
with_xps_client(None, |client| async move {
with_xps_client(None, |client, _, _, _| async move {
let result = client.status().await?;
assert_eq!(result, "OK");
Ok(())
Expand All @@ -28,7 +45,7 @@ mod it {

#[tokio::test]
async fn test_fail_send_message() -> Result<(), Error> {
with_xps_client(None, |client| async move {
with_xps_client(None, |client, _, _, _| async move {
let message = Message {
conversation_id: b"abcdefg".iter().map(|c| *c as u8).collect(),
payload: b"Hello World".iter().map(|c| *c as u8).collect(),
Expand All @@ -42,21 +59,79 @@ mod it {
})
.await
}

#[tokio::test]
async fn test_revoke_installation() -> Result<(), Error> {
with_xps_client(None, |client, context, resolver, _| async move {
let me = context.signer.address();
let name = *b"did/pub/xmtp/ed25519/inst/hex ";
let value = b"02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71";
let validity = U256::from(604_800);
let tx = context
.registry
.set_attribute(me, name, value.into(), validity)
.tx;
let signature = context.signer.sign_transaction(&tx, me).await.unwrap();
let attr = context.registry.set_attribute_signed(
me,
signature.v.try_into().unwrap(),
signature.r.try_into().unwrap(),
signature.s.try_into().unwrap(),
name,
value.into(),
validity,
);
attr.send().await?.await?;

let tx = context.registry.revoke_attribute(me, name, value.into()).tx;
let signature = context.signer.sign_transaction(&tx, me).await.unwrap();
client
.revoke_installation(
format!("0x{}", hex::encode(me)),
XmtpAttributeType::InstallationKey,
value.to_vec(),
signature,
)
.await?;

let doc = resolver.resolve_did(me, None).await.unwrap().document;
println!("{}", serde_json::to_string_pretty(&doc).unwrap());
Ok(())
})
.await
}
}

async fn with_xps_client<F, R, T>(timeout: Option<Duration>, f: F) -> Result<T, Error>
where
F: FnOnce(WsClient) -> R + 'static + Send,
F: FnOnce(WsClient, GatewayContext, Resolver<Arc<GatewaySigner>>, &AnvilInstance) -> R
+ 'static
+ Send,
R: Future<Output = Result<T, Error>> + FutureExt + Send + 'static,
{
let anvil = Anvil::new().args(vec!["--base-fee", "100"]).spawn();
log::debug!("Anvil spawned at {}", anvil.ws_endpoint());
let registry_address = deploy_to_anvil(&anvil).await;
log::debug!("Contract deployed at {}", registry_address);

let server = Server::builder().build(SERVER_HOST).await.unwrap();
let addr = server.local_addr().unwrap();
let handle = server.start(XpsMethods::new().into_rpc());
let context = GatewayContext::new(anvil.ws_endpoint()).await?;
let resolver = Resolver::new(context.signer.clone(), registry_address)
.await
.unwrap();

let handle = server.start(XpsMethods::new(&context).into_rpc());
let client = WsClientBuilder::default()
.build(&format!("ws://{addr}"))
.await
.unwrap();
let result = timeout_tokio(timeout.unwrap_or(TEST_TIMEOUT), f(client)).await;

let result = timeout_tokio(
timeout.unwrap_or(TEST_TIMEOUT),
f(client, context, resolver, &anvil),
)
.await;

handle.stop().unwrap();
handle.stopped().await;
Expand All @@ -66,3 +141,31 @@ where
Err(_) => panic!("Test timed out"),
}
}

async fn deploy_to_anvil(anvil: &AnvilInstance) -> Address {
let wallet: LocalWallet = anvil.keys()[0].clone().into();
let client = client(&anvil, wallet).await;

let registry = DIDRegistry::deploy(client.clone(), ())
.unwrap()
.gas_price(100)
.send()
.await
.unwrap();

registry.address()
}

async fn client(
anvil: &AnvilInstance,
wallet: LocalWallet,
) -> Arc<SignerMiddleware<Provider<Ws>, LocalWallet>> {
let provider = Provider::<Ws>::connect(anvil.ws_endpoint())
.await
.unwrap()
.interval(std::time::Duration::from_millis(10u64));
Arc::new(SignerMiddleware::new(
provider,
wallet.with_chain_id(anvil.chain_id()),
))
}

0 comments on commit fbc885d

Please sign in to comment.