mirror of
https://github.com/vacp2p/status-rln-prover.git
synced 2026-01-08 05:03:54 -05:00
Update RegistryListener to interact with Karma smart contract (#4)
* Update RegistryListener to interact with Karma smart contract * Add karma sc instance in grpc service
This commit is contained in:
34
Cargo.lock
generated
34
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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 = "*"
|
||||
|
||||
@@ -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,
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -18,6 +18,8 @@ pub enum AppError {
|
||||
Alloy2(#[from] RpcError<TransportErrorKind>),
|
||||
#[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)
|
||||
}
|
||||
|
||||
@@ -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<Result<ProofSendingData, ProofGenerationStringError>>,
|
||||
broadcast::Receiver<Result<ProofSendingData, ProofGenerationStringError>>,
|
||||
),
|
||||
karma_sc: KarmaSCInstance<AlloyWsProvider>
|
||||
}
|
||||
|
||||
#[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::<alloy::contract::Error, KarmaSCInstance<AlloyWsProvider>>(
|
||||
&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<UserTierInfo> for UserTierInfoResult {
|
||||
}
|
||||
|
||||
/// UserTierInfoError to UserTierInfoError (Grpc message) conversion
|
||||
impl From<crate::user_db_service::UserTierInfoError> for UserTierInfoError {
|
||||
fn from(value: crate::user_db_service::UserTierInfoError) -> Self {
|
||||
impl<E> From<crate::user_db_service::UserTierInfoError<E>> for UserTierInfoError where E: std::error::Error {
|
||||
fn from(value: crate::user_db_service::UserTierInfoError<E>) -> Self {
|
||||
UserTierInfoError {
|
||||
message: value.to_string(),
|
||||
}
|
||||
|
||||
@@ -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<Utc> = 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<dyn std::error::Error>> {
|
||||
|
||||
let filter = EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
.from_env_lossy();
|
||||
@@ -49,13 +54,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
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<dyn std::error::Error>> {
|
||||
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<dyn std::error::Error>> {
|
||||
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<dyn std::error::Error>> {
|
||||
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 });
|
||||
|
||||
@@ -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<ProofSendingData, ProofGenerationStringError>,
|
||||
>,
|
||||
verifying_key: &VerifyingKey<Curve>,
|
||||
// verifying_key: &VerifyingKey<Curve>,
|
||||
) -> 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<Curve> = ArkProof::deserialize_compressed(&mut proof_cursor).unwrap();
|
||||
let _proof: Proof<Curve> = 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(),
|
||||
|
||||
@@ -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<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>,
|
||||
@@ -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<AlloyWsProvider> {
|
||||
pub(crate) async fn try_new(rpc_url: Url, address: Address) -> Result<Self, RpcError<TransportError>> {
|
||||
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<AlloyWsProvider> {
|
||||
type Error = alloy::contract::Error;
|
||||
async fn karma_amount(&self, address: &Address) -> Result<U256, Self::Error> {
|
||||
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<AlloyWsProvider>, transfer_event: KarmaSC::Transfer) -> Result<(), HandleTransferError> {
|
||||
async fn handle_transfer_event<E: Into<AlloyContractError>, KSC: KarmaAmountExt<Error = E>>(&self, karma_sc: &KSC, transfer_event: KarmaSC::Transfer) -> Result<Address, HandleTransferError> {
|
||||
|
||||
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<U256, Self::Error> {
|
||||
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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,13 +177,18 @@ pub struct UserTierInfo {
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum UserTierInfoError {
|
||||
pub enum UserTierInfoError<E: std::error::Error> {
|
||||
#[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<U256, Self::Error>;
|
||||
}
|
||||
|
||||
/// User registration + tx counters + tier limits storage
|
||||
@@ -280,11 +285,11 @@ impl UserDb {
|
||||
}
|
||||
|
||||
/// Get user tier info
|
||||
pub(crate) async fn user_tier_info<KSC: KarmaAmountExt>(
|
||||
pub(crate) async fn user_tier_info<E: std::error::Error, KSC: KarmaAmountExt<Error = E>>(
|
||||
&self,
|
||||
address: &Address,
|
||||
karma_sc: KSC,
|
||||
) -> Result<UserTierInfo, UserTierInfoError> {
|
||||
karma_sc: &KSC,
|
||||
) -> Result<UserTierInfo, UserTierInfoError<E>> {
|
||||
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<U256, Self::Error> {
|
||||
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<U256, Self::Error> {
|
||||
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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user