Skip to content

Commit

Permalink
feat: improve state data struct (must rebuild inscription chain)
Browse files Browse the repository at this point in the history
  • Loading branch information
zensh committed Jan 8, 2024
1 parent c36029a commit abe3d29
Show file tree
Hide file tree
Showing 15 changed files with 799 additions and 280 deletions.
4 changes: 2 additions & 2 deletions crates/ns-fetcher/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ns-fetcher"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
rust-version = "1.64"
description = "Fetch and validate inscriptions from ns-indexer service"
Expand All @@ -11,7 +11,7 @@ license = "CC0-1.0"
[lib]

[dependencies]
ns-protocol = { path = "../ns-protocol", version = "0.6" }
ns-protocol = { path = "../ns-protocol", version = "0.7" }
anyhow = { workspace = true }
bytes = { workspace = true }
base64 = { workspace = true }
Expand Down
1 change: 1 addition & 0 deletions crates/ns-fetcher/src/fetcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub fn fetch_desc(

head_height -= 1;
let inscription: Inscription = cli.get_inscription_by_height(head_height).await?;

if head_inscription.previous_hash != inscription.hash()? {
Err(anyhow::anyhow!("inscription({}): previous hash mismatch", inscription.height))?;
}
Expand Down
4 changes: 2 additions & 2 deletions crates/ns-indexer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ns-indexer"
version = "0.4.1"
version = "0.5.0"
edition = "2021"
rust-version = "1.64"
description = "Name & Service Protocol indexer service in Rust"
Expand All @@ -15,7 +15,7 @@ name = "ns-indexer"
path = "src/bin/main.rs"

[dependencies]
ns-protocol = { path = "../ns-protocol", version = "0.6" }
ns-protocol = { path = "../ns-protocol", version = "0.7" }
ns-axum-web = { path = "../ns-axum-web", version = "0.1" }
ns-scylla-orm = { path = "../ns-scylla-orm", version = "0.1" }
ns-scylla-orm-macros = { path = "../ns-scylla-orm-macros", version = "0.1" }
Expand Down
6 changes: 4 additions & 2 deletions crates/ns-indexer/src/api/name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use ns_axum_web::{
erring::{HTTPError, SuccessResponse},
object::PackObject,
};
use ns_protocol::state::NameState;
use ns_protocol::{ns, state::NameState};

use crate::api::{IndexerAPI, QueryName, QueryPubkey};
use crate::db;
Expand Down Expand Up @@ -130,10 +130,12 @@ impl NameAPI {
};
let pubkey = hex::decode(key)
.map_err(|_| HTTPError::new(400, format!("Invalid pubkey: {}", input.pubkey)))?;
let pubkey =
ns::Bytes32::try_from(&pubkey).map_err(|e| HTTPError::new(400, e.to_string()))?;
ctx.set_kvs(vec![("action", "list_names_by_pubkey".into())])
.await;

let mut names = db::NameState::list_by_pubkey(&app.scylla, pubkey.to_vec()).await?;
let mut names = db::NameState::list_by_pubkey(&app.scylla, pubkey).await?;
names.sort();
Ok(to.with(SuccessResponse::new(names)))
}
Expand Down
38 changes: 21 additions & 17 deletions crates/ns-indexer/src/db/model_inscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use ns_axum_web::erring::HTTPError;
use ns_scylla_orm::{ColumnsMap, CqlValue, ToCqlVal};
use ns_scylla_orm_macros::CqlOrm;

use ns_protocol::state;
use ns_protocol::{ns::Bytes32, state};

use crate::db::{self, scylladb, scylladb::filter_single_row_err};

Expand Down Expand Up @@ -150,13 +150,17 @@ impl Inscription {
sequence: value.sequence as i64,
height: value.height as i64,
name_height: value.name_height as i64,
previous_hash: value.previous_hash.clone(),
name_hash: value.name_hash.clone(),
service_hash: value.service_hash.clone(),
protocol_hash: value.protocol_hash.as_ref().unwrap_or(&vec![]).clone(),
block_hash: value.block_hash.clone(),
previous_hash: (&value.previous_hash).into(),
name_hash: (&value.name_hash).into(),
service_hash: (&value.service_hash).into(),
protocol_hash: value
.protocol_hash
.as_ref()
.map(|v| v.into())
.unwrap_or_default(),
block_hash: (&value.block_hash).into(),
block_height: value.block_height as i64,
txid: value.txid.clone(),
txid: (&value.txid).into(),
vin: value.vin as i8,
data,
_fields: Self::fields(),
Expand All @@ -170,28 +174,28 @@ impl Inscription {
sequence: self.sequence as u64,
height: self.height as u64,
name_height: self.name_height as u64,
previous_hash: self.previous_hash.clone(),
name_hash: self.name_hash.clone(),
service_hash: self.service_hash.clone(),
previous_hash: (&self.previous_hash).try_into()?,
name_hash: (&self.name_hash).try_into()?,
service_hash: (&self.service_hash).try_into()?,
protocol_hash: if self.protocol_hash.is_empty() {
None
} else {
Some(self.protocol_hash.clone())
Some((&self.protocol_hash).try_into()?)
},
block_hash: self.block_hash.clone(),
block_hash: (&self.block_hash).try_into()?,
block_height: self.block_height as u64,
txid: self.txid.clone(),
txid: (&self.txid).try_into()?,
vin: self.vin as u8,
data,
})
}

pub fn to_checkpoint(&self, hash: Vec<u8>) -> anyhow::Result<Checkpoint> {
pub fn to_checkpoint(&self, hash: Bytes32) -> anyhow::Result<Checkpoint> {
Ok(Checkpoint {
checkpoint: Checkpoint::LAST_ACCEPTED.to_string(),
block_height: self.block_height,
height: self.height,
hash,
hash: hash.into(),
name: self.name.clone(),
sequence: self.sequence,
_fields: Checkpoint::fields(),
Expand Down Expand Up @@ -510,7 +514,7 @@ impl InvalidInscription {
Ok(Self {
name: value.name.clone(),
block_height: value.block_height as i64,
hash: value.hash.clone(),
hash: (&value.hash).into(),
reason: value.reason.clone(),
data,
_fields: Self::fields(),
Expand All @@ -522,7 +526,7 @@ impl InvalidInscription {
Ok(state::InvalidInscription {
name: self.name.clone(),
block_height: self.block_height as u64,
hash: self.hash.clone(),
hash: (&self.hash).try_into()?,
reason: self.reason.clone(),
data,
})
Expand Down
25 changes: 11 additions & 14 deletions crates/ns-indexer/src/db/model_name_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use ns_scylla_orm::{ColumnsMap, CqlValue, ToCqlVal};
use ns_scylla_orm_macros::CqlOrm;
use std::collections::{BTreeMap, HashSet};

use ns_protocol::state;
use ns_protocol::{ns::Bytes32, state};

use crate::db::scylladb;

Expand Down Expand Up @@ -57,8 +57,8 @@ impl NameState {
expire_time: value.expire_time as i64,
threshold: value.threshold as i8,
key_kind: value.key_kind as i8,
public_keys: value.public_keys.clone(),
next_public_keys: value.next_public_keys.as_ref().unwrap_or(&vec![]).clone(),
public_keys: Bytes32::vec_into(&value.public_keys),
next_public_keys: Bytes32::vec_into(value.next_public_keys.as_ref().unwrap_or(&vec![])),
_fields: Self::fields(),
})
}
Expand All @@ -73,11 +73,11 @@ impl NameState {
expire_time: self.expire_time as u64,
threshold: self.threshold as u8,
key_kind: self.key_kind as u8,
public_keys: self.public_keys.clone(),
public_keys: Bytes32::vec_try_from(&self.public_keys)?,
next_public_keys: if self.next_public_keys.is_empty() {
None
} else {
Some(self.next_public_keys.clone())
Some(Bytes32::vec_try_from(&self.next_public_keys)?)
},
})
}
Expand Down Expand Up @@ -211,7 +211,7 @@ impl NameState {

pub async fn batch_remove_pubkey_names(
db: &scylladb::ScyllaDB,
pubkey_names: HashSet<(Vec<u8>, String)>,
pubkey_names: HashSet<(Bytes32, String)>,
) -> anyhow::Result<()> {
let mut statements: Vec<&str> = Vec::with_capacity(pubkey_names.len());
let mut values: Vec<(Vec<u8>, String)> = Vec::with_capacity(pubkey_names.len());
Expand All @@ -220,7 +220,7 @@ impl NameState {
let query = "DELETE FROM pubkey_name WHERE pubk=? AND name=?";
for state in pubkey_names {
statements.push(query);
values.push((state.0, state.1));
values.push((state.0.to_vec(), state.1));
}
let _ = db
.batch(scylladb::BatchType::Unlogged, statements, values)
Expand All @@ -230,7 +230,7 @@ impl NameState {

pub async fn batch_add_pubkey_names(
db: &scylladb::ScyllaDB,
pubkey_names: HashSet<(Vec<u8>, String)>,
pubkey_names: HashSet<(Bytes32, String)>,
) -> anyhow::Result<()> {
let mut statements: Vec<&str> = Vec::with_capacity(pubkey_names.len());
let mut values: Vec<(Vec<u8>, String)> = Vec::with_capacity(pubkey_names.len());
Expand All @@ -250,7 +250,7 @@ impl NameState {
);
for state in pubkey_names {
statements.push(query.as_str());
values.push((state.0, state.1));
values.push((state.0.to_vec(), state.1));
}
let _ = db
.batch(scylladb::BatchType::Unlogged, statements, values)
Expand Down Expand Up @@ -283,15 +283,12 @@ impl NameState {

pub async fn list_by_pubkey(
db: &scylladb::ScyllaDB,
pubkey: Vec<u8>,
pubkey: Bytes32,
) -> anyhow::Result<Vec<String>> {
let fields = vec!["name".to_string()];
if pubkey.len() != 32 {
return Ok(vec![]);
}

let query = "SELECT name FROM pubkey_name WHERE pubkey=?";
let params = (pubkey,);
let params = (pubkey.to_vec(),);
let rows = db.execute_iter(query, params).await?;

let mut res: Vec<PubkeyName> = Vec::with_capacity(rows.len());
Expand Down
14 changes: 9 additions & 5 deletions crates/ns-indexer/src/envelope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,23 @@ mod tests {
use hex_literal::hex;
use ns_protocol::{
ed25519,
ns::{Operation, PublicKeyParams, Service, ThresholdLevel},
ns::{Bytes32, Operation, PublicKeyParams, Service, ThresholdLevel},
};

#[test]
fn names_from_witness() {
let secret_key = hex!("7ef3811aabb916dc2f646ef1a371b90adec91bc07992cd4d44c156c42fc1b300");
let public_key = hex!("ee90735ac719e85dc2f3e5974036387fdf478af7d9d1f8480e97eee601890266");
let secret_key = Bytes32(hex!(
"7ef3811aabb916dc2f646ef1a371b90adec91bc07992cd4d44c156c42fc1b300"
));
let public_key = Bytes32(hex!(
"ee90735ac719e85dc2f3e5974036387fdf478af7d9d1f8480e97eee601890266"
));
let params = PublicKeyParams {
public_keys: vec![public_key.to_vec()],
public_keys: vec![public_key],
threshold: Some(1),
kind: None,
};
let signer = ed25519::SigningKey::try_from(&secret_key).unwrap();
let signer = ed25519::SigningKey::from_bytes(&secret_key.0);
let signers = vec![signer];

let mut name1 = Name {
Expand Down
37 changes: 20 additions & 17 deletions crates/ns-indexer/src/indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use tokio::{
};

use ns_protocol::{
ns::{Name, PublicKeyParams, ThresholdLevel},
ns::{self, Bytes32, Name, PublicKeyParams, ThresholdLevel},
state::{
hash_sha3, Inscription, InvalidInscription, NameState, ServiceProtocol, ServiceState,
NAME_EXPIRE_SECONDS, NAME_STALE_SECONDS,
Expand Down Expand Up @@ -201,15 +201,15 @@ impl Indexer {
let mut inscription = Inscription {
name: name.name.clone(),
sequence: name.sequence,
height: 0,
name_height: 0,
previous_hash: vec![],
height: 1,
name_height: 1,
previous_hash: Bytes32::default(),
name_hash: name_state_hash,
service_hash: service_state_hash,
protocol_hash: service_protocol_hash,
block_hash: block_hash.to_byte_array().to_vec(),
block_hash: block_hash.to_byte_array().into(),
block_height,
txid: envelope.txid.to_byte_array().to_vec(),
txid: envelope.txid.to_byte_array().into(),
vin: envelope.vin,
data: name,
};
Expand Down Expand Up @@ -242,10 +242,7 @@ impl Indexer {
.expect("hash_sha3(inscription) should not fail");
}
None => {
// this is the first inscription
inscription.height = 1;
inscription.name_height = 1;
inscription.previous_hash = [0u8; 32].to_vec();
// this is the first inscription, no thing to do
}
},
}
Expand All @@ -272,7 +269,7 @@ impl Indexer {
block_height: u64,
block_time: u64,
name: &Name,
) -> anyhow::Result<(Vec<u8>, Vec<u8>, Option<Vec<u8>>)> {
) -> anyhow::Result<(Bytes32, Bytes32, Option<Bytes32>)> {
name.validate()?;
// default protocol is Name service
let mut service_protocol = ServiceProtocol::default();
Expand Down Expand Up @@ -491,11 +488,11 @@ impl Indexer {
}

let mut fresh_name_index: BTreeMap<String, u64> = BTreeMap::new();
let mut fresh_name_with_public_keys: HashSet<(String, Vec<Vec<u8>>)> = HashSet::new();
let mut captured_name_with_public_keys: HashSet<(String, Vec<Vec<u8>>)> = HashSet::new();
let mut stale_name_with_public_keys: HashSet<(String, Vec<Vec<u8>>)> = HashSet::new();
let mut fresh_pubkey_names: HashSet<(Vec<u8>, String)> = HashSet::new();
let mut stale_pubkey_names: HashSet<(Vec<u8>, String)> = HashSet::new();
let mut fresh_name_with_public_keys: HashSet<(String, Vec<Bytes32>)> = HashSet::new();
let mut captured_name_with_public_keys: HashSet<(String, Vec<Bytes32>)> = HashSet::new();
let mut stale_name_with_public_keys: HashSet<(String, Vec<Bytes32>)> = HashSet::new();
let mut fresh_pubkey_names: HashSet<(Bytes32, String)> = HashSet::new();
let mut stale_pubkey_names: HashSet<(Bytes32, String)> = HashSet::new();
if !inscriptions.is_empty() {
for name in &name_states {
fresh_name_index.insert(name.name.clone(), name.block_time);
Expand All @@ -508,7 +505,13 @@ impl Indexer {
)
.await?;
for npk in npks {
captured_name_with_public_keys.insert((npk.name.clone(), npk.public_keys.clone()));
captured_name_with_public_keys.insert((
npk.name.clone(),
npk.public_keys
.iter()
.map(Bytes32::try_from)
.collect::<anyhow::Result<Vec<Bytes32>, ns::Error>>()?,
));
}
for npk in &captured_name_with_public_keys {
if fresh_name_with_public_keys.contains(npk) {
Expand Down
2 changes: 1 addition & 1 deletion crates/ns-indexer/src/utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl UTXO {
.input
.iter()
.map(|txin| UTXO {
txid: txin.previous_output.txid.to_byte_array().to_vec(),
txid: txin.previous_output.txid.to_byte_array().into(),
vout: txin.previous_output.vout,
amount: 0,
})
Expand Down
6 changes: 3 additions & 3 deletions crates/ns-inscriber/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ns-inscriber"
version = "0.3.0"
version = "0.4.0"
edition = "2021"
rust-version = "1.64"
description = "Name & Service Protocol inscriber service in Rust"
Expand All @@ -15,8 +15,8 @@ name = "ns-inscriber"
path = "src/bin/main.rs"

[dependencies]
ns-protocol = { path = "../ns-protocol", version = "0.6" }
ns-indexer = { path = "../ns-indexer", version = "0.4" }
ns-protocol = { path = "../ns-protocol", version = "0.7" }
ns-indexer = { path = "../ns-indexer", version = "0.5" }
anyhow = { workspace = true }
bytes = { workspace = true }
base64 = { workspace = true }
Expand Down
Loading

0 comments on commit abe3d29

Please sign in to comment.