From e7b218563c4b6f00346eb6d013f63bf4fcd09c12 Mon Sep 17 00:00:00 2001 From: Aditi Srinivasan Date: Tue, 14 Jan 2025 12:16:30 -0500 Subject: [PATCH] fix handling of ens usernames --- src/storage/store/engine.rs | 77 +++++++++++++++++++++++-------- src/storage/store/engine_tests.rs | 37 +++++++++++++++ 2 files changed, 95 insertions(+), 19 deletions(-) diff --git a/src/storage/store/engine.rs b/src/storage/store/engine.rs index e4266c6..57d92d7 100644 --- a/src/storage/store/engine.rs +++ b/src/storage/store/engine.rs @@ -1,13 +1,13 @@ +use super::account::UsernameProofStore; use super::account::{IntoU8, OnchainEventStorageError, UserDataStore}; use crate::core::error::HubError; use crate::core::types::Height; use crate::core::validations; use crate::mempool::mempool::MempoolMessagesRequest; -use crate::proto::FarcasterNetwork; use crate::proto::HubEvent; -use crate::proto::Message; use crate::proto::UserNameProof; use crate::proto::{self, Block, MessageType, ShardChunk, Transaction}; +use crate::proto::{FarcasterNetwork, UserNameType}; use crate::proto::{OnChainEvent, OnChainEventType}; use crate::storage::db::{PageOptions, RocksDB, RocksDbTransactionBatch}; use crate::storage::store::account::{CastStore, MessagesPage}; @@ -18,6 +18,7 @@ use crate::storage::trie::merkle_trie; use crate::utils::statsd_wrapper::StatsdClientWrapper; use itertools::Itertools; use merkle_trie::TrieKey; +use prost::Message; use std::collections::HashSet; use std::str; use std::sync::Arc; @@ -963,32 +964,67 @@ impl ShardEngine { Ok(()) } + fn get_username_proof( + &self, + name: String, + txn: &mut RocksDbTransactionBatch, + ) -> Result, MessageValidationError> { + // TODO(aditi): The fnames proofs should live in the username proof store. + if name.ends_with(".eth") { + let proof_message = UsernameProofStore::get_username_proof( + &self.stores.username_proof_store, + &name.encode_to_vec(), + UserNameType::UsernameTypeEnsL1 as u8, + ) + .map_err(|e| MessageValidationError::StoreError { + inner: e, + hash: vec![], + })?; + match proof_message { + Some(message) => match message.data { + None => Ok(None), + Some(message_data) => match message_data.body { + Some(body) => match body { + proto::message_data::Body::UsernameProofBody(user_name_proof) => { + Ok(Some(user_name_proof)) + } + _ => Ok(None), + }, + None => Ok(None), + }, + }, + None => Ok(None), + } + } else { + UserDataStore::get_username_proof(&self.stores.user_data_store, txn, name.as_bytes()) + .map_err(|e| MessageValidationError::StoreError { + inner: e, + hash: vec![], + }) + } + } + fn validate_username( &self, fid: u64, - fname: &str, + name: &str, txn: &mut RocksDbTransactionBatch, ) -> Result<(), MessageValidationError> { - if fname.is_empty() { + if name.is_empty() { // Setting an empty username is allowed, no need to validate the proof return Ok(()); } - let fname = fname.to_string(); + let name = name.to_string(); // TODO: validate fname string - let proof = - UserDataStore::get_username_proof(&self.stores.user_data_store, txn, fname.as_bytes()) - .map_err(|e| MessageValidationError::StoreError { - inner: e, - hash: vec![], - })?; + let proof = self.get_username_proof(name.clone(), txn)?; match proof { Some(proof) => { if proof.fid != fid { return Err(MessageValidationError::MissingFname); } - if fname.ends_with(".eth") { + if name.ends_with(".eth") { // TODO: Validate ens names } else { } @@ -1134,7 +1170,10 @@ impl ShardEngine { } } - pub fn simulate_message(&mut self, message: &Message) -> Result<(), MessageValidationError> { + pub fn simulate_message( + &mut self, + message: &proto::Message, + ) -> Result<(), MessageValidationError> { let mut txn = RocksDbTransactionBatch::new(); let snapchain_txn = Transaction { fid: message.fid() as u64, @@ -1207,7 +1246,7 @@ impl ShardEngine { pub fn get_links_by_fid(&self, fid: u64) -> Result { self.stores .link_store - .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) + .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) } pub fn get_link_compact_state_messages_by_fid( @@ -1222,20 +1261,20 @@ impl ShardEngine { pub fn get_reactions_by_fid(&self, fid: u64) -> Result { self.stores .reaction_store - .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) + .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) } pub fn get_user_data_by_fid(&self, fid: u64) -> Result { self.stores .user_data_store - .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) + .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) } pub fn get_user_data_by_fid_and_type( &self, fid: u64, user_data_type: proto::UserDataType, - ) -> Result { + ) -> Result { UserDataStore::get_user_data_by_fid_and_type( &self.stores.user_data_store, fid, @@ -1246,13 +1285,13 @@ impl ShardEngine { pub fn get_verifications_by_fid(&self, fid: u64) -> Result { self.stores .verification_store - .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) + .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) } pub fn get_username_proofs_by_fid(&self, fid: u64) -> Result { self.stores .username_proof_store - .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) + .get_adds_by_fid:: bool>(fid, &PageOptions::default(), None) } pub fn get_fname_proof(&self, name: &String) -> Result, HubError> { diff --git a/src/storage/store/engine_tests.rs b/src/storage/store/engine_tests.rs index fb3cca0..b64d244 100644 --- a/src/storage/store/engine_tests.rs +++ b/src/storage/store/engine_tests.rs @@ -1182,6 +1182,43 @@ mod tests { )); } + #[tokio::test] + async fn test_merge_ens_username() { + let (mut engine, _tmpdir) = test_helper::new_engine(); + let ens_name = &"farcaster.eth".to_string(); + let owner = test_helper::default_custody_address(); + let signature = "signature".to_string(); + let signer = test_helper::default_signer(); + let timestamp = messages_factory::farcaster_time(); + + test_helper::register_user(FID_FOR_TEST, signer.clone(), owner.clone(), &mut engine).await; + + let username_proof_add = messages_factory::username_proof::create_username_proof( + FID_FOR_TEST as u64, + proto::UserNameType::UsernameTypeEnsL1, + ens_name.clone(), + owner, + signature.clone(), + timestamp as u64, + Some(&signer), + ); + + commit_message(&mut engine, &username_proof_add).await; + let committed_username_proof = engine.get_username_proofs_by_fid(FID_FOR_TEST).unwrap(); + assert_eq!(committed_username_proof.messages.len(), 1); + + let username_add = messages_factory::user_data::create_user_data_add( + FID_FOR_TEST as u64, + proto::UserDataType::Username, + ens_name, + Some(timestamp + 1), + Some(&signer), + ); + + // We had a bug where this commit would fail because we looked in the wrong store to find the username proof + commit_message(&mut engine, &username_add).await; + } + #[tokio::test] async fn test_username_revoked_when_proof_transferred() { let (mut engine, _tmpdir) = test_helper::new_engine();