diff --git a/Cargo.lock b/Cargo.lock index 30a4acb..6ed6bc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -247,9 +247,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5189fa9a8797e92396bc4b4454c5f2073a4945f7c2b366af9af60f9536558f7a" +checksum = "8b26fdd571915bafe857fccba4ee1a4f352965800e46a53e4a5f50187b7776fa" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -312,9 +312,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b98b99c1dcfbe74d7f0b31433ff215e7d1555e367d90e62db904f3c9d4ff53" +checksum = "a326d47106039f38b811057215a92139f46eef7983a4b77b10930a0ea5685b1e" dependencies = [ "alloy-rlp", "bytes", @@ -611,9 +611,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60fcfa26956bcb22f66ab13407115197f26ef23abca5b48d39a1946897382d74" +checksum = "d4be1ce1274ddd7fdfac86e5ece1b225e9bba1f2327e20fbb30ee6b9cc1423fe" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -625,9 +625,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a9b402f0013f1ff8c24066eeafc2207a8e52810a2b18b77776ce7fead5af41" +checksum = "01e92f3708ea4e0d9139001c86c051c538af0146944a2a9c7181753bd944bf57" dependencies = [ "alloy-json-abi", "alloy-sol-macro-input", @@ -644,9 +644,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d02d61741337bb6b3f4899c2e3173fe17ffa2810e143d3b28acd953197c8dd79" +checksum = "9afe1bd348a41f8c9b4b54dfb314886786d6201235b0b3f47198b9d910c86bb2" dependencies = [ "alloy-json-abi", "const-hex", @@ -662,9 +662,9 @@ dependencies = [ [[package]] name = "alloy-sol-type-parser" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b5f5f9f561c29f78ea521ebe2e5ac1633f1b1442dae582f68ecd57c6350042" +checksum = "d6195df2acd42df92a380a8db6205a5c7b41282d0ce3f4c665ecf7911ac292f1" dependencies = [ "serde", "winnow", @@ -672,14 +672,13 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02635bce18205ff8149fb752c753b0a91ea3f3c8ee04c58846448be4811a640" +checksum = "6185e98a79cf19010722f48a74b5a65d153631d2f038cabd250f4b9e9813b8ad" dependencies = [ "alloy-json-abi", "alloy-primitives", "alloy-sol-macro", - "const-hex", "serde", ] @@ -4435,6 +4434,7 @@ dependencies = [ "tracing", "tracing-subscriber 0.3.19", "tracing-test", + "url", ] [[package]] @@ -4495,9 +4495,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34c9c96de1f835488c1501092847b522be88c9ac6fb0d4c0fbea92992324c8f4" +checksum = "14c8c8f496c33dc6343dac05b4be8d9e0bca180a4caa81d7b8416b10cc2273cd" dependencies = [ "paste", "proc-macro2", diff --git a/prover/Cargo.toml b/prover/Cargo.toml index 6b659c9..b8b9c2a 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -13,7 +13,8 @@ tokio = { version = "1", features = ["macros", "rt-multi-thread"] } tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } tracing = "0.1.41" tracing-test = "0.2.5" -alloy = { version = "0.15", features = ["full", "getrandom"] } +alloy = { version = "0.15", features = ["full", "getrandom", "sol-types", "contract"] } +# alloy-sol-types = "1.2.0" thiserror = "2.0" futures = "0.3" rln = { git = "https://github.com/vacp2p/zerokit" } @@ -30,6 +31,7 @@ http = "*" async-channel = "2.3.1" rand = "0.8.5" derive_more = "2.0.1" +url = "2.5" [build-dependencies] tonic-build = "*" diff --git a/prover/src/args.rs b/prover/src/args.rs index 73de4ba..e8a1dd6 100644 --- a/prover/src/args.rs +++ b/prover/src/args.rs @@ -1,6 +1,8 @@ use std::net::IpAddr; // third-party use clap::Parser; +use url::Url; +use alloy::primitives::Address; #[derive(Debug, Clone, Parser)] #[command(about = "RLN prover service", long_about = None)] @@ -16,8 +18,15 @@ pub struct AppArgs { pub(crate) port: u16, #[arg( short = 'r', - long = "rpc_url", + long = "ws_rpc_url", help = "Websocket rpc url (e.g. wss://eth-mainnet.g.alchemy.com/v2/your-api-key)" )] - pub(crate) rpc_url: String, + pub(crate) ws_rpc_url: Url, + #[arg( + short = 'k', + long = "ksc", + help = "Karma smart contract address" + )] + pub(crate) ksc_address: Address, + } diff --git a/prover/src/epoch_service.rs b/prover/src/epoch_service.rs index 6145858..98b2f73 100644 --- a/prover/src/epoch_service.rs +++ b/prover/src/epoch_service.rs @@ -494,7 +494,7 @@ mod tests { debug!("[Notified] Epoch update..."); let _v = counter.fetch_add(1, Ordering::SeqCst); } - Ok::<(), AppErrorExt>(()) + // Ok::<(), AppErrorExt>(()) } ) .map_err(|_e| AppErrorExt::Elapsed) diff --git a/prover/src/error.rs b/prover/src/error.rs index e4e9363..40c1073 100644 --- a/prover/src/error.rs +++ b/prover/src/error.rs @@ -18,6 +18,8 @@ pub enum AppError { Alloy2(#[from] RpcError), #[error("Epoch service error: {0}")] EpochError(#[from] WaitUntilError), + #[error(transparent)] + RegistryError(#[from] HandleTransferError), } /* @@ -89,3 +91,11 @@ pub enum GetMerkleTreeProofError { #[error("Merkle tree error: {0}")] TreeError(String), } + +#[derive(thiserror::Error, Debug)] +pub enum HandleTransferError { + #[error(transparent)] + Register(#[from] RegisterError), + #[error("Unable to query balance: {0}")] + BalanceOf(#[from] alloy::contract::Error) +} diff --git a/prover/src/grpc_service.rs b/prover/src/grpc_service.rs index 83d7722..f12da62 100644 --- a/prover/src/grpc_service.rs +++ b/prover/src/grpc_service.rs @@ -16,11 +16,12 @@ use tonic::{ use tonic_web::GrpcWebLayer; use tower_http::cors::{Any, CorsLayer}; use tracing::debug; +use url::Url; // internal use crate::error::{AppError, ProofGenerationStringError, RegisterError}; use crate::proof_generation::{ProofGenerationData, ProofSendingData}; use crate::tier::{KarmaAmount, TierLimit, TierName}; -use crate::user_db_service::{KarmaAmountExt, UserDb, UserTierInfo}; +use crate::user_db_service::{UserDb, UserTierInfo}; use rln_proof::RlnIdentifier; pub mod prover_proto { @@ -40,6 +41,8 @@ use prover_proto::{ rln_proof_reply::Resp as GetProofsResp, rln_prover_server::{RlnProver, RlnProverServer}, }; +use crate::registry_listener::{AlloyWsProvider}; +use crate::registry_listener::KarmaSC::KarmaSCInstance; const PROVER_SERVICE_LIMIT_PER_CONNECTION: usize = 16; // Timeout for all handlers of a request @@ -62,6 +65,7 @@ pub struct ProverService { broadcast::Sender>, broadcast::Receiver>, ), + karma_sc: KarmaSCInstance } #[tonic::async_trait] @@ -200,16 +204,11 @@ impl RlnProver for ProverService { } else { return Err(Status::invalid_argument("No user address")); }; - - // TODO: SC call - struct MockKarmaSc {} - - impl KarmaAmountExt for MockKarmaSc { - async fn karma_amount(&self, _address: &Address) -> U256 { - U256::from(10) - } - } - let tier_info = self.user_db.user_tier_info(&user, MockKarmaSc {}).await; + + let tier_info = self.user_db.user_tier_info::>( + &user, + &self.karma_sc + ).await; match tier_info { Ok(tier_info) => Ok(Response::new(GetUserTierInfoReply { @@ -271,10 +270,16 @@ pub(crate) struct GrpcProverService { pub addr: SocketAddr, pub rln_identifier: RlnIdentifier, pub user_db: UserDb, + pub karma_sc_info: (Url, Address), } impl GrpcProverService { pub(crate) async fn serve(&self) -> Result<(), AppError> { + + let karma_sc = KarmaSCInstance::try_new( + self.karma_sc_info.0.clone(), self.karma_sc_info.1) + .await?; + let prover_service = ProverService { proof_sender: self.proof_sender.clone(), user_db: self.user_db.clone(), @@ -283,6 +288,7 @@ impl GrpcProverService { self.broadcast_channel.0.clone(), self.broadcast_channel.0.subscribe(), ), + karma_sc, }; let reflection_service = tonic_reflection::server::Builder::configure() @@ -356,8 +362,8 @@ impl From for UserTierInfoResult { } /// UserTierInfoError to UserTierInfoError (Grpc message) conversion -impl From for UserTierInfoError { - fn from(value: crate::user_db_service::UserTierInfoError) -> Self { +impl From> for UserTierInfoError where E: std::error::Error { + fn from(value: crate::user_db_service::UserTierInfoError) -> Self { UserTierInfoError { message: value.to_string(), } diff --git a/prover/src/main.rs b/prover/src/main.rs index 2db3690..9b39403 100644 --- a/prover/src/main.rs +++ b/prover/src/main.rs @@ -15,6 +15,7 @@ use std::time::Duration; // third-party use chrono::{DateTime, Utc}; use clap::Parser; +use alloy::primitives::U256; use rln_proof::RlnIdentifier; use tokio::task::JoinSet; use tracing::level_filters::LevelFilter; @@ -29,15 +30,19 @@ use crate::args::AppArgs; use crate::epoch_service::EpochService; use crate::grpc_service::GrpcProverService; use crate::proof_service::ProofService; +use crate::registry_listener::{RegistryListener}; use crate::user_db_service::{RateLimit, UserDbService}; const RLN_IDENTIFIER_NAME: &[u8] = b"test-rln-identifier"; const PROVER_SPAM_LIMIT: RateLimit = RateLimit::new(10_000u64); const PROOF_SERVICE_COUNT: u8 = 8; const GENESIS: DateTime = DateTime::from_timestamp(1431648000, 0).unwrap(); +const PROVER_MINIMAL_AMOUNT_FOR_REGISTRATION: U256 = U256::from_le_slice(10u64.to_le_bytes().as_slice()); + #[tokio::main] async fn main() -> Result<(), Box> { + let filter = EnvFilter::builder() .with_default_directive(LevelFilter::INFO.into()) .from_env_lossy(); @@ -49,13 +54,6 @@ async fn main() -> Result<(), Box> { let app_args = AppArgs::parse(); debug!("Arguments: {:?}", app_args); - // Smart contract - - // let uniswap_token_address = address!("1f9840a85d5aF5bf1D1762F925BDADdC4201F984"); - // let event = "Transfer(address,address,uint256)"; - // let registry_listener = - // RegistryListener::new(app_args.rpc_url.as_str(), uniswap_token_address, event); - // Epoch let epoch_service = EpochService::try_from((Duration::from_secs(60 * 2), GENESIS)) .expect("Failed to create epoch service"); @@ -67,6 +65,12 @@ async fn main() -> Result<(), Box> { PROVER_SPAM_LIMIT, ); + // Smart contract + + // let karma_sc_address = address!("1f9840a85d5aF5bf1D1762F925BDADdC4201F984"); + let registry_listener = + RegistryListener::new(app_args.ws_rpc_url.as_str(), app_args.ksc_address, user_db_service.get_user_db(), PROVER_MINIMAL_AMOUNT_FOR_REGISTRATION); + // proof service // FIXME: bound let (tx, rx) = tokio::sync::broadcast::channel(2); @@ -85,6 +89,7 @@ async fn main() -> Result<(), Box> { addr, rln_identifier, user_db: user_db_service.get_user_db(), + karma_sc_info: (app_args.ws_rpc_url, app_args.ksc_address), }; let mut set = JoinSet::new(); @@ -105,7 +110,7 @@ async fn main() -> Result<(), Box> { proof_service.serve().await }); } - // set.spawn(async move { registry_listener.listen().await }); + set.spawn(async move { registry_listener.listen().await }); set.spawn(async move { epoch_service.listen_for_new_epoch().await }); set.spawn(async move { user_db_service.listen_for_epoch_changes().await }); set.spawn(async move { prover_grpc_service.serve().await }); diff --git a/prover/src/proof_service.rs b/prover/src/proof_service.rs index e098b4b..c27b2ec 100644 --- a/prover/src/proof_service.rs +++ b/prover/src/proof_service.rs @@ -150,7 +150,7 @@ mod tests { use tokio::sync::broadcast; use tracing::info; // third-party: zerokit - use rln::protocol::{compute_id_secret, deserialize_proof_values, keygen, verify_proof}; + use rln::protocol::{compute_id_secret, deserialize_proof_values, verify_proof}; // internal use crate::user_db_service::UserDbService; use rln_proof::RlnIdentifier; @@ -343,7 +343,7 @@ mod tests { broadcast_receiver: &mut broadcast::Receiver< Result, >, - verifying_key: &VerifyingKey, + // verifying_key: &VerifyingKey, ) -> Result<(), AppErrorExt> { // used by test_user_spamming unit test @@ -361,7 +361,7 @@ mod tests { let res = res.unwrap(); let res = res?; let mut proof_cursor = Cursor::new(&res.proof); - let proof: Proof = ArkProof::deserialize_compressed(&mut proof_cursor).unwrap(); + let _proof: Proof = ArkProof::deserialize_compressed(&mut proof_cursor).unwrap(); let position = proof_cursor.position() as usize; let proof_cursor_2 = &proof_cursor.get_ref().as_slice()[position..]; let (proof_values, _) = deserialize_proof_values(proof_cursor_2); @@ -471,14 +471,10 @@ mod tests { rate_limit, ); - // Verification - let proving_key = zkey_from_folder(); - let verification_key = &proving_key.0.vk; - info!("Starting..."); let res = tokio::try_join!( proof_service.serve().map_err(AppErrorExt::AppError), - proof_reveal_secret(&mut broadcast_receiver, verification_key), + proof_reveal_secret(&mut broadcast_receiver), proof_sender_2( &mut proof_tx, rln_identifier.clone(), @@ -537,14 +533,10 @@ mod tests { rate_limit, ); - // Verification - let proving_key = zkey_from_folder(); - let verification_key = &proving_key.0.vk; - info!("Starting..."); - let res = tokio::try_join!( + let _res = tokio::try_join!( proof_service.serve().map_err(AppErrorExt::AppError), - proof_reveal_secret(&mut broadcast_receiver, verification_key), + proof_reveal_secret(&mut broadcast_receiver), proof_sender_2( &mut proof_tx, rln_identifier.clone(), diff --git a/prover/src/registry_listener.rs b/prover/src/registry_listener.rs index bb0c632..9f2801d 100644 --- a/prover/src/registry_listener.rs +++ b/prover/src/registry_listener.rs @@ -1,15 +1,18 @@ -use crate::error::AppError; -use alloy::eips::BlockNumberOrTag; -use alloy::primitives::Address; +use crate::error::{AppError, HandleTransferError, RegisterError}; +use alloy::primitives::{Address, U256}; use alloy::providers::fillers::{ BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, }; use alloy::providers::{Identity, Provider, ProviderBuilder, RootProvider, WsConnect}; -use alloy::rpc::types::Filter; use alloy::transports::{RpcError, TransportError}; +use alloy::{sol, sol_types::SolEvent, contract::Error as AlloyContractError}; +use alloy::transports::http::reqwest::Url; use tonic::codegen::tokio_stream::StreamExt; +use tracing::{debug, error, info}; +use crate::registry_listener::KarmaSC::KarmaSCInstance; +use crate::user_db_service::{KarmaAmountExt, UserDb}; -type AlloyWsProvider = FillProvider< +pub type AlloyWsProvider = FillProvider< JoinFill< Identity, JoinFill>>, @@ -17,18 +20,46 @@ type AlloyWsProvider = FillProvider< RootProvider, >; +sol! { + #[sol(rpc)] + contract KarmaSC { + // From: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L16 + event Transfer(address indexed from, address indexed to, uint256 value); + + function balanceOf(address account) public view override returns (uint256); + } +} + +impl KarmaSCInstance { + pub(crate) async fn try_new(rpc_url: Url, address: Address) -> Result> { + let ws = WsConnect::new(rpc_url.as_str()); + let provider = ProviderBuilder::new().connect_ws(ws).await?; + Ok(KarmaSC::new(address, provider)) + } +} + + +impl KarmaAmountExt for KarmaSCInstance { + type Error = alloy::contract::Error; + async fn karma_amount(&self, address: &Address) -> Result { + self.balanceOf(*address).call().await + } +} + pub(crate) struct RegistryListener { rpc_url: String, sc_address: Address, - event: String, + user_db: UserDb, + minimal_amount: U256, } impl RegistryListener { - pub(crate) fn new(rpc_url: &str, sc_address: Address, event: &str) -> Self { + pub(crate) fn new(rpc_url: &str, sc_address: Address, user_db: UserDb, minimal_amount: U256) -> Self { Self { rpc_url: rpc_url.to_string(), sc_address, - event: event.to_string(), + user_db, + minimal_amount, } } @@ -41,24 +72,136 @@ impl RegistryListener { /// Listen to Smart Contract specified events pub(crate) async fn listen(&self) -> Result<(), AppError> { + let provider = self.setup_provider_ws().await.map_err(AppError::from)?; + let karma_sc = KarmaSC::new(self.sc_address, provider.clone()); - let filter = Filter::new() + let filter = alloy::rpc::types::Filter::new() .address(self.sc_address) - .event(self.event.as_str()) - .from_block(BlockNumberOrTag::Latest); + .event(KarmaSC::Transfer::SIGNATURE); - // Subscribe to logs. - let sub = provider - .subscribe_logs(&filter) - .await - .map_err(AppError::from)?; - let mut stream = sub.into_stream(); + // Subscribe to logs matching the filter. + let subscription = provider.subscribe_logs(&filter).await?; + let mut stream = subscription.into_stream(); + // Loop through the incoming event logs while let Some(log) = stream.next().await { - println!("Uniswap token logs: {log:?}"); + + match KarmaSC::Transfer::decode_log_data(log.data()) { + Ok(transfer_event) => { + + match self.handle_transfer_event(&karma_sc, transfer_event).await { + Ok(addr) => { + info!("Registered new user: {}", addr); + } + Err(HandleTransferError::Register(RegisterError::AlreadyRegistered(address))) => { + debug!("Already registered: {}", address); + } + Err(e) => { + error!("Unexpected error: {}", e); + // FIXME: return / continue? + return Err(AppError::RegistryError(e)); + } + }; + }, + Err(e) => { + eprintln!("Error decoding log data: {:?}", e); + // It's also useful to print the raw log data for debugging + eprintln!("Raw log topics: {:?}", log.topics()); + eprintln!("Raw log data: {:?}", log.data()); + } + } } Ok(()) } + + // async fn handle_transfer_event(&self, karma_sc: &KarmaSCInstance, transfer_event: KarmaSC::Transfer) -> Result<(), HandleTransferError> { + async fn handle_transfer_event, KSC: KarmaAmountExt>(&self, karma_sc: &KSC, transfer_event: KarmaSC::Transfer) -> Result { + + let from_address: Address = transfer_event.from; + let to_address: Address = transfer_event.to; + let amount: U256 = transfer_event.value; + + // This is a mint event if from_address is the zero address + if from_address == Address::default() { + + let should_register = { + if amount >= self.minimal_amount { + true + } else { + let balance = karma_sc.karma_amount(&to_address) + .await + .map_err(|e| HandleTransferError::BalanceOf(e.into()))?; + balance >= self.minimal_amount + } + }; + + if should_register { + self.user_db.on_new_user(to_address).map_err(HandleTransferError::Register)?; + } + } + + Ok(to_address) + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + use alloy::primitives::address; + use parking_lot::RwLock; + use crate::epoch_service::{Epoch, EpochSlice}; + // use crate::tier::TIER_LIMITS; + use crate::user_db_service::{UserDbService}; + use super::*; + + // const ADDR_1: Address = address!("0xd8da6bf26964af9d7eed9e03e53415d37aa96045"); + const ADDR_2: Address = address!("0xb20a608c624Ca5003905aA834De7156C68b2E1d0"); + struct MockKarmaSc {} + + impl KarmaAmountExt for MockKarmaSc { + + type Error = AlloyContractError; + async fn karma_amount(&self, _address: &Address) -> Result { + Ok(U256::from(10)) + } + } + + #[tokio::test] + async fn test_handle_transfer_event() { + + let epoch = Epoch::from(11); + let epoch_slice = EpochSlice::from(42); + let epoch_store = Arc::new(RwLock::new((epoch, epoch_slice))); + let user_db_service = UserDbService::new(Default::default(), epoch_store, 10.into()); + let user_db = user_db_service.get_user_db(); + + assert!( + user_db_service.get_user_db().get_user(&ADDR_2).is_none() + ); + + let minimal_amount = U256::from(25); + let registry = RegistryListener { + rpc_url: "".to_string(), + sc_address: Default::default(), + user_db, + minimal_amount: U256::from(25), + }; + + let transfer = KarmaSC::Transfer { + from: Address::default(), + to: ADDR_2, + value: minimal_amount, + }; + + let karma_sc = MockKarmaSc {}; + registry.handle_transfer_event(&karma_sc, transfer) + .await + .unwrap(); + + assert!( + user_db_service.get_user_db().get_user(&ADDR_2).is_some() + ); + } } diff --git a/prover/src/user_db_service.rs b/prover/src/user_db_service.rs index 44f0945..88fa13d 100644 --- a/prover/src/user_db_service.rs +++ b/prover/src/user_db_service.rs @@ -177,13 +177,18 @@ pub struct UserTierInfo { } #[derive(Debug, thiserror::Error)] -pub enum UserTierInfoError { +pub enum UserTierInfoError { #[error("User {0} not registered")] NotRegistered(Address), + #[error(transparent)] + Contract(E) } pub trait KarmaAmountExt { - async fn karma_amount(&self, address: &Address) -> U256; + + type Error; + + async fn karma_amount(&self, address: &Address) -> Result; } /// User registration + tx counters + tier limits storage @@ -280,11 +285,11 @@ impl UserDb { } /// Get user tier info - pub(crate) async fn user_tier_info( + pub(crate) async fn user_tier_info>( &self, address: &Address, - karma_sc: KSC, - ) -> Result { + karma_sc: &KSC, + ) -> Result> { if self.user_registry.has_user(address) { let (epoch_tx_count, epoch_slice_tx_count) = self .tx_registry @@ -292,7 +297,8 @@ impl UserDb { .map(|ref_v| (ref_v.0, ref_v.1)) .unwrap_or_default(); - let karma_amount = karma_sc.karma_amount(address).await; + let karma_amount = karma_sc.karma_amount(address).await + .map_err(|e| UserTierInfoError::Contract(e))?; let guard = self.tier_limits.read(); let range_res = guard.range(( Included(&KarmaAmount::ZERO), @@ -409,12 +415,19 @@ mod tests { use super::*; use alloy::primitives::address; use claims::{assert_err, assert_matches}; + use derive_more::Display; + #[derive(Debug, Display, thiserror::Error)] + struct DummyError(); + struct MockKarmaSc {} impl KarmaAmountExt for MockKarmaSc { - async fn karma_amount(&self, _address: &Address) -> U256 { - U256::from(10) + + type Error = DummyError; + + async fn karma_amount(&self, _address: &Address) -> Result { + Ok(U256::from(10)) } } @@ -424,13 +437,16 @@ mod tests { struct MockKarmaSc2 {} impl KarmaAmountExt for MockKarmaSc2 { - async fn karma_amount(&self, address: &Address) -> U256 { + + type Error = DummyError; + + async fn karma_amount(&self, address: &Address) -> Result { if address == &ADDR_1 { - U256::from(10) + Ok(U256::from(10)) } else if address == &ADDR_2 { - U256::from(2000) + Ok(U256::from(2000)) } else { - U256::ZERO + Ok(U256::ZERO) } } } @@ -465,7 +481,7 @@ mod tests { // Try to update tx counter without registering first assert_eq!(user_db.on_new_tx(&addr), None); - let tier_info = user_db.user_tier_info(&addr, MockKarmaSc {}).await; + let tier_info = user_db.user_tier_info(&addr, &MockKarmaSc {}).await; // User is not registered -> no tier info assert!(matches!( tier_info, @@ -475,7 +491,7 @@ mod tests { user_db.user_registry.register(addr).unwrap(); // Now update user tx counter assert_eq!(user_db.on_new_tx(&addr), Some(EpochSliceCounter(1))); - let tier_info = user_db.user_tier_info(&addr, MockKarmaSc {}).await.unwrap(); + let tier_info = user_db.user_tier_info(&addr, &MockKarmaSc {}).await.unwrap(); assert_eq!(tier_info.epoch_tx_count, 1); assert_eq!(tier_info.epoch_slice_tx_count, 1); } @@ -510,7 +526,7 @@ mod tests { new_epoch_slice, ); let addr_1_tier_info = user_db - .user_tier_info(&ADDR_1, MockKarmaSc2 {}) + .user_tier_info(&ADDR_1, &MockKarmaSc2 {}) .await .unwrap(); assert_eq!(addr_1_tier_info.epoch_tx_count, addr_1_tx_count); @@ -518,7 +534,7 @@ mod tests { assert_eq!(addr_1_tier_info.tier_name, Some(TierName::from("Basic"))); let addr_2_tier_info = user_db - .user_tier_info(&ADDR_2, MockKarmaSc2 {}) + .user_tier_info(&ADDR_2, &MockKarmaSc2 {}) .await .unwrap(); assert_eq!(addr_2_tier_info.epoch_tx_count, addr_2_tx_count); @@ -540,7 +556,7 @@ mod tests { new_epoch_slice, ); let addr_1_tier_info = user_db - .user_tier_info(&ADDR_1, MockKarmaSc2 {}) + .user_tier_info(&ADDR_1, &MockKarmaSc2 {}) .await .unwrap(); assert_eq!(addr_1_tier_info.epoch_tx_count, 0); @@ -548,7 +564,7 @@ mod tests { assert_eq!(addr_1_tier_info.tier_name, Some(TierName::from("Basic"))); let addr_2_tier_info = user_db - .user_tier_info(&ADDR_2, MockKarmaSc2 {}) + .user_tier_info(&ADDR_2, &MockKarmaSc2 {}) .await .unwrap(); assert_eq!(addr_2_tier_info.epoch_tx_count, 0); diff --git a/rln_proof/src/proof.rs b/rln_proof/src/proof.rs index 3825133..1d25c78 100644 --- a/rln_proof/src/proof.rs +++ b/rln_proof/src/proof.rs @@ -7,9 +7,8 @@ use ark_relations::r1cs::ConstraintMatrices; use rln::circuit::ZKEY_BYTES; use rln::circuit::zkey::read_zkey; use rln::hashers::{hash_to_field, poseidon_hash}; -use rln::pm_tree_adapter::PmTree; use rln::protocol::{ - ProofError, RLNProofValues, compute_id_secret, generate_proof, keygen, + ProofError, RLNProofValues, generate_proof, proof_values_from_witness, rln_witness_from_values, }; @@ -96,6 +95,13 @@ pub fn compute_rln_proof_and_values( mod tests { use super::*; use zerokit_utils::ZerokitMerkleTree; + use rln::{ + protocol::{ + keygen, + compute_id_secret + }, + pm_tree_adapter::PmTree, + }; #[test] fn test_recover_secret_hash() {