From 7e67cb6d2abcca34205bb33e07d42408974df0f1 Mon Sep 17 00:00:00 2001 From: Brechy Date: Wed, 20 Sep 2023 21:46:23 -0300 Subject: [PATCH 1/4] feat: log filter --- eigentrust/src/lib.rs | 114 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 15 deletions(-) diff --git a/eigentrust/src/lib.rs b/eigentrust/src/lib.rs index 0dd9bf9e..7402592c 100644 --- a/eigentrust/src/lib.rs +++ b/eigentrust/src/lib.rs @@ -55,7 +55,10 @@ pub mod eth; pub mod storage; use crate::{ - attestation::{SignatureEth, SignatureRaw, SignedAttestationEth, SignedAttestationScalar}, + attestation::{ + SignatureEth, SignatureRaw, SignedAttestationEth, SignedAttestationScalar, DOMAIN_PREFIX, + DOMAIN_PREFIX_LEN, + }, circuit::{ETPublicInputs, OpinionVector, Score}, }; use att_station::{ @@ -92,7 +95,7 @@ use ethers::{ prelude::EthDisplay, providers::{Http, Middleware, Provider}, signers::{coins_bip39::English, LocalWallet, MnemonicBuilder, Signer}, - types::{Filter, Log, H160, H256}, + types::{Log, H160, H256}, }; use log::{debug, info, warn}; use num_rational::BigRational; @@ -221,8 +224,11 @@ impl Client { let signed_attestation = SignedAttestationEth::new(attestation_eth, signature_eth); - let as_address_res = self.config.as_address.parse::
(); - let as_address = as_address_res.map_err(|e| EigenError::ParsingError(e.to_string()))?; + let as_address = self + .config + .as_address + .parse::
() + .map_err(|e| EigenError::ParsingError(e.to_string()))?; let as_contract = AttestationStation::new(as_address, self.signer.clone()); // Verify signature is recoverable @@ -456,16 +462,29 @@ impl Client { signed_attestations } - /// Fetches logs from the contract. + /// Fetches "AttestationCreated" event logs from the contract, filtered by domain prefix. pub async fn get_logs(&self) -> Result, EigenError> { - let filter = Filter::new() - .address(self.config.as_address.parse::
().unwrap()) - .event("AttestationCreated(address,address,bytes32,bytes)") - .topic1(Vec::::new()) - .topic2(Vec::::new()) - .from_block(0); - - self.signer.get_logs(&filter).await.map_err(|e| EigenError::ParsingError(e.to_string())) + let as_contract = AttestationStation::new( + self.config.as_address.parse::
().unwrap(), + self.get_signer(), + ); + let filter = as_contract.attestation_created_filter().filter.from_block(0); + + // Fetch logs matching the filter. + let logs = self + .signer + .get_logs(&filter) + .await + .map_err(|e| EigenError::ParsingError(e.to_string()))?; + + // Filter logs based on the domain prefix. + let filtered_logs: Vec = logs + .iter() + .filter(|log| &log.topics[3].as_fixed_bytes()[..DOMAIN_PREFIX_LEN] == DOMAIN_PREFIX) + .cloned() + .collect(); + + Ok(filtered_logs) } /// Verifies the given proof. @@ -541,8 +560,16 @@ impl Client { #[cfg(test)] mod lib_tests { - use crate::{attestation::AttestationRaw, eth::deploy_as, Client, ClientConfig}; - use ethers::utils::Anvil; + use crate::{ + att_station::AttestationStation, + attestation::{AttestationRaw, DOMAIN_PREFIX, DOMAIN_PREFIX_LEN}, + eth::deploy_as, + Client, ClientConfig, ContractAttestationData, + }; + use ethers::{ + types::{Address, Bytes}, + utils::Anvil, + }; const TEST_MNEMONIC: &'static str = "test test test test test test test test test test test junk"; @@ -650,4 +677,61 @@ mod lib_tests { drop(anvil); } + + #[tokio::test] + async fn test_filter_logs_by_prefix() { + let anvil = Anvil::new().spawn(); + let config = ClientConfig { + as_address: "0x5fbdb2315678afecb367f032d93f642f64180aa3".to_string(), + band_id: "38922764296632428858395574229367".to_string(), + band_th: "500".to_string(), + band_url: "http://localhost:3000".to_string(), + chain_id: "31337".to_string(), + domain: "0x0000000000000000000000000000000000000000".to_string(), + node_url: anvil.endpoint().to_string(), + }; + let client = Client::new(config.clone(), TEST_MNEMONIC.to_string()); + + // Deploy attestation station + let as_address = deploy_as(client.get_signer()).await.unwrap(); + + // Update config with new addresses and instantiate client + let updated_config = ClientConfig { + as_address: format!("{:?}", as_address), + band_id: "38922764296632428858395574229367".to_string(), + band_th: "500".to_string(), + band_url: "http://localhost:3000".to_string(), + chain_id: "31337".to_string(), + domain: "0x0000000000000000000000000000000000000000".to_string(), + node_url: anvil.endpoint().to_string(), + }; + let updated_client = Client::new(updated_config, TEST_MNEMONIC.to_string()); + + // Submit a good attestation + let good_attestation = AttestationRaw::new([0; 20], [0; 20], 5, [0; 32]); + updated_client.attest(good_attestation).await.unwrap(); + + // Submit a bad attestation + let as_address = config.as_address.parse::
().unwrap(); + let as_contract = AttestationStation::new(as_address, client.get_signer()); + + let contract_data = ContractAttestationData { + about: Address::zero(), + key: [0; 32], + val: Bytes("0x0".into()), + }; + let tx_call = as_contract.attest(vec![contract_data]); + tx_call.send().await.unwrap(); + + // Fetch logs + let fetched_logs = updated_client.get_logs().await.unwrap(); + + // Asserts + assert_eq!(fetched_logs.len(), 1); + let prefix_in_fetched_log = + &fetched_logs[0].topics[3].as_fixed_bytes()[..DOMAIN_PREFIX_LEN]; + assert_eq!(prefix_in_fetched_log, DOMAIN_PREFIX); + + drop(anvil); + } } From a0b40f1b728ce1d7cd9bc55a69feef8ea07825bb Mon Sep 17 00:00:00 2001 From: Brechy Date: Thu, 21 Sep 2023 14:27:01 -0300 Subject: [PATCH 2/4] extend filter to configured domain --- eigentrust/src/attestation.rs | 10 ++++++++++ eigentrust/src/lib.rs | 24 ++++++++++-------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/eigentrust/src/attestation.rs b/eigentrust/src/attestation.rs index f09ee3e1..eeacb562 100644 --- a/eigentrust/src/attestation.rs +++ b/eigentrust/src/attestation.rs @@ -533,6 +533,16 @@ impl From for SignedAttestationRaw { } } +/// Builds the attestation default key for the given domain. +pub fn build_att_key(domain: H160) -> H256 { + let mut key = [0; 32]; + + key[..DOMAIN_PREFIX_LEN].copy_from_slice(&DOMAIN_PREFIX); + key[DOMAIN_PREFIX_LEN..].copy_from_slice(domain.as_fixed_bytes()); + + H256::from(key) +} + #[cfg(test)] mod tests { use crate::att_station::AttestationData as ContractAttestationData; diff --git a/eigentrust/src/lib.rs b/eigentrust/src/lib.rs index 7402592c..258cbaf4 100644 --- a/eigentrust/src/lib.rs +++ b/eigentrust/src/lib.rs @@ -55,16 +55,13 @@ pub mod eth; pub mod storage; use crate::{ - attestation::{ - SignatureEth, SignatureRaw, SignedAttestationEth, SignedAttestationScalar, DOMAIN_PREFIX, - DOMAIN_PREFIX_LEN, - }, + attestation::{SignatureEth, SignatureRaw, SignedAttestationEth, SignedAttestationScalar}, circuit::{ETPublicInputs, OpinionVector, Score}, }; use att_station::{ AttestationCreatedFilter, AttestationData as ContractAttestationData, AttestationStation, }; -use attestation::{AttestationEth, AttestationRaw, SignedAttestationRaw}; +use attestation::{build_att_key, AttestationEth, AttestationRaw, SignedAttestationRaw}; use circuit::ScoresReport; use eigentrust_zk::{ circuits::{ @@ -462,13 +459,15 @@ impl Client { signed_attestations } - /// Fetches "AttestationCreated" event logs from the contract, filtered by domain prefix. + /// Fetches "AttestationCreated" event logs from the contract, filtered by domain. pub async fn get_logs(&self) -> Result, EigenError> { let as_contract = AttestationStation::new( self.config.as_address.parse::
().unwrap(), self.get_signer(), ); let filter = as_contract.attestation_created_filter().filter.from_block(0); + let domain = H160::from_str(&self.config.domain) + .map_err(|e| EigenError::ParsingError(format!("Error parsing domain: {}", e)))?; // Fetch logs matching the filter. let logs = self @@ -477,12 +476,9 @@ impl Client { .await .map_err(|e| EigenError::ParsingError(e.to_string()))?; - // Filter logs based on the domain prefix. - let filtered_logs: Vec = logs - .iter() - .filter(|log| &log.topics[3].as_fixed_bytes()[..DOMAIN_PREFIX_LEN] == DOMAIN_PREFIX) - .cloned() - .collect(); + // Filter logs based on the correct key. + let filtered_logs: Vec = + logs.iter().filter(|log| log.topics[3] == build_att_key(domain)).cloned().collect(); Ok(filtered_logs) } @@ -679,7 +675,7 @@ mod lib_tests { } #[tokio::test] - async fn test_filter_logs_by_prefix() { + async fn test_get_logs() { let anvil = Anvil::new().spawn(); let config = ClientConfig { as_address: "0x5fbdb2315678afecb367f032d93f642f64180aa3".to_string(), @@ -711,10 +707,10 @@ mod lib_tests { let good_attestation = AttestationRaw::new([0; 20], [0; 20], 5, [0; 32]); updated_client.attest(good_attestation).await.unwrap(); - // Submit a bad attestation let as_address = config.as_address.parse::
().unwrap(); let as_contract = AttestationStation::new(as_address, client.get_signer()); + // Submit a bad attestation let contract_data = ContractAttestationData { about: Address::zero(), key: [0; 32], From 6d673f1361dc36c8c40640f842b0485ded3c3152 Mon Sep 17 00:00:00 2001 From: Brechy Date: Thu, 21 Sep 2023 15:42:41 -0300 Subject: [PATCH 3/4] fix: test --- eigentrust/src/lib.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/eigentrust/src/lib.rs b/eigentrust/src/lib.rs index 258cbaf4..9c5f8e25 100644 --- a/eigentrust/src/lib.rs +++ b/eigentrust/src/lib.rs @@ -103,6 +103,7 @@ use std::{ sync::Arc, time::Instant, }; +use storage::str_to_20_byte_array; /// Client Signer. pub type ClientSigner = SignerMiddleware, LocalWallet>; @@ -466,8 +467,7 @@ impl Client { self.get_signer(), ); let filter = as_contract.attestation_created_filter().filter.from_block(0); - let domain = H160::from_str(&self.config.domain) - .map_err(|e| EigenError::ParsingError(format!("Error parsing domain: {}", e)))?; + let domain = H160::from(str_to_20_byte_array(&self.config.domain)?); // Fetch logs matching the filter. let logs = self @@ -564,7 +564,7 @@ mod lib_tests { }; use ethers::{ types::{Address, Bytes}, - utils::Anvil, + utils::{hex, Anvil}, }; const TEST_MNEMONIC: &'static str = @@ -610,13 +610,21 @@ mod lib_tests { #[tokio::test] async fn test_get_attestations() { let anvil = Anvil::new().spawn(); + + // Build domain + let domain_input = [ + 0xff, 0x61, 0x4a, 0x6d, 0x59, 0x56, 0x2a, 0x42, 0x37, 0x72, 0x37, 0x76, 0x32, 0x4d, + 0x36, 0x53, 0x62, 0x6d, 0x35, 0xff, + ]; + let domain = format!("0x{}", hex::encode(domain_input)); + let config = ClientConfig { as_address: "0x5fbdb2315678afecb367f032d93f642f64180aa3".to_string(), band_id: "38922764296632428858395574229367".to_string(), band_th: "500".to_string(), band_url: "http://localhost:3000".to_string(), chain_id: "31337".to_string(), - domain: "0x0000000000000000000000000000000000000000".to_string(), + domain: domain.clone(), node_url: anvil.endpoint().to_string(), }; let client = Client::new(config, TEST_MNEMONIC.to_string()); @@ -631,7 +639,7 @@ mod lib_tests { band_th: "500".to_string(), band_url: "http://localhost:3000".to_string(), chain_id: "31337".to_string(), - domain: "0x0000000000000000000000000000000000000000".to_string(), + domain, node_url: anvil.endpoint().to_string(), }; let client = Client::new(config, TEST_MNEMONIC.to_string()); @@ -642,11 +650,6 @@ mod lib_tests { 0x36, 0x53, 0x62, 0x6d, 0x35, 0xff, ]; - let domain_input = [ - 0xff, 0x61, 0x4a, 0x6d, 0x59, 0x56, 0x2a, 0x42, 0x37, 0x72, 0x37, 0x76, 0x32, 0x4d, - 0x36, 0x53, 0x62, 0x6d, 0x35, 0xff, - ]; - let value: u8 = 10; let message = [ From 83b34a38b99596f8694d2f16d3a80ea3f734fc98 Mon Sep 17 00:00:00 2001 From: Brechy Date: Thu, 21 Sep 2023 15:59:31 -0300 Subject: [PATCH 4/4] use filter builder --- eigentrust/src/lib.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/eigentrust/src/lib.rs b/eigentrust/src/lib.rs index 9c5f8e25..80b5a0d8 100644 --- a/eigentrust/src/lib.rs +++ b/eigentrust/src/lib.rs @@ -466,21 +466,17 @@ impl Client { self.config.as_address.parse::
().unwrap(), self.get_signer(), ); - let filter = as_contract.attestation_created_filter().filter.from_block(0); let domain = H160::from(str_to_20_byte_array(&self.config.domain)?); - // Fetch logs matching the filter. - let logs = self - .signer - .get_logs(&filter) - .await - .map_err(|e| EigenError::ParsingError(e.to_string()))?; + // Set filter + let filter = as_contract + .attestation_created_filter() + .filter + .topic3(build_att_key(domain)) + .from_block(0); - // Filter logs based on the correct key. - let filtered_logs: Vec = - logs.iter().filter(|log| log.topics[3] == build_att_key(domain)).cloned().collect(); - - Ok(filtered_logs) + // Fetch logs matching the filter. + self.signer.get_logs(&filter).await.map_err(|e| EigenError::ParsingError(e.to_string())) } /// Verifies the given proof.