mirror of
https://github.com/vacp2p/status-rln-prover.git
synced 2026-01-09 05:28:00 -05:00
Add AccountSlashed event in KarmaSC contract (#52)
* Add AccountSlashed event in KarmaSC contract * Handle slash event in KarmaSCEventListener
This commit is contained in:
@@ -3,6 +3,7 @@ use alloy::{
|
|||||||
contract::Error as AlloyContractError,
|
contract::Error as AlloyContractError,
|
||||||
primitives::{Address, U256},
|
primitives::{Address, U256},
|
||||||
providers::Provider,
|
providers::Provider,
|
||||||
|
rpc::types::Log,
|
||||||
sol_types::SolEvent,
|
sol_types::SolEvent,
|
||||||
};
|
};
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
@@ -14,14 +15,14 @@ use crate::user_db::UserDb;
|
|||||||
use crate::user_db_error::RegisterError;
|
use crate::user_db_error::RegisterError;
|
||||||
use smart_contract::{KarmaAmountExt, KarmaRLNSC, KarmaSC, RLNRegister};
|
use smart_contract::{KarmaAmountExt, KarmaRLNSC, KarmaSC, RLNRegister};
|
||||||
|
|
||||||
pub(crate) struct RegistryListener {
|
pub(crate) struct KarmaScEventListener {
|
||||||
karma_sc_address: Address,
|
karma_sc_address: Address,
|
||||||
rln_sc_address: Address,
|
rln_sc_address: Address,
|
||||||
user_db: UserDb,
|
user_db: UserDb,
|
||||||
minimal_amount: U256,
|
minimal_amount: U256,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegistryListener {
|
impl KarmaScEventListener {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
karma_sc_address: Address,
|
karma_sc_address: Address,
|
||||||
rln_sc_address: Address,
|
rln_sc_address: Address,
|
||||||
@@ -42,17 +43,13 @@ impl RegistryListener {
|
|||||||
provider: P,
|
provider: P,
|
||||||
provider_with_signer: PS,
|
provider_with_signer: PS,
|
||||||
) -> Result<(), AppError> {
|
) -> Result<(), AppError> {
|
||||||
// let provider = self.setup_provider_ws().await.map_err(AppError::from)?;
|
|
||||||
let karma_sc = KarmaSC::new(self.karma_sc_address, provider.clone());
|
let karma_sc = KarmaSC::new(self.karma_sc_address, provider.clone());
|
||||||
|
|
||||||
// let provider_with_signer = self.setup_provider_with_signer(self.private_key.clone())
|
|
||||||
// .await
|
|
||||||
// .map_err(AppError::from)?;
|
|
||||||
let rln_sc = KarmaRLNSC::new(self.rln_sc_address, provider_with_signer);
|
let rln_sc = KarmaRLNSC::new(self.rln_sc_address, provider_with_signer);
|
||||||
|
|
||||||
let filter = alloy::rpc::types::Filter::new()
|
let filter = alloy::rpc::types::Filter::new()
|
||||||
.address(self.karma_sc_address)
|
.address(self.karma_sc_address)
|
||||||
.event(KarmaSC::Transfer::SIGNATURE);
|
.event(KarmaSC::Transfer::SIGNATURE)
|
||||||
|
.event(KarmaSC::AccountSlashed::SIGNATURE);
|
||||||
|
|
||||||
// Subscribe to logs matching the filter.
|
// Subscribe to logs matching the filter.
|
||||||
let subscription = provider.subscribe_logs(&filter).await?;
|
let subscription = provider.subscribe_logs(&filter).await?;
|
||||||
@@ -60,6 +57,21 @@ impl RegistryListener {
|
|||||||
|
|
||||||
// Loop through the incoming event logs
|
// Loop through the incoming event logs
|
||||||
while let Some(log) = stream.next().await {
|
while let Some(log) = stream.next().await {
|
||||||
|
match log.topic0() {
|
||||||
|
Some(&KarmaSC::Transfer::SIGNATURE_HASH) => {
|
||||||
|
self.transfer_event(&log, &karma_sc, &rln_sc)
|
||||||
|
.await
|
||||||
|
.map_err(AppError::RegistryError)?;
|
||||||
|
}
|
||||||
|
Some(&KarmaSC::AccountSlashed::SIGNATURE_HASH) => {
|
||||||
|
self.slash_event(&log).await;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
debug!("Received unknown topic from karma sc: {:?}", log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
match KarmaSC::Transfer::decode_log_data(log.data()) {
|
match KarmaSC::Transfer::decode_log_data(log.data()) {
|
||||||
Ok(transfer_event) => {
|
Ok(transfer_event) => {
|
||||||
match self
|
match self
|
||||||
@@ -93,6 +105,64 @@ impl RegistryListener {
|
|||||||
// in order to avoid a too long service interruption?
|
// in order to avoid a too long service interruption?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
// TODO
|
||||||
|
/*
|
||||||
|
match KarmaSC::AccountSlashed::decode_log_data(log.data()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decode transfert event from log and call `handle_transfer_event`
|
||||||
|
async fn transfer_event<
|
||||||
|
E: Into<AlloyContractError>,
|
||||||
|
KSC: KarmaAmountExt<Error = E>,
|
||||||
|
RLNSC: RLNRegister<Error = E>,
|
||||||
|
>(
|
||||||
|
&self,
|
||||||
|
log: &Log,
|
||||||
|
karma_sc: &KSC,
|
||||||
|
rln_sc: &RLNSC,
|
||||||
|
) -> Result<(), HandleTransferError> {
|
||||||
|
match KarmaSC::Transfer::decode_log_data(log.data()) {
|
||||||
|
Ok(transfer_event) => {
|
||||||
|
match self
|
||||||
|
.handle_transfer_event(karma_sc, rln_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);
|
||||||
|
// Note: Err(e) == HandleTransferError::FetchBalanceOf
|
||||||
|
// if we cannot fetch the user balance, something is seriously wrong
|
||||||
|
// and the prover will fail here
|
||||||
|
|
||||||
|
// return Err(AppError::RegistryError(e));
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error decoding log data: {:?}", e);
|
||||||
|
// It's also useful to print the raw log data for debugging
|
||||||
|
error!("Raw log topics: {:?}", log.topics());
|
||||||
|
error!("Raw log data: {:?}", log.data());
|
||||||
|
// Note: This can happen when
|
||||||
|
// - SC code has been updated but not the Prover
|
||||||
|
// - In the update process, the Prover has not been shutdown (yet)
|
||||||
|
// in order to avoid a too long service interruption?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -155,7 +225,7 @@ impl RegistryListener {
|
|||||||
U256::from_le_slice(BigUint::from(id_commitment).to_bytes_le().as_slice());
|
U256::from_le_slice(BigUint::from(id_commitment).to_bytes_le().as_slice());
|
||||||
|
|
||||||
if let Err(e) = rln_sc.register_user(&to_address, id_co).await {
|
if let Err(e) = rln_sc.register_user(&to_address, id_co).await {
|
||||||
// Fail to register user on smart contract
|
// Fail to register the user on smart contract
|
||||||
// Remove the user in internal Db
|
// Remove the user in internal Db
|
||||||
if !self.user_db.remove_user(&to_address, false) {
|
if !self.user_db.remove_user(&to_address, false) {
|
||||||
// Fails if DB & SC are inconsistent
|
// Fails if DB & SC are inconsistent
|
||||||
@@ -170,6 +240,28 @@ impl RegistryListener {
|
|||||||
|
|
||||||
Ok(to_address)
|
Ok(to_address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle slash event from Karma smart contract
|
||||||
|
async fn slash_event(&self, log: &Log) {
|
||||||
|
match KarmaSC::AccountSlashed::decode_log_data(log.data()) {
|
||||||
|
Ok(slash_event) => {
|
||||||
|
let address_slashed: Address = slash_event.account;
|
||||||
|
if !self.user_db.remove_user(&address_slashed, false) {
|
||||||
|
error!("Cannot remove user ({:?}) from DB", address_slashed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error decoding log data: {:?}", e);
|
||||||
|
// It's also useful to print the raw log data for debugging
|
||||||
|
error!("Raw log topics: {:?}", log.topics());
|
||||||
|
error!("Raw log data: {:?}", log.data());
|
||||||
|
// Note: This can happen when
|
||||||
|
// - SC code has been updated but not the Prover
|
||||||
|
// - In the update process, the Prover has not been shutdown (yet)
|
||||||
|
// to avoid a too long service interruption?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -247,7 +339,7 @@ mod tests {
|
|||||||
assert!(user_db_service.get_user_db().get_user(&ADDR_2).is_none());
|
assert!(user_db_service.get_user_db().get_user(&ADDR_2).is_none());
|
||||||
|
|
||||||
let minimal_amount = U256::from(25);
|
let minimal_amount = U256::from(25);
|
||||||
let registry = RegistryListener {
|
let registry = KarmaScEventListener {
|
||||||
rln_sc_address: Default::default(),
|
rln_sc_address: Default::default(),
|
||||||
karma_sc_address: Default::default(),
|
karma_sc_address: Default::default(),
|
||||||
user_db,
|
user_db,
|
||||||
@@ -2,11 +2,11 @@ mod args;
|
|||||||
mod epoch_service;
|
mod epoch_service;
|
||||||
mod error;
|
mod error;
|
||||||
mod grpc_service;
|
mod grpc_service;
|
||||||
|
mod karma_sc_listener;
|
||||||
pub mod metrics;
|
pub mod metrics;
|
||||||
mod mock;
|
mod mock;
|
||||||
mod proof_generation;
|
mod proof_generation;
|
||||||
mod proof_service;
|
mod proof_service;
|
||||||
mod registry_listener;
|
|
||||||
mod rocksdb_operands;
|
mod rocksdb_operands;
|
||||||
mod tier;
|
mod tier;
|
||||||
mod tiers_listener;
|
mod tiers_listener;
|
||||||
@@ -37,10 +37,10 @@ pub use crate::args::{ARGS_DEFAULT_GENESIS, AppArgs, AppArgsConfig};
|
|||||||
use crate::epoch_service::EpochService;
|
use crate::epoch_service::EpochService;
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::grpc_service::GrpcProverService;
|
use crate::grpc_service::GrpcProverService;
|
||||||
|
use crate::karma_sc_listener::KarmaScEventListener;
|
||||||
pub use crate::mock::MockUser;
|
pub use crate::mock::MockUser;
|
||||||
use crate::mock::read_mock_user;
|
use crate::mock::read_mock_user;
|
||||||
use crate::proof_service::ProofService;
|
use crate::proof_service::ProofService;
|
||||||
use crate::registry_listener::RegistryListener;
|
|
||||||
use crate::tier::TierLimits;
|
use crate::tier::TierLimits;
|
||||||
use crate::tiers_listener::TiersListener;
|
use crate::tiers_listener::TiersListener;
|
||||||
use crate::user_db::{MERKLE_TREE_HEIGHT, UserDbConfig};
|
use crate::user_db::{MERKLE_TREE_HEIGHT, UserDbConfig};
|
||||||
@@ -150,7 +150,7 @@ pub async fn run_prover(app_args: AppArgs) -> Result<(), AppError> {
|
|||||||
// No registry listener when mock is enabled
|
// No registry listener when mock is enabled
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(RegistryListener::new(
|
Some(KarmaScEventListener::new(
|
||||||
app_args.ksc_address.unwrap(),
|
app_args.ksc_address.unwrap(),
|
||||||
app_args.rlnsc_address.unwrap(),
|
app_args.rlnsc_address.unwrap(),
|
||||||
user_db_service.get_user_db(),
|
user_db_service.get_user_db(),
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
use alloy::primitives::{Address, U256};
|
|
||||||
use futures::FutureExt;
|
|
||||||
use parking_lot::RwLock;
|
|
||||||
use prover::{AppArgs, MockUser, run_prover};
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::net::{IpAddr, Ipv4Addr};
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
// third-party
|
||||||
|
use alloy::primitives::{Address, U256};
|
||||||
|
use futures::FutureExt;
|
||||||
|
use parking_lot::RwLock;
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
use tonic::Response;
|
use tonic::Response;
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
use tracing_test::traced_test;
|
// use tracing_test::traced_test;
|
||||||
|
// internal
|
||||||
|
use prover::{AppArgs, MockUser, run_prover};
|
||||||
pub mod prover_proto {
|
pub mod prover_proto {
|
||||||
// Include generated code (see build.rs)
|
// Include generated code (see build.rs)
|
||||||
tonic::include_proto!("prover");
|
tonic::include_proto!("prover");
|
||||||
@@ -220,7 +221,7 @@ async fn proof_collector(port: u16, proof_count: usize) -> Vec<RlnProofReply> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[traced_test]
|
// #[traced_test]
|
||||||
async fn test_grpc_gen_proof() {
|
async fn test_grpc_gen_proof() {
|
||||||
let mock_users = vec![
|
let mock_users = vec![
|
||||||
MockUser {
|
MockUser {
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ edition = "2024"
|
|||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "karma_sc_test"
|
name = "karma_sc_test"
|
||||||
path = "src/karma_sc_test.rs"
|
path = "src/bin_tests/karma_sc_test.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "karma_tiers_test"
|
name = "karma_tiers_test"
|
||||||
path = "src/karma_tiers_test.rs"
|
path = "src/bin_tests/karma_tiers_test.rs"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "rln_sc_test"
|
name = "rln_sc_test"
|
||||||
path = "src/rln_sc_test.rs"
|
path = "src/bin_tests/rln_sc_test.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ pub trait KarmaAmountExt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sol! {
|
sol! {
|
||||||
// https://github.com/vacp2p/staking-reward-streamer/blob/main/src/Karma.sol
|
// https://github.com/status-im/status-network-monorepo/blob/develop/status-network-contracts/src/Karma.sol
|
||||||
|
// OLD: https://github.com/vacp2p/staking-reward-streamer/blob/main/src/Karma.sol
|
||||||
//
|
//
|
||||||
// docker run -v ./:/sources ethereum/solc:stable --bin --via-ir --optimize --optimize-runs 1 --overwrite @openzeppelin/contracts=/sources/lib/openzeppelin-contracts/contracts @openzeppelin/contracts-upgradeable=/sources/lib/openzeppelin-contracts-upgradeable/contracts /sources/src/Karma.sol
|
// docker run -v ./:/sources ethereum/solc:stable --bin --via-ir --optimize --optimize-runs 1 --overwrite @openzeppelin/contracts=/sources/lib/openzeppelin-contracts/contracts @openzeppelin/contracts-upgradeable=/sources/lib/openzeppelin-contracts-upgradeable/contracts /sources/src/Karma.sol
|
||||||
|
|
||||||
@@ -53,6 +54,9 @@ sol! {
|
|||||||
|
|
||||||
// From: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L16
|
// 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);
|
event Transfer(address indexed from, address indexed to, uint256 value);
|
||||||
|
event AccountSlashed(
|
||||||
|
address indexed account, uint256 amount, address indexed rewardRecipient, uint256 rewardAmount
|
||||||
|
);
|
||||||
|
|
||||||
function balanceOf(address account) public view override returns (uint256);
|
function balanceOf(address account) public view override returns (uint256);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user