From 66af43628919951ac7ce1f4f7518bb227afff832 Mon Sep 17 00:00:00 2001 From: Andrew Plaza Date: Tue, 13 Feb 2024 17:51:37 -0500 Subject: [PATCH] Some bugs during demo development (#66) --- .github/workflows/coverage.yml | 2 +- Cargo.lock | 33 +++++++++ Cargo.toml | 2 +- bin/registry-localnet/Cargo.toml | 14 ++++ bin/registry-localnet/src/main.rs | 97 +++++++++++++++++++++++++++ lib-xps/src/lib.rs | 6 +- lib-xps/src/rpc/methods.rs | 15 +++-- lib-xps/tests/integration_test.rs | 74 ++++++++++---------- lib-xps/tests/integration_util/mod.rs | 13 +++- registry/src/lib.rs | 24 ++++++- xps-types/src/lib.rs | 9 +-- xps/src/main.rs | 17 ++++- 12 files changed, 249 insertions(+), 57 deletions(-) create mode 100644 bin/registry-localnet/Cargo.toml create mode 100644 bin/registry-localnet/src/main.rs diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 94aacb2..95178b1 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -16,7 +16,7 @@ jobs: - name: Install cargo-llvm-cov run: curl -LsSf https://github.com/taiki-e/cargo-llvm-cov/releases/latest/download/cargo-llvm-cov-x86_64-unknown-linux-gnu.tar.gz | tar xzf - -C ~/.cargo/bin - name: Generate code coverage - run: RUST_LOG=xps_gateway=info,registry=info,inbox=info,messaging=info,gateway_types=info cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info + run: RUST_LOG=xps_gateway=info,registry=info,inbox=info,messaging=info,gateway_types=info cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info --exclude registry-localnet - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: diff --git a/Cargo.lock b/Cargo.lock index 26a09ab..5fa17b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,6 +660,16 @@ dependencies = [ "cipher", ] +[[package]] +name = "ctrlc" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b" +dependencies = [ + "nix", + "windows-sys 0.52.0", +] + [[package]] name = "data-encoding" version = "2.5.0" @@ -2296,6 +2306,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.4.2", + "cfg-if", + "libc", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2946,6 +2967,18 @@ dependencies = [ "xps-types", ] +[[package]] +name = "registry-localnet" +version = "0.1.0" +dependencies = [ + "anyhow", + "ctrlc", + "ethers", + "hex", + "lib-didethresolver", + "tokio", +] + [[package]] name = "reqwest" version = "0.11.24" diff --git a/Cargo.toml b/Cargo.toml index 52c9eab..93a50f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ members = [ "messaging", "inbox", "registry", - "xps-types", + "xps-types", "bin/registry-localnet", ] exclude = [] diff --git a/bin/registry-localnet/Cargo.toml b/bin/registry-localnet/Cargo.toml new file mode 100644 index 0000000..b72f6bd --- /dev/null +++ b/bin/registry-localnet/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "registry-localnet" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ethers.workspace = true +anyhow.workspace = true +tokio.workspace = true +ctrlc = "3.4.2" +lib-didethresolver.workspace = true +hex.workspace = true diff --git a/bin/registry-localnet/src/main.rs b/bin/registry-localnet/src/main.rs new file mode 100644 index 0000000..825fdcc --- /dev/null +++ b/bin/registry-localnet/src/main.rs @@ -0,0 +1,97 @@ +use anyhow::Error; +use ethers::{ + abi::Address, + core::utils::Anvil, + middleware::SignerMiddleware, + providers::{Provider, Ws}, + signers::{LocalWallet, Signer as _}, + utils::AnvilInstance, +}; +use lib_didethresolver::did_registry::DIDRegistry; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; + +#[tokio::main] +async fn main() -> Result<(), Error> { + let running = Arc::new(AtomicBool::new(true)); + let r = running.clone(); + + ctrlc::set_handler(move || { + r.store(false, Ordering::SeqCst); + }) + .expect("Error setting Ctrl-C handler"); + + let anvil = deploy().await?; + + println!("Waiting for Ctrl-C..."); + while running.load(Ordering::SeqCst) {} + drop(anvil); + println!("Shutting down..."); + Ok(()) +} + +async fn deploy() -> Result { + let anvil = Anvil::new() + .port(8545_u16) + .args(vec![ + "--base-fee", + "35", + "--gas-price", + "50", + "--disable-block-gas-limit", + ]) + .spawn(); + let registry_address = deploy_to_anvil(&anvil).await?; + println!( + "Registry deployed at {}, at endpoint {}", + hex::encode(registry_address), + anvil.ws_endpoint() + ); + + println!("Chain ID: {}", anvil.chain_id()); + println!("Endpoint: {}", anvil.endpoint()); + println!("WS Endpoint: {}", anvil.ws_endpoint()); + + println!("\n\n"); + println!("Private Keys -------------------------------------"); + for key in anvil.keys() { + println!("0x{}", hex::encode(key.to_bytes())); + } + println!("\n\n"); + println!("Addresses -------------------------------------"); + for address in anvil.addresses() { + println!("0x{}", hex::encode(address)); + } + + Ok(anvil) +} + +async fn deploy_to_anvil(anvil: &AnvilInstance) -> Result { + println!("Deploying Registry to local anvil"); + + 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(); + + Ok(registry.address()) +} + +async fn client( + anvil: &AnvilInstance, + wallet: LocalWallet, +) -> Arc, LocalWallet>> { + let provider = Provider::::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()), + )) +} diff --git a/lib-xps/src/lib.rs b/lib-xps/src/lib.rs index 3fd478e..1cde25c 100644 --- a/lib-xps/src/lib.rs +++ b/lib-xps/src/lib.rs @@ -15,7 +15,7 @@ pub use crate::rpc::{XpsClient, XpsMethods, XpsServer}; use crate::types::GatewayContext; /// Entrypoint for the xps Gateway -pub async fn run(host: String, port: u16) -> Result<()> { +pub async fn run>(host: String, port: u16, provider: P) -> Result<()> { crate::util::init_logging(); let server_addr = format!("{}:{}", host, port); @@ -26,9 +26,7 @@ pub async fn run(host: String, port: u16) -> Result<()> { let registry_contract = Address::from_str(DID_ETH_REGISTRY)?; let conversation_contract = Address::from_str(CONVERSATION)?; - let provider = Provider::::connect("wss://ethereum-sepolia.publicnode.com") - .await - .unwrap(); + let provider = Provider::::connect(provider.as_ref()).await.unwrap(); let context = GatewayContext::new(registry_contract, conversation_contract, provider).await?; let xps_methods = rpc::XpsMethods::new(&context); diff --git a/lib-xps/src/rpc/methods.rs b/lib-xps/src/rpc/methods.rs index 89aa19e..efab4a6 100644 --- a/lib-xps/src/rpc/methods.rs +++ b/lib-xps/src/rpc/methods.rs @@ -13,7 +13,6 @@ use ethers::{ use jsonrpsee::types::ErrorObjectOwned; use lib_didethresolver::types::XmtpAttribute; use messaging::MessagingOperations; -use rand::{rngs::StdRng, SeedableRng}; use std::sync::Arc; use thiserror::Error; use xps_types::{ @@ -31,7 +30,6 @@ pub const DEFAULT_ATTRIBUTE_VALIDITY: u64 = 60 * 60 * 24 * 365; pub struct XpsMethods { message_operations: MessagingOperations>, contact_operations: ContactOperations>, - pub wallet: LocalWallet, pub signer: Arc>, } @@ -40,7 +38,6 @@ impl XpsMethods

{ Self { message_operations: MessagingOperations::new(context.conversation.clone()), contact_operations: ContactOperations::new(context.registry.clone()), - wallet: LocalWallet::new(&mut StdRng::from_entropy()), signer: context.signer.clone(), } } @@ -81,8 +78,10 @@ impl XpsServer for XpsMethods

{ signature, U256::from(DEFAULT_ATTRIBUTE_VALIDITY), ) - .await - .map_err(RpcError::from)?; + .await; + + log::debug!("{:?}", result); + let result = result.map_err(RpcError::from)?; Ok(result) } @@ -104,7 +103,8 @@ impl XpsServer for XpsMethods

{ } async fn wallet_address(&self) -> Result { - Ok(self.wallet.address()) + log::debug!("xps_walletAddress called"); + Ok(self.signer.signer().address()) } /// Fetches the current balance of the wallet in Ether. @@ -120,11 +120,12 @@ impl XpsServer for XpsMethods

{ /// balance could not be fetched or converted. /// async fn balance(&self) -> Result { + log::debug!("xps_balance called"); // Fetch the balance in wei (the smallest unit of Ether) from the blockchain. let wei_balance: U256 = self .signer .provider() - .get_balance(self.wallet.address(), None) + .get_balance(self.signer.signer().address(), None) .await .map_err::, _>(RpcError::from)?; diff --git a/lib-xps/tests/integration_test.rs b/lib-xps/tests/integration_test.rs index 79f1d56..3ab3dd0 100644 --- a/lib-xps/tests/integration_test.rs +++ b/lib-xps/tests/integration_test.rs @@ -20,7 +20,7 @@ use xps_types::{Message, Status, Unit}; #[tokio::test] async fn test_say_hello() -> Result<(), Error> { - with_xps_client(None, |client, _, _, _| async move { + with_xps_client(None, None, |client, _, _, _| async move { let result = client.status().await?; assert_eq!(result, "OK"); Ok(()) @@ -30,7 +30,7 @@ async fn test_say_hello() -> Result<(), Error> { #[tokio::test] async fn test_send_message() -> Result<(), Error> { - with_xps_client(None, |client, context, _resolver, anvil| async move { + with_xps_client(None, None, |client, context, _resolver, anvil| async move { let wallet: LocalWallet = anvil.keys()[3].clone().into(); let me = get_user(&anvil, 3).await; @@ -70,7 +70,7 @@ async fn test_send_message() -> Result<(), Error> { #[tokio::test] async fn test_send_message_fail() -> Result<(), Error> { - with_xps_client(None, |client, context, _resolver, anvil| async move { + with_xps_client(None, None, |client, context, _resolver, anvil| async move { let wallet: LocalWallet = anvil.keys()[3].clone().into(); let me = get_user(&anvil, 3).await; @@ -110,7 +110,7 @@ async fn test_send_message_fail() -> Result<(), Error> { #[tokio::test] async fn test_wallet_address() -> Result<(), Error> { - with_xps_client(None, |client, _, _, _| async move { + with_xps_client(None, None, |client, _, _, _| async move { let result = client.wallet_address().await?; assert_ne!(result, Address::zero()); Ok(()) @@ -120,7 +120,7 @@ async fn test_wallet_address() -> Result<(), Error> { #[tokio::test] async fn test_grant_revoke() -> Result<(), Error> { - with_xps_client(None, |client, context, resolver, anvil| async move { + with_xps_client(None, None, |client, context, resolver, anvil| async move { for (key_index, key) in anvil.keys().iter().enumerate() { let wallet: LocalWallet = key.clone().into(); let me = get_user(&anvil, key_index).await; @@ -211,7 +211,7 @@ async fn test_grant_revoke() -> Result<(), Error> { #[tokio::test] async fn test_grant_installation() -> Result<(), Error> { - with_xps_client(None, |client, context, resolver, anvil| async move { + with_xps_client(None, None, |client, context, resolver, anvil| async move { let keys = anvil.keys(); let wallet: LocalWallet = keys[3].clone().into(); let me = get_user(&anvil, 3).await; @@ -331,7 +331,7 @@ async fn test_grant_installation() -> Result<(), Error> { #[tokio::test] async fn test_revoke_installation() -> Result<(), Error> { - with_xps_client(None, |client, context, resolver, anvil| async move { + with_xps_client(None, None, |client, context, resolver, anvil| async move { let me: LocalWallet = anvil.keys()[3].clone().into(); let name = *b"xmtp/installation/hex "; let value = b"02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71"; @@ -393,37 +393,41 @@ async fn test_revoke_installation() -> Result<(), Error> { #[tokio::test] async fn test_balance() -> Result<(), Error> { - with_xps_client(None, |client, context, _resolver, _anvil| async move { - // by default, we have no balance. verify that. - let mut balance = client.balance().await?; - assert_eq!(balance.balance, U256::from(0)); - assert_eq!(balance.unit, Unit::Eth); - - // fund the wallet account. - let accounts = context.signer.get_accounts().await?; - let from = accounts[1]; - let tx = TransactionRequest::new() - .to(client.wallet_address().await?) - .value(5_000_000_000_000_000_000_000_u128) - .from(from); - context.signer.send_transaction(tx, None).await?.await?; - - // check to see if the balance gets updated. - balance = client.balance().await?; - assert_eq!( - balance.balance, - U256::from(5_000_000_000_000_000_000_000_u128) - ); - assert_eq!(balance.unit, Unit::Eth); + with_xps_client( + None, + Some(0.into()), + |client, context, _resolver, _anvil| async move { + // by default, we have no balance. verify that. + let mut balance = client.balance().await?; + assert_eq!(balance.balance, U256::from(0)); + assert_eq!(balance.unit, Unit::Eth); + + // fund the wallet account. + let accounts = context.signer.get_accounts().await?; + let from = accounts[1]; + let tx = TransactionRequest::new() + .to(client.wallet_address().await?) + .value(5_000_000_000_000_000_000_000_u128) + .from(from); + context.signer.send_transaction(tx, None).await?.await?; + + // check to see if the balance gets updated. + balance = client.balance().await?; + assert_eq!( + balance.balance, + U256::from(5_000_000_000_000_000_000_000_u128) + ); + assert_eq!(balance.unit, Unit::Eth); - Ok(()) - }) + Ok(()) + }, + ) .await } #[tokio::test] async fn test_fetch_key_packages() -> Result<(), Error> { - with_xps_client(None, |client, context, _, anvil| async move { + with_xps_client(None, None, |client, context, _, anvil| async move { let me: LocalWallet = anvil.keys()[3].clone().into(); let name = *b"xmtp/installation/hex "; let value = b"000000000000000000000000000000000000000000000000000000000000000000"; @@ -454,7 +458,7 @@ async fn test_fetch_key_packages() -> Result<(), Error> { #[tokio::test] async fn test_fetch_key_packages_revoke() -> Result<(), Error> { - with_xps_client(None, |client, context, _, anvil| async move { + with_xps_client(None, None, |client, context, _, anvil| async move { let me: LocalWallet = anvil.keys()[3].clone().into(); let name = *b"xmtp/installation/hex "; let value = b"000000000000000000000000000000000000000000000000000000000000000000"; @@ -497,7 +501,7 @@ async fn test_fetch_key_packages_revoke() -> Result<(), Error> { #[tokio::test] async fn test_fetch_key_packages_client() -> Result<(), Error> { - with_xps_client(None, |client, context, _, anvil| async move { + with_xps_client(None, None, |client, context, _, anvil| async move { let me: LocalWallet = anvil.keys()[3].clone().into(); let attribute = XmtpAttribute { purpose: XmtpKeyPurpose::Installation, @@ -540,7 +544,7 @@ async fn test_fetch_key_packages_client() -> Result<(), Error> { #[tokio::test] async fn test_did_deactivation() -> Result<(), Error> { - with_xps_client(None, |client, context, _, anvil| async move { + with_xps_client(None, None, |client, context, _, anvil| async move { let me: LocalWallet = anvil.keys()[3].clone().into(); let new_owner = Address::from_str(NULL_ADDRESS).unwrap(); diff --git a/lib-xps/tests/integration_util/mod.rs b/lib-xps/tests/integration_util/mod.rs index c418681..a374c82 100644 --- a/lib-xps/tests/integration_util/mod.rs +++ b/lib-xps/tests/integration_util/mod.rs @@ -36,7 +36,14 @@ use lib_xps::{ const TEST_TIMEOUT: Duration = Duration::from_secs(20); pub const SERVER_HOST: &str = "127.0.0.1"; -pub async fn with_xps_client(timeout: Option, f: F) -> Result +/// Run a test with an XPS client +/// If `with_balance` is provided, the gateway signer will be funded with the given balance +/// If `with_balance` is not provided, the gateway signer will be funded with 5_000_000_000_000_000_000_000 wei +pub async fn with_xps_client( + timeout: Option, + with_balance: Option, + f: F, +) -> Result where F: FnOnce( WsClient, @@ -61,17 +68,19 @@ where let context = GatewayContext::new(registry_address, conversation_address, provider).await?; + // transfer balance to the gateway signer so that we may be able to send & pay for transactions to anvil let accounts = context.signer.get_accounts().await?; let from = accounts[0]; let tx = TransactionRequest::new() .to(context.signer.address()) - .value(5_000_000_000_000_000_000_000_u128) + .value(with_balance.unwrap_or(U256::from(5_000_000_000_000_000_000_000_u128))) .from(from); context.signer.send_transaction(tx, None).await?.await?; let balance = context .signer .get_balance(context.signer.address(), None) .await?; + log::debug!("Gateway Balance is {}", balance); let resolver = Resolver::new(context.signer.clone(), registry_address) diff --git a/registry/src/lib.rs b/registry/src/lib.rs index 2744b0e..a41ce88 100644 --- a/registry/src/lib.rs +++ b/registry/src/lib.rs @@ -108,10 +108,20 @@ where .send() .await? .await?; + + if let Some(ref receipt) = transaction_receipt { + log::debug!( + "Gas Used by transaction {}, Gas used in block {}, effective_price {}", + receipt.gas_used.unwrap_or(0.into()), + receipt.cumulative_gas_used, + receipt.effective_gas_price.unwrap_or(0.into()) + ); + } + Ok(GrantInstallationResult { status: Status::Success, message: "Installation request complete.".to_string(), - transaction: transaction_receipt.unwrap().transaction_hash.to_string(), + transaction: transaction_receipt.map(|r| r.transaction_hash), }) } @@ -130,7 +140,8 @@ where String::from_utf8_lossy(&attribute) ); - self.registry + let transaction_receipt = self + .registry .revoke_attribute_signed( address, signature.v.try_into()?, @@ -143,6 +154,15 @@ where .await? .await?; + if let Some(ref receipt) = transaction_receipt { + log::debug!( + "Gas Used by transaction {}, Gas used in block {}, effective_price {}", + receipt.gas_used.unwrap_or(0.into()), + receipt.cumulative_gas_used, + receipt.effective_gas_price.unwrap_or(0.into()) + ); + } + Ok(()) } } diff --git a/xps-types/src/lib.rs b/xps-types/src/lib.rs index 952c578..f4307fb 100644 --- a/xps-types/src/lib.rs +++ b/xps-types/src/lib.rs @@ -2,8 +2,8 @@ pub mod error; -use ethers::types::U256; use ethers::types::{Address, Bytes as EthersBytes, Signature}; +use ethers::types::{H256, U256}; use ethers::utils::format_units; use std::fmt; @@ -11,8 +11,9 @@ use serde::{Deserialize, Serialize}; use std::fmt::Display; /// Address of the did:ethr Registry on Sepolia -pub const DID_ETH_REGISTRY: &str = "0xd1D374DDE031075157fDb64536eF5cC13Ae75000"; -// Address of the Converstion on Sepolia +// pub const DID_ETH_REGISTRY: &str = "0xd1D374DDE031075157fDb64536eF5cC13Ae75000"; +pub const DID_ETH_REGISTRY: &str = "0x5fbdb2315678afecb367f032d93f642f64180aa3"; +// Address of the Conversation on Sepolia pub const CONVERSATION: &str = "0x15aE865d0645816d8EEAB0b7496fdd24227d1801"; /// A message sent to a conversation @@ -49,7 +50,7 @@ pub type Bytes = Vec; pub struct GrantInstallationResult { pub status: Status, pub message: String, - pub transaction: String, + pub transaction: Option, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] diff --git a/xps/src/main.rs b/xps/src/main.rs index ebde1bc..ebbe998 100644 --- a/xps/src/main.rs +++ b/xps/src/main.rs @@ -9,12 +9,18 @@ struct Args { port: u16, #[arg(short = 's', long = "host", default_value = "127.0.0.1")] host: String, + #[arg( + short = 'e', + long = "endpoint", + default_value = "wss://ethereum-sepolia.publicnode.com" + )] + endpoint: String, } #[tokio::main] async fn main() -> Result<()> { let args = Args::parse(); - crate::run(args.host, args.port).await?; + crate::run(args.host, args.port, args.endpoint).await?; Ok(()) } @@ -60,6 +66,15 @@ mod tests { let args = Args::parse_from(arg_list); assert_eq!(args.port, 0); assert_eq!(args.host, "127.0.0.1"); + assert_eq!(args.endpoint, "wss://ethereum-sepolia.publicnode.com"); + Ok(()) + } + + #[test] + fn test_endpoint() -> Result<()> { + let arg_list = vec!["xps", "--endpoint", "http://localhost:8545"]; + let args = Args::parse_from(arg_list); + assert_eq!(args.endpoint, "http://localhost:8545"); Ok(()) } }