Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
feat: support dob combination ring
  • Loading branch information
ashuralyk committed Jul 20, 2024
commit 9fcb078cb248023ad38f0d87e8b946e0af27205b
5 changes: 3 additions & 2 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ pub struct RpcClient {
}

impl RpcClient {
pub fn new(ckb_uri: &str, indexer_uri: &str) -> Self {
pub fn new(ckb_uri: &str, indexer_uri: Option<&str>) -> Self {
let indexer_uri = Url::parse(indexer_uri.unwrap_or(ckb_uri))
.expect("ckb uri, e.g. \"http://127.0.0.1:8116\"");
let ckb_uri = Url::parse(ckb_uri).expect("ckb uri, e.g. \"http://127.0.0.1:8114\"");
let indexer_uri = Url::parse(indexer_uri).expect("ckb uri, e.g. \"http://127.0.0.1:8116\"");

RpcClient {
raw: Client::new(),
Expand Down
30 changes: 23 additions & 7 deletions src/decoder/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use ckb_sdk::{constants::TYPE_ID_CODE_HASH, traits::CellQueryOptions};
use ckb_types::{
core::ScriptHashType,
packed::{OutPoint, Script},
prelude::{Builder, Entity, Pack},
prelude::{Builder, Entity, Pack, Unpack},
H256,
};
use serde_json::Value;
Expand Down Expand Up @@ -82,7 +82,7 @@ pub async fn fetch_dob_content(
rpc: &RpcClient,
settings: &Settings,
spore_id: [u8; 32],
) -> Result<((Value, String), [u8; 32]), Error> {
) -> Result<((Value, String), [u8; 32], H256), Error> {
let mut spore_cell = None;
for spore_search_option in build_batch_search_options(spore_id, &settings.available_spores) {
spore_cell = rpc
Expand All @@ -99,14 +99,25 @@ pub async fn fetch_dob_content(
let Some(spore_cell) = spore_cell else {
return Err(Error::SporeIdNotFound);
};
extract_dob_information(
spore_cell.output_data.unwrap_or_default().as_bytes(),
spore_cell.output.type_.unwrap().into(),
&settings.protocol_versions,
)
}

#[allow(clippy::type_complexity)]
pub fn extract_dob_information(
output_data: &[u8],
spore_type: Script,
protocol_versions: &[String],
) -> Result<((Value, String), [u8; 32], H256), Error> {
let molecule_spore_data =
SporeData::from_compatible_slice(spore_cell.output_data.unwrap_or_default().as_bytes())
.map_err(|_| Error::SporeDataUncompatible)?;
SporeData::from_compatible_slice(output_data).map_err(|_| Error::SporeDataUncompatible)?;
let content_type = String::from_utf8(molecule_spore_data.content_type().raw_data().to_vec())
.map_err(|_| Error::SporeDataContentTypeUncompatible)?;
if !content_type.is_empty()
&& !settings
.protocol_versions
&& !protocol_versions
.iter()
.any(|version| content_type.starts_with(version))
{
Expand All @@ -118,7 +129,12 @@ pub async fn fetch_dob_content(
.ok_or(Error::ClusterIdNotSet)?
.raw_data();
let dob_content = decode_spore_data(&molecule_spore_data.content().raw_data())?;
Ok((dob_content, cluster_id.to_vec().try_into().unwrap()))
let spore_type_hash = spore_type.calc_script_hash().unpack();
Ok((
dob_content,
cluster_id.to_vec().try_into().unwrap(),
spore_type_hash,
))
}

// search on-chain cluster cell and return its description field, which contains dob metadata
Expand Down
41 changes: 30 additions & 11 deletions src/decoder/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use ckb_types::H256;
use serde_json::Value;

use crate::{
Expand All @@ -19,7 +20,7 @@ pub struct DOBDecoder {
impl DOBDecoder {
pub fn new(settings: Settings) -> Self {
Self {
rpc: RpcClient::new(&settings.ckb_rpc, &settings.ckb_rpc),
rpc: RpcClient::new(&settings.ckb_rpc, None),
settings,
}
}
Expand All @@ -35,27 +36,34 @@ impl DOBDecoder {
pub async fn fetch_decode_ingredients(
&self,
spore_id: [u8; 32],
) -> Result<((Value, String), ClusterDescriptionField), Error> {
let (content, cluster_id) = fetch_dob_content(&self.rpc, &self.settings, spore_id).await?;
) -> Result<((Value, String), ClusterDescriptionField, H256), Error> {
let (content, cluster_id, type_hash) =
fetch_dob_content(&self.rpc, &self.settings, spore_id).await?;
let dob_metadata = fetch_dob_metadata(&self.rpc, &self.settings, cluster_id).await?;
Ok((content, dob_metadata))
Ok((content, dob_metadata, type_hash))
}

// decode DNA under target spore_id
pub async fn decode_dna(
&self,
dna: &str,
dob_metadata: ClusterDescriptionField,
spore_type_hash: H256,
) -> Result<String, Error> {
let dob = dob_metadata.unbox_dob()?;
match dob {
Dob::V0(dob0) => self.decode_dob0_dna(dna, dob0).await,
Dob::V1(dob1) => self.decode_dob1_dna(dna, dob1).await,
Dob::V0(dob0) => self.decode_dob0_dna(dna, dob0, spore_type_hash).await,
Dob::V1(dob1) => self.decode_dob1_dna(dna, dob1, spore_type_hash).await,
}
}

// decode specificly for objects under DOB/0 protocol
async fn decode_dob0_dna(&self, dna: &str, dob0: &DOBClusterFormatV0) -> Result<String, Error> {
async fn decode_dob0_dna(
&self,
dna: &str,
dob0: &DOBClusterFormatV0,
spore_type_hash: H256,
) -> Result<String, Error> {
let decoder_path = parse_decoder_path(&self.rpc, &dob0.decoder, &self.settings).await?;
let pattern = match &dob0.pattern {
Value::String(string) => string.to_owned(),
Expand All @@ -65,6 +73,8 @@ impl DOBDecoder {
let (exit_code, outputs) = crate::vm::execute_riscv_binary(
&decoder_path.to_string_lossy(),
vec![dna.to_owned().into(), pattern.into()],
spore_type_hash,
&self.settings,
)
.map_err(|_| Error::DecoderExecutionError)?;
#[cfg(feature = "render_debug")]
Expand All @@ -82,7 +92,12 @@ impl DOBDecoder {
}

// decode specificly for objects under DOB/1 protocol
async fn decode_dob1_dna(&self, dna: &str, dob1: &DOBClusterFormatV1) -> Result<String, Error> {
async fn decode_dob1_dna(
&self,
dna: &str,
dob1: &DOBClusterFormatV1,
spore_type_hash: H256,
) -> Result<String, Error> {
let mut output = Option::<Vec<StandardDOBOutput>>::None;
for (i, value) in dob1.decoders.iter().enumerate() {
let decoder_path =
Expand All @@ -103,9 +118,13 @@ impl DOBDecoder {
} else {
vec![dna.to_owned().into(), pattern.into()]
};
let (exit_code, outputs) =
crate::vm::execute_riscv_binary(&decoder_path.to_string_lossy(), args)
.map_err(|_| Error::DecoderExecutionError)?;
let (exit_code, outputs) = crate::vm::execute_riscv_binary(
&decoder_path.to_string_lossy(),
args,
spore_type_hash.clone(),
&self.settings,
)
.map_err(|_| Error::DecoderExecutionError)?;
#[cfg(feature = "render_debug")]
{
println!("\n-------- DOB/1 DECODE RESULT ({i} => {exit_code}) ---------");
Expand Down
8 changes: 6 additions & 2 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,12 @@ impl DecoderStandaloneServer {
spore_id: [u8; 32],
cache_path: PathBuf,
) -> Result<(String, Value), Error> {
let ((content, dna), metadata) = self.decoder.fetch_decode_ingredients(spore_id).await?;
let render_output = self.decoder.decode_dna(&dna, metadata).await?;
let ((content, dna), metadata, spore_type_hash) =
self.decoder.fetch_decode_ingredients(spore_id).await?;
let render_output = self
.decoder
.decode_dna(&dna, metadata, spore_type_hash)
.await?;
write_dob_to_cache(&render_output, &content, cache_path, self.cache_expiration)?;
Ok((render_output, content))
}
Expand Down
8 changes: 4 additions & 4 deletions src/tests/dob0/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ fn generate_example_dob_ingredients(onchain_decoder: bool) -> (Value, ClusterDes
async fn test_fetch_and_decode_unicorn_dna() {
let settings = prepare_settings("text/plain");
let decoder = DOBDecoder::new(settings);
let ((_, dna), dob_metadata) = decoder
let ((_, dna), dob_metadata, type_hash) = decoder
.fetch_decode_ingredients(UNICORN_SPORE_ID.into())
.await
.expect("fetch");
let render_result = decoder
.decode_dna(&dna, dob_metadata)
.decode_dna(&dna, dob_metadata, type_hash)
// array type
.await
.expect("decode");
Expand All @@ -117,12 +117,12 @@ fn test_unicorn_json_serde() {
async fn test_fetch_and_decode_example_dna() {
let settings = prepare_settings("text/plain");
let decoder = DOBDecoder::new(settings);
let ((_, dna), dob_metadata) = decoder
let ((_, dna), dob_metadata, type_hash) = decoder
.fetch_decode_ingredients(EXAMPLE_SPORE_ID.into())
.await
.expect("fetch");
let render_result = decoder
.decode_dna(&dna, dob_metadata)
.decode_dna(&dna, dob_metadata, type_hash)
// array type
.await
.expect("decode");
Expand Down
7 changes: 4 additions & 3 deletions src/tests/dob0/legacy_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,9 @@ async fn decode_unicorn_dna(onchain_decoder: bool) -> String {
let settings = prepare_settings("text/plain");
let decoder = DOBDecoder::new(settings);
let (unicorn_content, unicorn_metadata) = generate_unicorn_dob_ingredients(onchain_decoder);
let dna = unicorn_content["dna"].as_str().unwrap();
decoder
.decode_dna(&unicorn_content["dna"].as_str().unwrap(), unicorn_metadata)
.decode_dna(dna, unicorn_metadata, Default::default())
.await
.expect("decode")
}
Expand All @@ -101,12 +102,12 @@ async fn test_decode_unicorn_dna() {
async fn test_fetch_and_decode_nervape_dna() {
let settings = prepare_settings("text/plain");
let decoder = DOBDecoder::new(settings);
let ((_, dna), dob_metadata) = decoder
let ((_, dna), dob_metadata, type_hash) = decoder
.fetch_decode_ingredients(NERVAPE_SPORE_ID.into())
.await
.expect("fetch");
let render_result = decoder
.decode_dna(&dna, dob_metadata)
.decode_dna(&dna, dob_metadata, type_hash)
// array type
.await
.expect("decode");
Expand Down
5 changes: 4 additions & 1 deletion src/tests/dob1/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ async fn test_dob1_basic_decode() {
let (content, dob_metadata) = generate_dob1_ingredients();
let decoder = DOBDecoder::new(settings);
let dna = content.get("dna").unwrap().as_str().unwrap();
let render_result = decoder.decode_dna(dna, dob_metadata).await.expect("decode");
let render_result = decoder
.decode_dna(dna, dob_metadata, Default::default())
.await
.expect("decode");
println!("\nrender_result: {}", render_result);
}
8 changes: 8 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ pub enum Error {
DecoderScriptNotFound,
#[error("decoder chain list cannot be empty")]
DecoderChainIsEmpty,
#[error("DOB ring broken with disconnected outpoint pointer")]
CellOutputNotFound,
#[error("invalid DOB spore cell")]
InvalidDOBCell,
#[error("DOB ring broken with invalid ring pointer")]
InvalidNextDobRingPointer,
#[error("DOB ring is not a circle")]
DobRingUncirclelized,
}

pub enum Dob<'a> {
Expand Down
Loading