Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix handling of ens usernames #215

Merged
merged 1 commit into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let us add a check in the userdata store to panic if the name ends with .eth, and a todo to move it to the username proof store.

.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