Skip to content

Commit

Permalink
fix handling of ens usernames (#215)
Browse files Browse the repository at this point in the history
Look up ens proofs in the username proofs store rather than the user
data store.
  • Loading branch information
aditiharini authored Jan 14, 2025
1 parent f0b0a67 commit c137499
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 19 deletions.
77 changes: 58 additions & 19 deletions src/storage/store/engine.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -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;
Expand Down Expand Up @@ -963,32 +964,67 @@ impl ShardEngine {
Ok(())
}

fn get_username_proof(
&self,
name: String,
txn: &mut RocksDbTransactionBatch,
) -> Result<Option<UserNameProof>, 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 {
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1207,7 +1246,7 @@ impl ShardEngine {
pub fn get_links_by_fid(&self, fid: u64) -> Result<MessagesPage, HubError> {
self.stores
.link_store
.get_adds_by_fid::<fn(&Message) -> bool>(fid, &PageOptions::default(), None)
.get_adds_by_fid::<fn(&proto::Message) -> bool>(fid, &PageOptions::default(), None)
}

pub fn get_link_compact_state_messages_by_fid(
Expand All @@ -1222,20 +1261,20 @@ impl ShardEngine {
pub fn get_reactions_by_fid(&self, fid: u64) -> Result<MessagesPage, HubError> {
self.stores
.reaction_store
.get_adds_by_fid::<fn(&Message) -> bool>(fid, &PageOptions::default(), None)
.get_adds_by_fid::<fn(&proto::Message) -> bool>(fid, &PageOptions::default(), None)
}

pub fn get_user_data_by_fid(&self, fid: u64) -> Result<MessagesPage, HubError> {
self.stores
.user_data_store
.get_adds_by_fid::<fn(&Message) -> bool>(fid, &PageOptions::default(), None)
.get_adds_by_fid::<fn(&proto::Message) -> bool>(fid, &PageOptions::default(), None)
}

pub fn get_user_data_by_fid_and_type(
&self,
fid: u64,
user_data_type: proto::UserDataType,
) -> Result<Message, HubError> {
) -> Result<proto::Message, HubError> {
UserDataStore::get_user_data_by_fid_and_type(
&self.stores.user_data_store,
fid,
Expand All @@ -1246,13 +1285,13 @@ impl ShardEngine {
pub fn get_verifications_by_fid(&self, fid: u64) -> Result<MessagesPage, HubError> {
self.stores
.verification_store
.get_adds_by_fid::<fn(&Message) -> bool>(fid, &PageOptions::default(), None)
.get_adds_by_fid::<fn(&proto::Message) -> bool>(fid, &PageOptions::default(), None)
}

pub fn get_username_proofs_by_fid(&self, fid: u64) -> Result<MessagesPage, HubError> {
self.stores
.username_proof_store
.get_adds_by_fid::<fn(&Message) -> bool>(fid, &PageOptions::default(), None)
.get_adds_by_fid::<fn(&proto::Message) -> bool>(fid, &PageOptions::default(), None)
}

pub fn get_fname_proof(&self, name: &String) -> Result<Option<UserNameProof>, HubError> {
Expand Down
37 changes: 37 additions & 0 deletions src/storage/store/engine_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit c137499

Please sign in to comment.