Skip to content

Commit

Permalink
chore: add more test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
zensh committed Dec 23, 2023
1 parent ec6e69f commit b924133
Show file tree
Hide file tree
Showing 6 changed files with 717 additions and 47 deletions.
22 changes: 15 additions & 7 deletions crates/ns-fetcher/src/fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ use async_stream::try_stream;
use bloomfilter::Bloom;
use futures_core::stream::Stream;

use ns_protocol::state::{Inscription, NameState, ServiceState};
use ns_protocol::state::{Inscription, NameState, ServiceProtocol, ServiceState};

use crate::indexer::Client;

pub type InscriptionState = (
Inscription,
Option<(NameState, ServiceState, Option<ServiceProtocol>)>,
);

// fetches all inscriptions and states from last accepted to bottom_height
pub fn fetch_desc(
cli: Client,
bottom_height: u64,
) -> impl Stream<Item = anyhow::Result<(Inscription, Option<(NameState, ServiceState)>)>> {
) -> impl Stream<Item = anyhow::Result<InscriptionState>> {
try_stream! {
let last_accepted: Inscription = cli.get_last_accepted_inscription().await?;
let name_state: NameState = cli.get_name_state(&last_accepted.name).await?;
Expand All @@ -21,7 +26,7 @@ pub fn fetch_desc(
let mut head_inscription = last_accepted.clone();

bloom.set(&head_inscription.name);
yield (last_accepted, Some((name_state, service_state)));
yield (last_accepted, Some((name_state, service_state, None)));

loop {
if head_height == 0 || head_height < bottom_height {
Expand Down Expand Up @@ -65,7 +70,7 @@ pub fn fetch_desc(
Err(anyhow::anyhow!("inscription({}): service_hash mismatch", inscription.height))?;
}

yield (inscription, Some((name_state, service_state)));
yield (inscription, Some((name_state, service_state, None)));
}
}
}
Expand All @@ -81,7 +86,7 @@ mod tests {
#[ignore]
async fn fetcher_works() {
let endpoint = std::env::var("INDEXER_ENDPOINT").unwrap_or_default();
// let endpoint = "http://127.0.0.1::8080".to_string();
// let endpoint = "http://192.168.1.80:8080".to_string();
if endpoint.is_empty() {
return;
}
Expand All @@ -95,7 +100,7 @@ mod tests {
let (last_accepted, state) = s.next().await.unwrap().unwrap();
assert!(last_accepted.height > 0);
assert!(state.is_some());
let (name_state, service_state) = state.unwrap();
let (name_state, service_state, _) = state.unwrap();
assert_eq!(last_accepted.name, name_state.name);
assert_eq!(last_accepted.sequence, name_state.sequence);
assert_eq!(last_accepted.name, service_state.name);
Expand All @@ -104,10 +109,13 @@ mod tests {
assert_eq!(last_accepted.service_hash, service_state.hash().unwrap());

let mut state_exists = false;
let mut head_ins = last_accepted.clone();
while let Some(res) = s.next().await {
let (ins, state) = res.unwrap();
println!("got {}, {}, {}", ins.height, ins.name, ins.sequence);
if let Some((name_state, service_state)) = state {
assert_eq!(head_ins.previous_hash, ins.hash().unwrap());
head_ins = ins.clone();
if let Some((name_state, service_state, _)) = state {
assert_eq!(ins.name, name_state.name);
assert_eq!(ins.sequence, name_state.sequence);
assert_eq!(ins.name, service_state.name);
Expand Down
14 changes: 13 additions & 1 deletion crates/ns-indexer/src/db/model_inscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,19 @@ impl Inscription {
);
}

let _ = db.batch(statements, values).await?;
let mut start = 0;
while start < statements.len() {
let end = if start + 1000 > statements.len() {
statements.len()
} else {
start + 1000
};

let _ = db
.batch(statements[start..end].to_vec(), &values[start..end])
.await?;
start = end;
}
Ok(())
}

Expand Down
56 changes: 33 additions & 23 deletions crates/ns-indexer/src/db/model_name_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,33 +134,43 @@ impl NameState {
db: &scylladb::ScyllaDB,
names: Vec<&String>,
) -> anyhow::Result<Vec<NameState>> {
let mut vals_name: Vec<&str> = Vec::with_capacity(names.len());
let mut params: Vec<CqlValue> = Vec::with_capacity(names.len());
let fields = vec!["name".to_string(), "public_keys".to_string()];

for name in names {
vals_name.push("?");
params.push(name.to_cql());
}
let mut output: Vec<NameState> = Vec::with_capacity(names.len());

let fields = vec!["name".to_string(), "public_keys".to_string()];
let query = format!(
"SELECT {} FROM name_state WHERE name IN ({})",
fields.join(","),
vals_name.join(",")
);
let res = db.execute(query, params).await?;

let rows = res.rows.unwrap_or_default();
let mut res: Vec<NameState> = Vec::with_capacity(rows.len());
for r in rows {
let mut cols = ColumnsMap::with_capacity(2);
cols.fill(r, &fields)?;
let mut item = NameState::default();
item.fill(&cols);
res.push(item);
let mut start = 0;
while start < names.len() {
let end = if start + 100 > names.len() {
names.len()
} else {
start + 100
};

let mut vals_name: Vec<&str> = Vec::with_capacity(end - start);
let mut params: Vec<CqlValue> = Vec::with_capacity(end - start);
for name in &names[start..end] {
vals_name.push("?");
params.push(name.to_cql());
}

let query = format!(
"SELECT {} FROM name_state WHERE name IN ({})",
fields.join(","),
vals_name.join(",")
);
let res = db.execute(query, params).await?;
let rows = res.rows.unwrap_or_default();
for r in rows {
let mut cols = ColumnsMap::with_capacity(2);
cols.fill(r, &fields)?;
let mut item = NameState::default();
item.fill(&cols);
output.push(item);
}
start = end;
}

Ok(res)
Ok(output)
}

pub async fn batch_update_name_indexs(
Expand Down
1 change: 1 addition & 0 deletions crates/ns-protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ sha3 = "0.10"
[dev-dependencies]
hex = "0.4"
hex-literal = "0.4"
rand_core = { version = "0.6", features = ["getrandom", "alloc"] }
135 changes: 126 additions & 9 deletions crates/ns-protocol/src/ns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ impl PublicKeyParams {
let mut public_keys = self.public_keys.clone();
public_keys.dedup();
if public_keys.len() != self.public_keys.len() {
return Err(Error::Custom(format!(
"PublicKeyParams: duplicate public_keys",
)));
return Err(Error::Custom(
"PublicKeyParams: duplicate public_keys".to_string(),
));
}

Ok(())
Expand Down Expand Up @@ -261,7 +261,7 @@ impl Name {
let mut signatures = self.signatures.clone();
signatures.dedup();
if signatures.len() != self.signatures.len() {
return Err(Error::Custom(format!("Name: duplicate signatures",)));
return Err(Error::Custom("Name: duplicate signatures".to_string()));
}
Ok(())
}
Expand All @@ -276,15 +276,19 @@ impl Name {
}

let data = self.to_sign_bytes()?;
let mut keys = params.public_keys.iter();
let mut keys: Vec<ed25519::VerifyingKey> = Vec::with_capacity(params.public_keys.len());
for pk in &params.public_keys {
let key = ed25519::VerifyingKey::try_from(pk.as_slice())
.map_err(|err| Error::Custom(err.to_string()))?;
keys.push(key);
}

let mut count = 0;
for sig in self.signatures.iter() {
let sig = ed25519::Signature::from_slice(&sig.0)
.map_err(|err| Error::Custom(err.to_string()))?;
for key in keys.by_ref() {
let verifying_key = ed25519::VerifyingKey::try_from(key.as_slice())
.map_err(|err| Error::Custom(err.to_string()))?;
if verifying_key.verify_strict(&data, &sig).is_ok() {
for key in keys.iter() {
if key.verify_strict(&data, &sig).is_ok() {
count += 1;
if count >= threshold {
return Ok(());
Expand Down Expand Up @@ -324,8 +328,12 @@ impl Name {
{
let sig = Signature(signer.sign(&data).to_bytes().to_vec());
self.signatures.push(sig);
if self.signatures.len() == threshold as usize {
break;
}
}
}

if self.signatures.len() != threshold as usize {
return Err(Error::Custom(format!(
"Name: expected {} signatures, got {}",
Expand Down Expand Up @@ -742,6 +750,13 @@ fn kind_of_value(v: &Value) -> String {
mod tests {
use super::*;
use hex_literal::hex;
use rand_core::{OsRng, RngCore};

fn secret_key() -> [u8; 32] {
let mut data = [0u8; 32];
OsRng.fill_bytes(&mut data);
data
}

#[test]
fn valid_name_works() {
Expand Down Expand Up @@ -853,4 +868,106 @@ mod tests {
buf.push(0x80);
assert!(Name::from_bytes(&buf[..]).is_err());
}

#[test]
fn name_sign_verify() {
let s1 = ed25519::SigningKey::from_bytes(&secret_key());
let s2 = ed25519::SigningKey::from_bytes(&secret_key());
let s3 = ed25519::SigningKey::from_bytes(&secret_key());
let s4 = ed25519::SigningKey::from_bytes(&secret_key());
let mut signers = vec![s1.clone(), s2.clone(), s3.clone(), s4.clone()];

let params = PublicKeyParams {
public_keys: vec![
s1.verifying_key().as_bytes().to_vec(),
s2.verifying_key().as_bytes().to_vec(),
s3.verifying_key().as_bytes().to_vec(),
s4.verifying_key().as_bytes().to_vec(),
],
threshold: Some(2),
kind: None,
};

let mut name = Name {
name: "道".to_string(),
sequence: 0,
payload: Service {
code: 0,
operations: vec![Operation {
subcode: 1,
params: Value::from(&params),
}],
approver: None,
},
signatures: vec![],
};
assert!(name.validate().is_err());
name.sign(&params, ThresholdLevel::Single, &signers)
.unwrap();
assert!(name.validate().is_ok());
assert_eq!(1, name.signatures.len());
assert!(name.verify(&params, ThresholdLevel::Single).is_ok());
assert!(name.verify(&params, ThresholdLevel::Default).is_err());
assert!(name.verify(&params, ThresholdLevel::Strict).is_err());
assert!(name.verify(&params, ThresholdLevel::All).is_err());

name.sign(&params, ThresholdLevel::Default, &signers)
.unwrap();
assert!(name.validate().is_ok());
assert_eq!(2, name.signatures.len());
assert!(name.verify(&params, ThresholdLevel::Single).is_ok());
assert!(name.verify(&params, ThresholdLevel::Default).is_ok());
assert!(name.verify(&params, ThresholdLevel::Strict).is_err());
assert!(name.verify(&params, ThresholdLevel::All).is_err());

name.sign(&params, ThresholdLevel::Strict, &signers)
.unwrap();
assert!(name.validate().is_ok());
assert_eq!(3, name.signatures.len());
assert!(name.verify(&params, ThresholdLevel::Single).is_ok());
assert!(name.verify(&params, ThresholdLevel::Default).is_ok());
assert!(name.verify(&params, ThresholdLevel::Strict).is_ok());
assert!(name.verify(&params, ThresholdLevel::All).is_err());

name.sign(&params, ThresholdLevel::All, &signers).unwrap();
assert!(name.validate().is_ok());
assert_eq!(4, name.signatures.len());
assert!(name.verify(&params, ThresholdLevel::Single).is_ok());
assert!(name.verify(&params, ThresholdLevel::Default).is_ok());
assert!(name.verify(&params, ThresholdLevel::Strict).is_ok());
assert!(name.verify(&params, ThresholdLevel::All).is_ok());

assert!(
name.sign(&params, ThresholdLevel::All, &signers[1..])
.is_err(),
"signers less than ThresholdLevel::All"
);
assert!(name
.sign(&params, ThresholdLevel::Strict, &signers[1..])
.is_ok());
assert!(name.verify(&params, ThresholdLevel::Strict).is_ok());
assert!(name.verify(&params, ThresholdLevel::All).is_err());

signers[3] = s3.clone();
assert!(
name.sign(&params, ThresholdLevel::All, &signers).is_err(),
"depulicate signer"
);
assert!(name.sign(&params, ThresholdLevel::Strict, &signers).is_ok());
assert!(name.verify(&params, ThresholdLevel::Strict).is_ok());
assert!(name.verify(&params, ThresholdLevel::All).is_err());

signers[3] = ed25519::SigningKey::from_bytes(&secret_key());
assert!(
name.sign(&params, ThresholdLevel::All, &signers).is_err(),
"stranger signer"
);
assert!(name.sign(&params, ThresholdLevel::Strict, &signers).is_ok());
assert!(name.verify(&params, ThresholdLevel::Strict).is_ok());
assert!(name.verify(&params, ThresholdLevel::All).is_err());

signers[3] = s4.clone();
assert!(name.sign(&params, ThresholdLevel::All, &signers).is_ok());
assert!(name.verify(&params, ThresholdLevel::All).is_ok());
}
}
Loading

0 comments on commit b924133

Please sign in to comment.