diff --git a/Cargo.lock b/Cargo.lock index f1cc900..d031500 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,6 +14,12 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f0d2da64a6a895d5a7e0724882825d50f83c13396b1b9f1878e19a024bab395" +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + [[package]] name = "cc" version = "1.0.83" @@ -102,9 +108,8 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "molecule" version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd9767ab5e5f2ea40f71ff4c8bdb633c50509052e093c2fdd0e390a749dfa3" dependencies = [ + "bytes", "cfg-if", ] diff --git a/Cargo.toml b/Cargo.toml index db63d65..c8ad18c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,6 @@ opt-level = 1 debug = false panic = 'abort' debug-assertions = true + +[patch.crates-io] +molecule = { path = "../molecule/bindings/rust" } diff --git a/Makefile b/Makefile index f73d01e..fc94af8 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,13 @@ mol: moleculec --language rust --schema-file schemas/top_level.mol > ckb-transaction-cobuild/src/schemas/top_level.rs cargo fmt +mol2: + moleculec --language rust-lazy-reader --schema-file schemas/basic.mol > ckb-transaction-cobuild/src/schemas2/basic.rs + moleculec --language rust-lazy-reader --schema-file schemas/top_level.mol > ckb-transaction-cobuild/src/schemas2/top_level.rs + moleculec --language rust-lazy-reader --schema-file schemas/blockchain.mol > ckb-transaction-cobuild/src/schemas2/blockchain.rs + cargo fmt + + install: rustup target add riscv64imac-unknown-none-elf cargo install cross --git https://github.com/cross-rs/cross diff --git a/ckb-transaction-cobuild/Cargo.toml b/ckb-transaction-cobuild/Cargo.toml index aee8fbe..376e010 100644 --- a/ckb-transaction-cobuild/Cargo.toml +++ b/ckb-transaction-cobuild/Cargo.toml @@ -12,5 +12,5 @@ log = [] [dependencies] blake2b-ref = "0.3.1" ckb-std = { version = "0.14.3", default-features = false, features = ["ckb-types"] } -molecule = { version = "0.7.5", default-features = false } +molecule = { version = "0.7.5", default-features = false, features = ["bytes_vec"] } ckb-gen-types = { version = "0.111.0", default-features = false } diff --git a/ckb-transaction-cobuild/src/blake2b.rs b/ckb-transaction-cobuild/src/blake2b.rs index 8be1677..6a2ba9e 100644 --- a/ckb-transaction-cobuild/src/blake2b.rs +++ b/ckb-transaction-cobuild/src/blake2b.rs @@ -1,9 +1,12 @@ pub use blake2b_ref::{Blake2b, Blake2bBuilder}; +pub use molecule::lazy_reader::Cursor; pub const PERSONALIZATION_SIGHASH_ALL: &[u8] = b"ckb-tcob-sighash"; pub const PERSONALIZATION_SIGHASH_ALL_ONLY: &[u8] = b"ckb-tcob-sgohash"; pub const PERSONALIZATION_OTX: &[u8] = b"ckb-tcob-otxhash"; +const BATCH_SIZE: usize = 2048; + /// return a blake2b instance with personalization for SighashAll pub fn new_sighash_all_blake2b() -> Blake2bStatistics { Blake2bStatistics::new( @@ -45,6 +48,16 @@ impl Blake2bStatistics { self.blake2b.update(data); self.count += data.len(); } + pub fn update_cursor(&mut self, mut cursor: Cursor) { + let mut buf = [0u8; BATCH_SIZE]; + while cursor.size > 0 { + let read_len = cursor.read_at(&mut buf).unwrap(); + if read_len > 0 { + self.blake2b.update(&buf[0..read_len]); + cursor = cursor.slice_by_start(read_len).unwrap(); + } + } + } pub fn finalize(self, dst: &mut [u8]) { self.blake2b.finalize(dst) diff --git a/ckb-transaction-cobuild/src/error.rs b/ckb-transaction-cobuild/src/error.rs new file mode 100644 index 0000000..d8723b2 --- /dev/null +++ b/ckb-transaction-cobuild/src/error.rs @@ -0,0 +1,36 @@ +use ckb_std::error::SysError; +use molecule::error::VerificationError; +use molecule::lazy_reader::Error as LazyReaderError; + +#[derive(Debug)] +pub enum Error { + Sys(SysError), + LazyReader(LazyReaderError), + MoleculeEncoding, + WrongSighashAll, + WrongWitnessLayout, + WrongOtxStart, + WrongOtx, + NoSealFound, + AuthError, + ScriptHashAbsent, + WrongCount, +} + +impl From for Error { + fn from(e: SysError) -> Self { + Error::Sys(e) + } +} + +impl From for Error { + fn from(_: VerificationError) -> Self { + Error::MoleculeEncoding + } +} + +impl From for Error { + fn from(e: LazyReaderError) -> Self { + Error::LazyReader(e) + } +} diff --git a/ckb-transaction-cobuild/src/lazy_reader.rs b/ckb-transaction-cobuild/src/lazy_reader.rs new file mode 100644 index 0000000..1bd60b3 --- /dev/null +++ b/ckb-transaction-cobuild/src/lazy_reader.rs @@ -0,0 +1,56 @@ +use core::cmp::min; + +use alloc::boxed::Box; +use ckb_std::{error::SysError, syscalls}; +use molecule::lazy_reader::{Cursor, Error, Read}; + +use crate::log; + +pub struct TransactionReader { + pub total_length: usize, +} + +impl TransactionReader { + pub fn new() -> Self { + let mut buf = [0u8; 4]; + let result = syscalls::load_transaction(&mut buf, 0); + let total_length = match result { + Ok(l) => l, + Err(e) => match e { + SysError::LengthNotEnough(l) => l, + _ => panic!("error on load_transaction"), + }, + }; + Self { total_length } + } +} + +impl Read for TransactionReader { + fn read(&self, buf: &mut [u8], offset: usize) -> Result { + log!( + "try to read {} bytes into buffer with offset {}", + buf.len(), + offset + ); + if offset >= self.total_length { + return Err(Error::OutOfBound(offset, self.total_length)); + } + + let remaining_len = self.total_length - offset; + let min_len = min(remaining_len, buf.len()); + + if (offset + min_len) > self.total_length { + return Err(Error::OutOfBound(offset + min_len, self.total_length)); + } + let actual_len = syscalls::load_transaction(buf, offset).map_err(|_| Error::Common)?; + let read_len = min(buf.len(), actual_len); + log!("totally read {} bytes", read_len); + Ok(read_len) + } +} + +impl From for Cursor { + fn from(data: TransactionReader) -> Self { + Cursor::new(data.total_length, Box::new(data)) + } +} diff --git a/ckb-transaction-cobuild/src/lib.rs b/ckb-transaction-cobuild/src/lib.rs index 64f3e25..9dd4532 100644 --- a/ckb-transaction-cobuild/src/lib.rs +++ b/ckb-transaction-cobuild/src/lib.rs @@ -1,8 +1,11 @@ #![no_std] extern crate alloc; pub mod blake2b; +pub mod error; +pub mod lazy_reader; pub mod log; pub mod schemas; +pub mod schemas2; use alloc::{collections::BTreeSet, vec::Vec}; use blake2b::{new_otx_blake2b, new_sighash_all_blake2b, new_sighash_all_only_blake2b}; @@ -16,9 +19,12 @@ use ckb_std::{ load_transaction, load_tx_hash, load_witness, QueryIter, }, }; +use error::Error; +use schemas2::{basic, blockchain, top_level}; + use core::convert::Into; use molecule::{ - error::VerificationError, + lazy_reader::Cursor, prelude::{Entity, Reader}, NUMBER_SIZE, }; @@ -27,32 +33,6 @@ use schemas::{ top_level::{WitnessLayout, WitnessLayoutReader, WitnessLayoutUnion, WitnessLayoutUnionReader}, }; -#[derive(Eq, PartialEq, Debug, Clone, Copy)] -pub enum Error { - Sys(SysError), - MoleculeEncoding, - WrongSighashAll, - WrongWitnessLayout, - WrongOtxStart, - WrongOtx, - NoSealFound, - AuthError, - ScriptHashAbsent, - WrongCount, -} - -impl From for Error { - fn from(e: SysError) -> Self { - Error::Sys(e) - } -} - -impl From for Error { - fn from(_: VerificationError) -> Self { - Error::MoleculeEncoding - } -} - /// /// This is the callback trait should be implemented in lock script by /// developers. @@ -217,15 +197,39 @@ pub fn parse_witness_layouts(tx: &Transaction) -> (Vec>, b (witness_layouts, activated) } +pub fn parse_witness_layouts2( + tx: &blockchain::Transaction, +) -> (Vec>, bool) { + let witness_layouts: Vec> = tx + .witnesses() + .unwrap() + .into_iter() + .map(|w| top_level::WitnessLayout::try_from(w).ok()) + .collect(); + for w in &witness_layouts { + if let Some(w2) = w { + w2.verify(false).unwrap(); + } + } + let activated = witness_layouts.iter().any(|w| w.is_some()); + (witness_layouts, activated) +} + /// /// verify all otx messages with the given script hash and verify function /// This function is mainly used by lock script /// pub fn cobuild_entry(verifier: F) -> Result { + let tx_reader = lazy_reader::TransactionReader::new(); + let cursor: Cursor = tx_reader.into(); + let lazy_tx = blockchain::Transaction::from(cursor); + let tx = load_transaction()?; let raw_tx = tx.raw(); let (witness_layouts, cobuild_activated) = parse_witness_layouts(&tx); + let (witness_layouts2, cobuild_activated2) = parse_witness_layouts2(&lazy_tx); + assert_eq!(cobuild_activated, cobuild_activated2); // Legacy Flow Handling if !cobuild_activated { return Ok(false); @@ -235,6 +239,9 @@ pub fn cobuild_entry(verifier: F) -> Result { // step 2 // step 4 let (otx_start, i) = fetch_otx_start()?; + let (otx_start2, i2) = fetch_otx_start2(&witness_layouts2)?; + assert_eq!(i, i2); + assert_eq!(otx_start.is_none(), otx_start2.is_none()); if otx_start.is_none() { // step 3 log!("No otx detected"); @@ -242,12 +249,21 @@ pub fn cobuild_entry(verifier: F) -> Result { return Ok(true); } let otx_start = otx_start.unwrap(); + let otx_start2 = otx_start2.unwrap(); let start_input_cell: u32 = otx_start.start_input_cell().unpack(); let start_output_cell: u32 = otx_start.start_output_cell().unpack(); let start_cell_deps: u32 = otx_start.start_cell_deps().unpack(); let start_header_deps: u32 = otx_start.start_header_deps().unpack(); + let start_input_cell2: u32 = otx_start2.start_input_cell().unwrap(); + let start_output_cell2: u32 = otx_start2.start_output_cell().unwrap(); + let start_cell_deps2: u32 = otx_start2.start_cell_deps().unwrap(); + let start_header_deps2: u32 = otx_start2.start_header_deps().unwrap(); + assert_eq!(start_input_cell, start_input_cell2); + assert_eq!(start_output_cell, start_output_cell2); + assert_eq!(start_cell_deps, start_cell_deps2); + assert_eq!(start_header_deps, start_header_deps2); // abbrev. from spec: // ie = input end // is = input start @@ -466,6 +482,91 @@ fn generate_otx_smh( Ok(result) } +// TODO +/// generate OTX signing message hash +// fn generate_otx_smh2( +// otx: &schemas2::basic::Otx, +// raw_tx: &blockchain::RawTransaction, +// ie: usize, +// oe: usize, +// ce: usize, +// he: usize, +// ) -> Result<[u8; 32], Error> { +// log!("ie = {}, oe = {}, ce = {}, he = {}", ie, oe, ce, he); +// let input_cells: u32 = otx.input_cells()?; +// let output_cells: u32 = otx.output_cells()?; +// let cell_deps: u32 = otx.cell_deps()?; +// let header_deps: u32 = otx.header_deps()?; + +// let mut hasher = new_otx_blake2b(); +// hasher.update_cursor(otx.message()?.cursor.clone()); +// hasher.update(&input_cells.to_le_bytes()); +// let input_iter = raw_tx +// .inputs() +// .into_iter() +// .skip(ie) +// .zip(QueryIter::new(load_cell, Source::Input).skip(ie)) +// .zip(QueryIter::new(load_cell_data, Source::Input).skip(ie)); +// let mut count = 0; +// for ((input, input_cell), input_cell_data) in input_iter.take(input_cells as usize) { +// hasher.update(input.as_slice()); +// hasher.update(input_cell.as_slice()); +// hasher.update(&(input_cell_data.len() as u32).to_le_bytes()); +// hasher.update(&input_cell_data); +// count += 1; +// } +// // It's important to verify count. Consider the scenario that the all +// // count(input_cells, output_cells, cell_deps, header_deps) are zero due to +// // `iterator::take` method. The hash result can be a predictable. +// if count != input_cells { +// return Err(Error::WrongCount); +// } +// hasher.update(&output_cells.to_le_bytes()); +// let output_iter = raw_tx +// .outputs() +// .into_iter() +// .skip(oe) +// .zip(raw_tx.outputs_data().into_iter().skip(oe)); +// let mut count = 0; +// for (output_cell, output_cell_data) in output_iter.take(output_cells as usize) { +// hasher.update(output_cell.as_slice()); +// hasher.update(output_cell_data.as_slice()); +// count += 1; +// } +// if count != output_cells { +// return Err(Error::WrongCount); +// } +// hasher.update(&cell_deps.to_le_bytes()); +// let cell_dep_iter = raw_tx.cell_deps().into_iter().skip(ce); +// let mut count = 0; +// for cell_dep in cell_dep_iter.take(cell_deps as usize) { +// hasher.update(cell_dep.as_slice()); +// count += 1; +// } +// if count != cell_deps { +// return Err(Error::WrongCount); +// } +// hasher.update(&header_deps.to_le_bytes()); +// let header_dep_iter = raw_tx.header_deps().into_iter().skip(he); +// let mut count = 0; +// for header_dep in header_dep_iter.take(header_deps as usize) { +// hasher.update(header_dep.as_slice()); +// count += 1; +// } +// if count != header_deps { +// return Err(Error::WrongCount); +// } +// let mut result = [0u8; 32]; +// let count = hasher.count(); +// hasher.finalize(&mut result); +// log!( +// "generate_otx_smh totally hashed {} bytes and hash is {:?}", +// count, +// result +// ); +// Ok(result) +// } + fn fetch_otx_start() -> Result<(Option, usize), Error> { let mut otx_start = None; let mut start_index = 0; @@ -512,3 +613,53 @@ fn fetch_otx_start() -> Result<(Option, usize), Error> { Ok((None, 0)) } } + +fn fetch_otx_start2( + witnesses: &Vec>, +) -> Result<(Option, usize), Error> { + let mut otx_start = None; + let mut start_index = 0; + let mut end_index = 0; + + for (i, witness) in witnesses.iter().enumerate() { + if let Some(witness_layout) = witness { + match witness_layout { + top_level::WitnessLayout::OtxStart(start) => { + if otx_start.is_none() { + otx_start = Some(start.cursor.clone().into()); + start_index = i; + end_index = i; + } else { + log!("Duplicated OtxStart found"); + return Err(Error::WrongWitnessLayout); + } + } + top_level::WitnessLayout::Otx(_) => { + if otx_start.is_none() { + log!("A Otx without OtxStart found"); + return Err(Error::WrongWitnessLayout); + } else { + if end_index + 1 != i { + log!("Otx are not continuous"); + return Err(Error::WrongWitnessLayout); + } else { + end_index = i; + } + } + } + _ => {} + } + } + } + + if otx_start.is_some() { + if end_index > 0 { + return Ok((otx_start, start_index)); + } else { + log!("end_index == 0, there is no OTX"); + return Err(Error::WrongOtxStart); + } + } else { + Ok((None, 0)) + } +} diff --git a/ckb-transaction-cobuild/src/schemas/basic.rs b/ckb-transaction-cobuild/src/schemas/basic.rs index 117b595..4a11f77 100644 --- a/ckb-transaction-cobuild/src/schemas/basic.rs +++ b/ckb-transaction-cobuild/src/schemas/basic.rs @@ -348,6 +348,7 @@ impl<'r> molecule::prelude::Reader<'r> for HashReader<'r> { Ok(()) } } +#[derive(Clone)] pub struct HashBuilder(pub(crate) [Byte; 32]); impl ::core::fmt::Debug for HashBuilder { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { @@ -577,6 +578,87 @@ impl molecule::prelude::Builder for HashBuilder { Hash::new_unchecked(inner.into()) } } +impl From<[Byte; 32usize]> for Hash { + fn from(value: [Byte; 32usize]) -> Self { + Self::new_builder().set(value).build() + } +} +impl ::core::convert::TryFrom<&[Byte]> for Hash { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[Byte]) -> Result { + Ok(Self::new_builder() + .set(<&[Byte; 32usize]>::try_from(value)?.clone()) + .build()) + } +} +impl From for [Byte; 32usize] { + #[track_caller] + fn from(value: Hash) -> Self { + [ + value.nth0(), + value.nth1(), + value.nth2(), + value.nth3(), + value.nth4(), + value.nth5(), + value.nth6(), + value.nth7(), + value.nth8(), + value.nth9(), + value.nth10(), + value.nth11(), + value.nth12(), + value.nth13(), + value.nth14(), + value.nth15(), + value.nth16(), + value.nth17(), + value.nth18(), + value.nth19(), + value.nth20(), + value.nth21(), + value.nth22(), + value.nth23(), + value.nth24(), + value.nth25(), + value.nth26(), + value.nth27(), + value.nth28(), + value.nth29(), + value.nth30(), + value.nth31(), + ] + } +} +impl From<[u8; 32usize]> for Hash { + fn from(value: [u8; 32usize]) -> Self { + HashReader::new_unchecked(&value).to_entity() + } +} +impl ::core::convert::TryFrom<&[u8]> for Hash { + type Error = ::core::array::TryFromSliceError; + fn try_from(value: &[u8]) -> Result { + Ok(<[u8; 32usize]>::try_from(value)?.into()) + } +} +impl From for [u8; 32usize] { + #[track_caller] + fn from(value: Hash) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From> for &'a [u8; 32usize] { + #[track_caller] + fn from(value: HashReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} +impl<'a> From<&'a HashReader<'a>> for &'a [u8; 32usize] { + #[track_caller] + fn from(value: &'a HashReader<'a>) -> Self { + ::core::convert::TryFrom::try_from(value.as_slice()).unwrap() + } +} #[derive(Clone)] pub struct String(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for String { @@ -750,7 +832,7 @@ impl<'r> molecule::prelude::Reader<'r> for StringReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct StringBuilder(pub(crate) Vec); impl StringBuilder { pub const ITEM_SIZE: usize = 1; @@ -820,6 +902,18 @@ impl ::core::iter::IntoIterator for String { StringIterator(self, 0, len) } } +impl ::core::iter::FromIterator for String { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } +} +impl ::core::iter::FromIterator for String { + fn from_iter>(iter: T) -> Self { + Self::new_builder() + .extend(iter.into_iter().map(Into::into)) + .build() + } +} #[derive(Clone)] pub struct Uint32Opt(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for Uint32Opt { @@ -954,7 +1048,7 @@ impl<'r> molecule::prelude::Reader<'r> for Uint32OptReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct Uint32OptBuilder(pub(crate) Option); impl Uint32OptBuilder { pub fn set(mut self, v: Option) -> Self { @@ -984,6 +1078,11 @@ impl molecule::prelude::Builder for Uint32OptBuilder { Uint32Opt::new_unchecked(inner.into()) } } +impl From for Uint32Opt { + fn from(value: Uint32) -> Self { + Self::new_builder().set(Some(value)).build() + } +} #[derive(Clone)] pub struct Action(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for Action { @@ -1218,7 +1317,7 @@ impl<'r> molecule::prelude::Reader<'r> for ActionReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct ActionBuilder { pub(crate) script_info_hash: Byte32, pub(crate) script_hash: Byte32, @@ -1496,7 +1595,7 @@ impl<'r> molecule::prelude::Reader<'r> for ActionVecReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct ActionVecBuilder(pub(crate) Vec); impl ActionVecBuilder { pub fn set(mut self, v: Vec) -> Self { @@ -1613,6 +1712,11 @@ impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for ActionVecReaderIterator<'t, self.2 - self.1 } } +impl ::core::iter::FromIterator for ActionVec { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } +} #[derive(Clone)] pub struct Message(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for Message { @@ -1810,7 +1914,7 @@ impl<'r> molecule::prelude::Reader<'r> for MessageReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct MessageBuilder { pub(crate) actions: ActionVec, } @@ -2112,7 +2216,7 @@ impl<'r> molecule::prelude::Reader<'r> for ScriptInfoReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct ScriptInfoBuilder { pub(crate) name: String, pub(crate) url: String, @@ -2408,7 +2512,7 @@ impl<'r> molecule::prelude::Reader<'r> for ScriptInfoVecReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct ScriptInfoVecBuilder(pub(crate) Vec); impl ScriptInfoVecBuilder { pub fn set(mut self, v: Vec) -> Self { @@ -2525,6 +2629,11 @@ impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for ScriptInfoVecReaderIterator self.2 - self.1 } } +impl ::core::iter::FromIterator for ScriptInfoVec { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } +} #[derive(Clone)] pub struct ResolvedInputs(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for ResolvedInputs { @@ -2741,7 +2850,7 @@ impl<'r> molecule::prelude::Reader<'r> for ResolvedInputsReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct ResolvedInputsBuilder { pub(crate) outputs: CellOutputVec, pub(crate) outputs_data: BytesVec, @@ -3071,7 +3180,7 @@ impl<'r> molecule::prelude::Reader<'r> for BuildingPacketV1Reader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct BuildingPacketV1Builder { pub(crate) message: Message, pub(crate) payload: Transaction, @@ -3293,7 +3402,7 @@ impl<'r> molecule::prelude::Reader<'r> for BuildingPacketReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct BuildingPacketBuilder(pub(crate) BuildingPacketUnion); impl BuildingPacketBuilder { pub const ITEMS_COUNT: usize = 1; @@ -3423,6 +3532,11 @@ impl<'r> BuildingPacketUnionReader<'r> { } } } +impl From for BuildingPacket { + fn from(value: BuildingPacketV1) -> Self { + Self::new_builder().set(value).build() + } +} #[derive(Clone)] pub struct SighashAll(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for SighashAll { @@ -3639,7 +3753,7 @@ impl<'r> molecule::prelude::Reader<'r> for SighashAllReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct SighashAllBuilder { pub(crate) message: Message, pub(crate) seal: Bytes, @@ -3882,7 +3996,7 @@ impl<'r> molecule::prelude::Reader<'r> for SighashAllOnlyReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct SighashAllOnlyBuilder { pub(crate) seal: Bytes, } @@ -4135,7 +4249,7 @@ impl<'r> molecule::prelude::Reader<'r> for SealPairReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct SealPairBuilder { pub(crate) script_hash: Byte32, pub(crate) seal: Bytes, @@ -4404,7 +4518,7 @@ impl<'r> molecule::prelude::Reader<'r> for SealPairVecReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct SealPairVecBuilder(pub(crate) Vec); impl SealPairVecBuilder { pub fn set(mut self, v: Vec) -> Self { @@ -4521,6 +4635,11 @@ impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for SealPairVecReaderIterator<' self.2 - self.1 } } +impl ::core::iter::FromIterator for SealPairVec { + fn from_iter>(iter: T) -> Self { + Self::new_builder().extend(iter).build() + } +} #[derive(Clone)] pub struct OtxStart(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for OtxStart { @@ -4770,7 +4889,7 @@ impl<'r> molecule::prelude::Reader<'r> for OtxStartReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct OtxStartBuilder { pub(crate) start_input_cell: Uint32, pub(crate) start_output_cell: Uint32, @@ -5116,7 +5235,7 @@ impl<'r> molecule::prelude::Reader<'r> for OtxReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct OtxBuilder { pub(crate) input_cells: Uint32, pub(crate) output_cells: Uint32, diff --git a/ckb-transaction-cobuild/src/schemas/top_level.rs b/ckb-transaction-cobuild/src/schemas/top_level.rs index 1bb527d..ab0af45 100644 --- a/ckb-transaction-cobuild/src/schemas/top_level.rs +++ b/ckb-transaction-cobuild/src/schemas/top_level.rs @@ -148,7 +148,7 @@ impl<'r> molecule::prelude::Reader<'r> for WitnessLayoutReader<'r> { Ok(()) } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct WitnessLayoutBuilder(pub(crate) WitnessLayoutUnion); impl WitnessLayoutBuilder { pub const ITEMS_COUNT: usize = 4; @@ -362,3 +362,23 @@ impl<'r> WitnessLayoutUnionReader<'r> { } } } +impl From for WitnessLayout { + fn from(value: SighashAll) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for WitnessLayout { + fn from(value: SighashAllOnly) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for WitnessLayout { + fn from(value: Otx) -> Self { + Self::new_builder().set(value).build() + } +} +impl From for WitnessLayout { + fn from(value: OtxStart) -> Self { + Self::new_builder().set(value).build() + } +} diff --git a/ckb-transaction-cobuild/src/schemas2/basic.rs b/ckb-transaction-cobuild/src/schemas2/basic.rs new file mode 100644 index 0000000..f13454e --- /dev/null +++ b/ckb-transaction-cobuild/src/schemas2/basic.rs @@ -0,0 +1,747 @@ +extern crate alloc; +use super::blockchain::*; +use core::convert::TryInto; +use molecule::lazy_reader::{Cursor, Error, NUMBER_SIZE}; +pub struct Hash { + pub cursor: Cursor, +} +impl From for Hash { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl Hash { + pub fn len(&self) -> usize { + 32 + } +} +impl Hash { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.slice_by_offset(1usize * index, 1usize)?; + cur.try_into() + } +} +impl Hash { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(32usize)?; + Ok(()) + } +} +pub struct String { + pub cursor: Cursor, +} +impl From for String { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl String { + pub fn len(&self) -> Result { + self.cursor.fixvec_length() + } +} +impl String { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.fixvec_slice_by_index(1usize, index)?; + cur.try_into() + } +} +pub struct StringIterator { + cur: String, + index: usize, + len: usize, +} +impl core::iter::Iterator for StringIterator { + type Item = u8; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for String { + type Item = u8; + type IntoIter = StringIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct StringIteratorRef<'a> { + cur: &'a String, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for StringIteratorRef<'a> { + type Item = u8; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl String { + pub fn iter(&self) -> StringIteratorRef { + let len = self.len().unwrap(); + StringIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl String { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixvec(1usize)?; + Ok(()) + } +} +pub struct Uint32Opt { + pub cursor: Cursor, +} +impl From for Uint32Opt { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +pub struct Action { + pub cursor: Cursor, +} +impl From for Action { + fn from(cursor: Cursor) -> Self { + Action { cursor } + } +} +impl Action { + pub fn script_info_hash(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.table_slice_by_index(0usize)?; + cur.try_into() + } +} +impl Action { + pub fn script_hash(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.table_slice_by_index(1usize)?; + cur.try_into() + } +} +impl Action { + pub fn data(&self) -> Result { + let cur = self.cursor.table_slice_by_index(2usize)?; + cur.convert_to_rawbytes() + } +} +impl Action { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(3usize, compatible)?; + Byte32::from(Cursor::try_from(self.script_info_hash()?)?).verify(compatible)?; + Byte32::from(Cursor::try_from(self.script_hash()?)?).verify(compatible)?; + Ok(()) + } +} +pub struct ActionVec { + pub cursor: Cursor, +} +impl From for ActionVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl ActionVec { + pub fn len(&self) -> Result { + self.cursor.dynvec_length() + } +} +impl ActionVec { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.dynvec_slice_by_index(index)?; + Ok(cur.into()) + } +} +pub struct ActionVecIterator { + cur: ActionVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for ActionVecIterator { + type Item = Action; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for ActionVec { + type Item = Action; + type IntoIter = ActionVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct ActionVecIteratorRef<'a> { + cur: &'a ActionVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for ActionVecIteratorRef<'a> { + type Item = Action; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl ActionVec { + pub fn iter(&self) -> ActionVecIteratorRef { + let len = self.len().unwrap(); + ActionVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl ActionVec { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_dynvec()?; + for i in 0..self.len()? { + self.get(i)?.verify(compatible)?; + } + Ok(()) + } +} +pub struct Message { + pub cursor: Cursor, +} +impl From for Message { + fn from(cursor: Cursor) -> Self { + Message { cursor } + } +} +impl Message { + pub fn actions(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + Ok(cur.into()) + } +} +impl Message { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(1usize, compatible)?; + self.actions()?.verify(compatible)?; + Ok(()) + } +} +pub struct ScriptInfo { + pub cursor: Cursor, +} +impl From for ScriptInfo { + fn from(cursor: Cursor) -> Self { + ScriptInfo { cursor } + } +} +impl ScriptInfo { + pub fn name(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + cur.convert_to_rawbytes() + } +} +impl ScriptInfo { + pub fn url(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + cur.convert_to_rawbytes() + } +} +impl ScriptInfo { + pub fn script_hash(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.table_slice_by_index(2usize)?; + cur.try_into() + } +} +impl ScriptInfo { + pub fn schema(&self) -> Result { + let cur = self.cursor.table_slice_by_index(3usize)?; + cur.convert_to_rawbytes() + } +} +impl ScriptInfo { + pub fn message_type(&self) -> Result { + let cur = self.cursor.table_slice_by_index(4usize)?; + cur.convert_to_rawbytes() + } +} +impl ScriptInfo { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(5usize, compatible)?; + Byte32::from(Cursor::try_from(self.script_hash()?)?).verify(compatible)?; + Ok(()) + } +} +pub struct ScriptInfoVec { + pub cursor: Cursor, +} +impl From for ScriptInfoVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl ScriptInfoVec { + pub fn len(&self) -> Result { + self.cursor.dynvec_length() + } +} +impl ScriptInfoVec { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.dynvec_slice_by_index(index)?; + Ok(cur.into()) + } +} +pub struct ScriptInfoVecIterator { + cur: ScriptInfoVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for ScriptInfoVecIterator { + type Item = ScriptInfo; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for ScriptInfoVec { + type Item = ScriptInfo; + type IntoIter = ScriptInfoVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct ScriptInfoVecIteratorRef<'a> { + cur: &'a ScriptInfoVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for ScriptInfoVecIteratorRef<'a> { + type Item = ScriptInfo; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl ScriptInfoVec { + pub fn iter(&self) -> ScriptInfoVecIteratorRef { + let len = self.len().unwrap(); + ScriptInfoVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl ScriptInfoVec { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_dynvec()?; + for i in 0..self.len()? { + self.get(i)?.verify(compatible)?; + } + Ok(()) + } +} +pub struct ResolvedInputs { + pub cursor: Cursor, +} +impl From for ResolvedInputs { + fn from(cursor: Cursor) -> Self { + ResolvedInputs { cursor } + } +} +impl ResolvedInputs { + pub fn outputs(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + Ok(cur.into()) + } +} +impl ResolvedInputs { + pub fn outputs_data(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + Ok(cur.into()) + } +} +impl ResolvedInputs { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(2usize, compatible)?; + self.outputs()?.verify(compatible)?; + self.outputs_data()?.verify(compatible)?; + Ok(()) + } +} +pub struct BuildingPacketV1 { + pub cursor: Cursor, +} +impl From for BuildingPacketV1 { + fn from(cursor: Cursor) -> Self { + BuildingPacketV1 { cursor } + } +} +impl BuildingPacketV1 { + pub fn message(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + Ok(cur.into()) + } +} +impl BuildingPacketV1 { + pub fn payload(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + Ok(cur.into()) + } +} +impl BuildingPacketV1 { + pub fn resolved_inputs(&self) -> Result { + let cur = self.cursor.table_slice_by_index(2usize)?; + Ok(cur.into()) + } +} +impl BuildingPacketV1 { + pub fn change_output(&self) -> Result, Error> { + let cur = self.cursor.table_slice_by_index(3usize)?; + if cur.option_is_none() { + Ok(None) + } else { + Ok(Some(cur.try_into()?)) + } + } +} +impl BuildingPacketV1 { + pub fn script_infos(&self) -> Result { + let cur = self.cursor.table_slice_by_index(4usize)?; + Ok(cur.into()) + } +} +impl BuildingPacketV1 { + pub fn lock_actions(&self) -> Result { + let cur = self.cursor.table_slice_by_index(5usize)?; + Ok(cur.into()) + } +} +impl BuildingPacketV1 { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(6usize, compatible)?; + self.message()?.verify(compatible)?; + self.payload()?.verify(compatible)?; + self.resolved_inputs()?.verify(compatible)?; + self.script_infos()?.verify(compatible)?; + self.lock_actions()?.verify(compatible)?; + Ok(()) + } +} +pub enum BuildingPacket { + BuildingPacketV1(BuildingPacketV1), +} +impl TryFrom for BuildingPacket { + type Error = Error; + fn try_from(cur: Cursor) -> Result { + let item = cur.union_unpack()?; + let mut cur = cur; + cur.add_offset(NUMBER_SIZE)?; + cur.sub_size(NUMBER_SIZE)?; + match item.item_id { + 0usize => Ok(Self::BuildingPacketV1(cur.into())), + _ => Err(Error::UnknownItem), + } + } +} +impl BuildingPacket { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + match self { + Self::BuildingPacketV1(v) => { + v.verify(compatible)?; + Ok(()) + } + } + } +} +pub struct SighashAll { + pub cursor: Cursor, +} +impl From for SighashAll { + fn from(cursor: Cursor) -> Self { + SighashAll { cursor } + } +} +impl SighashAll { + pub fn message(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + Ok(cur.into()) + } +} +impl SighashAll { + pub fn seal(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + cur.convert_to_rawbytes() + } +} +impl SighashAll { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(2usize, compatible)?; + self.message()?.verify(compatible)?; + Ok(()) + } +} +pub struct SighashAllOnly { + pub cursor: Cursor, +} +impl From for SighashAllOnly { + fn from(cursor: Cursor) -> Self { + SighashAllOnly { cursor } + } +} +impl SighashAllOnly { + pub fn seal(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + cur.convert_to_rawbytes() + } +} +impl SighashAllOnly { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(1usize, compatible)?; + Ok(()) + } +} +pub struct SealPair { + pub cursor: Cursor, +} +impl From for SealPair { + fn from(cursor: Cursor) -> Self { + SealPair { cursor } + } +} +impl SealPair { + pub fn script_hash(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.table_slice_by_index(0usize)?; + cur.try_into() + } +} +impl SealPair { + pub fn seal(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + cur.convert_to_rawbytes() + } +} +impl SealPair { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(2usize, compatible)?; + Byte32::from(Cursor::try_from(self.script_hash()?)?).verify(compatible)?; + Ok(()) + } +} +pub struct SealPairVec { + pub cursor: Cursor, +} +impl From for SealPairVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl SealPairVec { + pub fn len(&self) -> Result { + self.cursor.dynvec_length() + } +} +impl SealPairVec { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.dynvec_slice_by_index(index)?; + Ok(cur.into()) + } +} +pub struct SealPairVecIterator { + cur: SealPairVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for SealPairVecIterator { + type Item = SealPair; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for SealPairVec { + type Item = SealPair; + type IntoIter = SealPairVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct SealPairVecIteratorRef<'a> { + cur: &'a SealPairVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for SealPairVecIteratorRef<'a> { + type Item = SealPair; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl SealPairVec { + pub fn iter(&self) -> SealPairVecIteratorRef { + let len = self.len().unwrap(); + SealPairVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl SealPairVec { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_dynvec()?; + for i in 0..self.len()? { + self.get(i)?.verify(compatible)?; + } + Ok(()) + } +} +pub struct OtxStart { + pub cursor: Cursor, +} +impl From for OtxStart { + fn from(cursor: Cursor) -> Self { + OtxStart { cursor } + } +} +impl OtxStart { + pub fn start_input_cell(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + cur.try_into() + } +} +impl OtxStart { + pub fn start_output_cell(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + cur.try_into() + } +} +impl OtxStart { + pub fn start_cell_deps(&self) -> Result { + let cur = self.cursor.table_slice_by_index(2usize)?; + cur.try_into() + } +} +impl OtxStart { + pub fn start_header_deps(&self) -> Result { + let cur = self.cursor.table_slice_by_index(3usize)?; + cur.try_into() + } +} +impl OtxStart { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(4usize, compatible)?; + Ok(()) + } +} +pub struct Otx { + pub cursor: Cursor, +} +impl From for Otx { + fn from(cursor: Cursor) -> Self { + Otx { cursor } + } +} +impl Otx { + pub fn input_cells(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + cur.try_into() + } +} +impl Otx { + pub fn output_cells(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + cur.try_into() + } +} +impl Otx { + pub fn cell_deps(&self) -> Result { + let cur = self.cursor.table_slice_by_index(2usize)?; + cur.try_into() + } +} +impl Otx { + pub fn header_deps(&self) -> Result { + let cur = self.cursor.table_slice_by_index(3usize)?; + cur.try_into() + } +} +impl Otx { + pub fn message(&self) -> Result { + let cur = self.cursor.table_slice_by_index(4usize)?; + Ok(cur.into()) + } +} +impl Otx { + pub fn seals(&self) -> Result { + let cur = self.cursor.table_slice_by_index(5usize)?; + Ok(cur.into()) + } +} +impl Otx { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(6usize, compatible)?; + self.message()?.verify(compatible)?; + self.seals()?.verify(compatible)?; + Ok(()) + } +} diff --git a/ckb-transaction-cobuild/src/schemas2/blockchain.rs b/ckb-transaction-cobuild/src/schemas2/blockchain.rs new file mode 100644 index 0000000..81297e4 --- /dev/null +++ b/ckb-transaction-cobuild/src/schemas2/blockchain.rs @@ -0,0 +1,1525 @@ +extern crate alloc; +use core::convert::TryInto; +use molecule::lazy_reader::{Cursor, Error, NUMBER_SIZE}; +pub struct Uint32 { + pub cursor: Cursor, +} +impl From for Uint32 { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl Uint32 { + pub fn len(&self) -> usize { + 4 + } +} +impl Uint32 { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.slice_by_offset(1usize * index, 1usize)?; + cur.try_into() + } +} +impl Uint32 { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(4usize)?; + Ok(()) + } +} +pub struct Uint64 { + pub cursor: Cursor, +} +impl From for Uint64 { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl Uint64 { + pub fn len(&self) -> usize { + 8 + } +} +impl Uint64 { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.slice_by_offset(1usize * index, 1usize)?; + cur.try_into() + } +} +impl Uint64 { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(8usize)?; + Ok(()) + } +} +pub struct Uint128 { + pub cursor: Cursor, +} +impl From for Uint128 { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl Uint128 { + pub fn len(&self) -> usize { + 16 + } +} +impl Uint128 { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.slice_by_offset(1usize * index, 1usize)?; + cur.try_into() + } +} +impl Uint128 { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(16usize)?; + Ok(()) + } +} +pub struct Byte32 { + pub cursor: Cursor, +} +impl From for Byte32 { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl Byte32 { + pub fn len(&self) -> usize { + 32 + } +} +impl Byte32 { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.slice_by_offset(1usize * index, 1usize)?; + cur.try_into() + } +} +impl Byte32 { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(32usize)?; + Ok(()) + } +} +pub struct Uint256 { + pub cursor: Cursor, +} +impl From for Uint256 { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl Uint256 { + pub fn len(&self) -> usize { + 32 + } +} +impl Uint256 { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.slice_by_offset(1usize * index, 1usize)?; + cur.try_into() + } +} +impl Uint256 { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(32usize)?; + Ok(()) + } +} +pub struct Bytes { + pub cursor: Cursor, +} +impl From for Bytes { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl Bytes { + pub fn len(&self) -> Result { + self.cursor.fixvec_length() + } +} +impl Bytes { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.fixvec_slice_by_index(1usize, index)?; + cur.try_into() + } +} +pub struct BytesIterator { + cur: Bytes, + index: usize, + len: usize, +} +impl core::iter::Iterator for BytesIterator { + type Item = u8; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for Bytes { + type Item = u8; + type IntoIter = BytesIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct BytesIteratorRef<'a> { + cur: &'a Bytes, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for BytesIteratorRef<'a> { + type Item = u8; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl Bytes { + pub fn iter(&self) -> BytesIteratorRef { + let len = self.len().unwrap(); + BytesIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl Bytes { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixvec(1usize)?; + Ok(()) + } +} +pub struct BytesOpt { + pub cursor: Cursor, +} +impl From for BytesOpt { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +pub struct BytesOptVec { + pub cursor: Cursor, +} +impl From for BytesOptVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl BytesOptVec { + pub fn len(&self) -> Result { + self.cursor.dynvec_length() + } +} +impl BytesOptVec { + pub fn get(&self, index: usize) -> Result, Error> { + let cur = self.cursor.dynvec_slice_by_index(index)?; + if cur.option_is_none() { + Ok(None) + } else { + let cur = cur.convert_to_rawbytes()?; + Ok(Some(cur.into())) + } + } +} +pub struct BytesOptVecIterator { + cur: BytesOptVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for BytesOptVecIterator { + type Item = Option; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for BytesOptVec { + type Item = Option; + type IntoIter = BytesOptVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct BytesOptVecIteratorRef<'a> { + cur: &'a BytesOptVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for BytesOptVecIteratorRef<'a> { + type Item = Option; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl BytesOptVec { + pub fn iter(&self) -> BytesOptVecIteratorRef { + let len = self.len().unwrap(); + BytesOptVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl BytesOptVec { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_dynvec()?; + Ok(()) + } +} +pub struct BytesVec { + pub cursor: Cursor, +} +impl From for BytesVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl BytesVec { + pub fn len(&self) -> Result { + self.cursor.dynvec_length() + } +} +impl BytesVec { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.dynvec_slice_by_index(index)?; + cur.convert_to_rawbytes() + } +} +pub struct BytesVecIterator { + cur: BytesVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for BytesVecIterator { + type Item = Cursor; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for BytesVec { + type Item = Cursor; + type IntoIter = BytesVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct BytesVecIteratorRef<'a> { + cur: &'a BytesVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for BytesVecIteratorRef<'a> { + type Item = Cursor; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl BytesVec { + pub fn iter(&self) -> BytesVecIteratorRef { + let len = self.len().unwrap(); + BytesVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl BytesVec { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_dynvec()?; + Ok(()) + } +} +pub struct Byte32Vec { + pub cursor: Cursor, +} +impl From for Byte32Vec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl Byte32Vec { + pub fn len(&self) -> Result { + self.cursor.fixvec_length() + } +} +impl Byte32Vec { + pub fn get(&self, index: usize) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.fixvec_slice_by_index(32usize, index)?; + cur.try_into() + } +} +pub struct Byte32VecIterator { + cur: Byte32Vec, + index: usize, + len: usize, +} +impl core::iter::Iterator for Byte32VecIterator { + type Item = [u8; 32usize]; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for Byte32Vec { + type Item = [u8; 32usize]; + type IntoIter = Byte32VecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct Byte32VecIteratorRef<'a> { + cur: &'a Byte32Vec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for Byte32VecIteratorRef<'a> { + type Item = [u8; 32usize]; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl Byte32Vec { + pub fn iter(&self) -> Byte32VecIteratorRef { + let len = self.len().unwrap(); + Byte32VecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl Byte32Vec { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixvec(32usize)?; + Ok(()) + } +} +pub struct ScriptOpt { + pub cursor: Cursor, +} +impl From for ScriptOpt { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +pub struct ProposalShortId { + pub cursor: Cursor, +} +impl From for ProposalShortId { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl ProposalShortId { + pub fn len(&self) -> usize { + 10 + } +} +impl ProposalShortId { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.slice_by_offset(1usize * index, 1usize)?; + cur.try_into() + } +} +impl ProposalShortId { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(10usize)?; + Ok(()) + } +} +pub struct UncleBlockVec { + pub cursor: Cursor, +} +impl From for UncleBlockVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl UncleBlockVec { + pub fn len(&self) -> Result { + self.cursor.dynvec_length() + } +} +impl UncleBlockVec { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.dynvec_slice_by_index(index)?; + Ok(cur.into()) + } +} +pub struct UncleBlockVecIterator { + cur: UncleBlockVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for UncleBlockVecIterator { + type Item = UncleBlock; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for UncleBlockVec { + type Item = UncleBlock; + type IntoIter = UncleBlockVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct UncleBlockVecIteratorRef<'a> { + cur: &'a UncleBlockVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for UncleBlockVecIteratorRef<'a> { + type Item = UncleBlock; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl UncleBlockVec { + pub fn iter(&self) -> UncleBlockVecIteratorRef { + let len = self.len().unwrap(); + UncleBlockVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl UncleBlockVec { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_dynvec()?; + for i in 0..self.len()? { + self.get(i)?.verify(compatible)?; + } + Ok(()) + } +} +pub struct TransactionVec { + pub cursor: Cursor, +} +impl From for TransactionVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl TransactionVec { + pub fn len(&self) -> Result { + self.cursor.dynvec_length() + } +} +impl TransactionVec { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.dynvec_slice_by_index(index)?; + Ok(cur.into()) + } +} +pub struct TransactionVecIterator { + cur: TransactionVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for TransactionVecIterator { + type Item = Transaction; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for TransactionVec { + type Item = Transaction; + type IntoIter = TransactionVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct TransactionVecIteratorRef<'a> { + cur: &'a TransactionVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for TransactionVecIteratorRef<'a> { + type Item = Transaction; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl TransactionVec { + pub fn iter(&self) -> TransactionVecIteratorRef { + let len = self.len().unwrap(); + TransactionVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl TransactionVec { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_dynvec()?; + for i in 0..self.len()? { + self.get(i)?.verify(compatible)?; + } + Ok(()) + } +} +pub struct ProposalShortIdVec { + pub cursor: Cursor, +} +impl From for ProposalShortIdVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl ProposalShortIdVec { + pub fn len(&self) -> Result { + self.cursor.fixvec_length() + } +} +impl ProposalShortIdVec { + pub fn get(&self, index: usize) -> Result<[u8; 10usize], Error> { + let cur = self.cursor.fixvec_slice_by_index(10usize, index)?; + cur.try_into() + } +} +pub struct ProposalShortIdVecIterator { + cur: ProposalShortIdVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for ProposalShortIdVecIterator { + type Item = [u8; 10usize]; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for ProposalShortIdVec { + type Item = [u8; 10usize]; + type IntoIter = ProposalShortIdVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct ProposalShortIdVecIteratorRef<'a> { + cur: &'a ProposalShortIdVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for ProposalShortIdVecIteratorRef<'a> { + type Item = [u8; 10usize]; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl ProposalShortIdVec { + pub fn iter(&self) -> ProposalShortIdVecIteratorRef { + let len = self.len().unwrap(); + ProposalShortIdVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl ProposalShortIdVec { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixvec(10usize)?; + Ok(()) + } +} +pub struct CellDepVec { + pub cursor: Cursor, +} +impl From for CellDepVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl CellDepVec { + pub fn len(&self) -> Result { + self.cursor.fixvec_length() + } +} +impl CellDepVec { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.fixvec_slice_by_index(37usize, index)?; + Ok(cur.into()) + } +} +pub struct CellDepVecIterator { + cur: CellDepVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for CellDepVecIterator { + type Item = CellDep; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for CellDepVec { + type Item = CellDep; + type IntoIter = CellDepVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct CellDepVecIteratorRef<'a> { + cur: &'a CellDepVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for CellDepVecIteratorRef<'a> { + type Item = CellDep; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl CellDepVec { + pub fn iter(&self) -> CellDepVecIteratorRef { + let len = self.len().unwrap(); + CellDepVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl CellDepVec { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixvec(37usize)?; + Ok(()) + } +} +pub struct CellInputVec { + pub cursor: Cursor, +} +impl From for CellInputVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl CellInputVec { + pub fn len(&self) -> Result { + self.cursor.fixvec_length() + } +} +impl CellInputVec { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.fixvec_slice_by_index(44usize, index)?; + Ok(cur.into()) + } +} +pub struct CellInputVecIterator { + cur: CellInputVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for CellInputVecIterator { + type Item = CellInput; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for CellInputVec { + type Item = CellInput; + type IntoIter = CellInputVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct CellInputVecIteratorRef<'a> { + cur: &'a CellInputVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for CellInputVecIteratorRef<'a> { + type Item = CellInput; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl CellInputVec { + pub fn iter(&self) -> CellInputVecIteratorRef { + let len = self.len().unwrap(); + CellInputVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl CellInputVec { + pub fn verify(&self, _compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixvec(44usize)?; + Ok(()) + } +} +pub struct CellOutputVec { + pub cursor: Cursor, +} +impl From for CellOutputVec { + fn from(cursor: Cursor) -> Self { + Self { cursor } + } +} +impl CellOutputVec { + pub fn len(&self) -> Result { + self.cursor.dynvec_length() + } +} +impl CellOutputVec { + pub fn get(&self, index: usize) -> Result { + let cur = self.cursor.dynvec_slice_by_index(index)?; + Ok(cur.into()) + } +} +pub struct CellOutputVecIterator { + cur: CellOutputVec, + index: usize, + len: usize, +} +impl core::iter::Iterator for CellOutputVecIterator { + type Item = CellOutput; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl core::iter::IntoIterator for CellOutputVec { + type Item = CellOutput; + type IntoIter = CellOutputVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len().unwrap(); + Self::IntoIter { + cur: self, + index: 0, + len, + } + } +} +pub struct CellOutputVecIteratorRef<'a> { + cur: &'a CellOutputVec, + index: usize, + len: usize, +} +impl<'a> core::iter::Iterator for CellOutputVecIteratorRef<'a> { + type Item = CellOutput; + fn next(&mut self) -> Option { + if self.index >= self.len { + None + } else { + let res = self.cur.get(self.index).unwrap(); + self.index += 1; + Some(res) + } + } +} +impl CellOutputVec { + pub fn iter(&self) -> CellOutputVecIteratorRef { + let len = self.len().unwrap(); + CellOutputVecIteratorRef { + cur: &self, + index: 0, + len, + } + } +} +impl CellOutputVec { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_dynvec()?; + for i in 0..self.len()? { + self.get(i)?.verify(compatible)?; + } + Ok(()) + } +} +pub struct Script { + pub cursor: Cursor, +} +impl From for Script { + fn from(cursor: Cursor) -> Self { + Script { cursor } + } +} +impl Script { + pub fn code_hash(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.table_slice_by_index(0usize)?; + cur.try_into() + } +} +impl Script { + pub fn hash_type(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + cur.try_into() + } +} +impl Script { + pub fn args(&self) -> Result { + let cur = self.cursor.table_slice_by_index(2usize)?; + cur.convert_to_rawbytes() + } +} +impl Script { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(3usize, compatible)?; + Byte32::from(Cursor::try_from(self.code_hash()?)?).verify(compatible)?; + Ok(()) + } +} +pub struct OutPoint { + pub cursor: Cursor, +} +impl From for OutPoint { + fn from(cursor: Cursor) -> Self { + OutPoint { cursor } + } +} +impl OutPoint { + pub fn tx_hash(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.slice_by_offset(0usize, 32usize)?; + cur.try_into() + } +} +impl OutPoint { + pub fn index(&self) -> Result { + let cur = self.cursor.slice_by_offset(32usize, 4usize)?; + cur.try_into() + } +} +impl OutPoint { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(36usize)?; + Byte32::from(Cursor::try_from(self.tx_hash()?)?).verify(compatible)?; + Ok(()) + } +} +pub struct CellInput { + pub cursor: Cursor, +} +impl From for CellInput { + fn from(cursor: Cursor) -> Self { + CellInput { cursor } + } +} +impl CellInput { + pub fn since(&self) -> Result { + let cur = self.cursor.slice_by_offset(0usize, 8usize)?; + cur.try_into() + } +} +impl CellInput { + pub fn previous_output(&self) -> Result { + let cur = self.cursor.slice_by_offset(8usize, 36usize)?; + Ok(cur.into()) + } +} +impl CellInput { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(44usize)?; + self.previous_output()?.verify(compatible)?; + Ok(()) + } +} +pub struct CellOutput { + pub cursor: Cursor, +} +impl From for CellOutput { + fn from(cursor: Cursor) -> Self { + CellOutput { cursor } + } +} +impl CellOutput { + pub fn capacity(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + cur.try_into() + } +} +impl CellOutput { + pub fn lock(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + Ok(cur.into()) + } +} +impl CellOutput { + pub fn type_(&self) -> Result, Error> { + let cur = self.cursor.table_slice_by_index(2usize)?; + if cur.option_is_none() { + Ok(None) + } else { + Ok(Some(cur.try_into()?)) + } + } +} +impl CellOutput { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(3usize, compatible)?; + self.lock()?.verify(compatible)?; + let val = self.type_()?; + if val.is_some() { + let val = val.unwrap(); + val.verify(compatible)?; + } + Ok(()) + } +} +pub struct CellDep { + pub cursor: Cursor, +} +impl From for CellDep { + fn from(cursor: Cursor) -> Self { + CellDep { cursor } + } +} +impl CellDep { + pub fn out_point(&self) -> Result { + let cur = self.cursor.slice_by_offset(0usize, 36usize)?; + Ok(cur.into()) + } +} +impl CellDep { + pub fn dep_type(&self) -> Result { + let cur = self.cursor.slice_by_offset(36usize, 1usize)?; + cur.try_into() + } +} +impl CellDep { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(37usize)?; + self.out_point()?.verify(compatible)?; + Ok(()) + } +} +pub struct RawTransaction { + pub cursor: Cursor, +} +impl From for RawTransaction { + fn from(cursor: Cursor) -> Self { + RawTransaction { cursor } + } +} +impl RawTransaction { + pub fn version(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + cur.try_into() + } +} +impl RawTransaction { + pub fn cell_deps(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + Ok(cur.into()) + } +} +impl RawTransaction { + pub fn header_deps(&self) -> Result { + let cur = self.cursor.table_slice_by_index(2usize)?; + Ok(cur.into()) + } +} +impl RawTransaction { + pub fn inputs(&self) -> Result { + let cur = self.cursor.table_slice_by_index(3usize)?; + Ok(cur.into()) + } +} +impl RawTransaction { + pub fn outputs(&self) -> Result { + let cur = self.cursor.table_slice_by_index(4usize)?; + Ok(cur.into()) + } +} +impl RawTransaction { + pub fn outputs_data(&self) -> Result { + let cur = self.cursor.table_slice_by_index(5usize)?; + Ok(cur.into()) + } +} +impl RawTransaction { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(6usize, compatible)?; + self.outputs()?.verify(compatible)?; + self.outputs_data()?.verify(compatible)?; + Ok(()) + } +} +pub struct Transaction { + pub cursor: Cursor, +} +impl From for Transaction { + fn from(cursor: Cursor) -> Self { + Transaction { cursor } + } +} +impl Transaction { + pub fn raw(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + Ok(cur.into()) + } +} +impl Transaction { + pub fn witnesses(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + Ok(cur.into()) + } +} +impl Transaction { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(2usize, compatible)?; + self.raw()?.verify(compatible)?; + self.witnesses()?.verify(compatible)?; + Ok(()) + } +} +pub struct RawHeader { + pub cursor: Cursor, +} +impl From for RawHeader { + fn from(cursor: Cursor) -> Self { + RawHeader { cursor } + } +} +impl RawHeader { + pub fn version(&self) -> Result { + let cur = self.cursor.slice_by_offset(0usize, 4usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn compact_target(&self) -> Result { + let cur = self.cursor.slice_by_offset(4usize, 4usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn timestamp(&self) -> Result { + let cur = self.cursor.slice_by_offset(8usize, 8usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn number(&self) -> Result { + let cur = self.cursor.slice_by_offset(16usize, 8usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn epoch(&self) -> Result { + let cur = self.cursor.slice_by_offset(24usize, 8usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn parent_hash(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.slice_by_offset(32usize, 32usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn transactions_root(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.slice_by_offset(64usize, 32usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn proposals_hash(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.slice_by_offset(96usize, 32usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn extra_hash(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.slice_by_offset(128usize, 32usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn dao(&self) -> Result<[u8; 32usize], Error> { + let cur = self.cursor.slice_by_offset(160usize, 32usize)?; + cur.try_into() + } +} +impl RawHeader { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(192usize)?; + Byte32::from(Cursor::try_from(self.parent_hash()?)?).verify(compatible)?; + Byte32::from(Cursor::try_from(self.transactions_root()?)?).verify(compatible)?; + Byte32::from(Cursor::try_from(self.proposals_hash()?)?).verify(compatible)?; + Byte32::from(Cursor::try_from(self.extra_hash()?)?).verify(compatible)?; + Byte32::from(Cursor::try_from(self.dao()?)?).verify(compatible)?; + Ok(()) + } +} +pub struct Header { + pub cursor: Cursor, +} +impl From for Header { + fn from(cursor: Cursor) -> Self { + Header { cursor } + } +} +impl Header { + pub fn raw(&self) -> Result { + let cur = self.cursor.slice_by_offset(0usize, 192usize)?; + Ok(cur.into()) + } +} +impl Header { + pub fn nonce(&self) -> Result<[u8; 16usize], Error> { + let cur = self.cursor.slice_by_offset(192usize, 16usize)?; + cur.try_into() + } +} +impl Header { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_fixed_size(208usize)?; + self.raw()?.verify(compatible)?; + Uint128::from(Cursor::try_from(self.nonce()?)?).verify(compatible)?; + Ok(()) + } +} +pub struct UncleBlock { + pub cursor: Cursor, +} +impl From for UncleBlock { + fn from(cursor: Cursor) -> Self { + UncleBlock { cursor } + } +} +impl UncleBlock { + pub fn header(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + Ok(cur.into()) + } +} +impl UncleBlock { + pub fn proposals(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + Ok(cur.into()) + } +} +impl UncleBlock { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(2usize, compatible)?; + self.header()?.verify(compatible)?; + Ok(()) + } +} +pub struct Block { + pub cursor: Cursor, +} +impl From for Block { + fn from(cursor: Cursor) -> Self { + Block { cursor } + } +} +impl Block { + pub fn header(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + Ok(cur.into()) + } +} +impl Block { + pub fn uncles(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + Ok(cur.into()) + } +} +impl Block { + pub fn transactions(&self) -> Result { + let cur = self.cursor.table_slice_by_index(2usize)?; + Ok(cur.into()) + } +} +impl Block { + pub fn proposals(&self) -> Result { + let cur = self.cursor.table_slice_by_index(3usize)?; + Ok(cur.into()) + } +} +impl Block { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(4usize, compatible)?; + self.header()?.verify(compatible)?; + self.uncles()?.verify(compatible)?; + self.transactions()?.verify(compatible)?; + Ok(()) + } +} +pub struct BlockV1 { + pub cursor: Cursor, +} +impl From for BlockV1 { + fn from(cursor: Cursor) -> Self { + BlockV1 { cursor } + } +} +impl BlockV1 { + pub fn header(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + Ok(cur.into()) + } +} +impl BlockV1 { + pub fn uncles(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + Ok(cur.into()) + } +} +impl BlockV1 { + pub fn transactions(&self) -> Result { + let cur = self.cursor.table_slice_by_index(2usize)?; + Ok(cur.into()) + } +} +impl BlockV1 { + pub fn proposals(&self) -> Result { + let cur = self.cursor.table_slice_by_index(3usize)?; + Ok(cur.into()) + } +} +impl BlockV1 { + pub fn extension(&self) -> Result { + let cur = self.cursor.table_slice_by_index(4usize)?; + cur.convert_to_rawbytes() + } +} +impl BlockV1 { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(5usize, compatible)?; + self.header()?.verify(compatible)?; + self.uncles()?.verify(compatible)?; + self.transactions()?.verify(compatible)?; + Ok(()) + } +} +pub struct CellbaseWitness { + pub cursor: Cursor, +} +impl From for CellbaseWitness { + fn from(cursor: Cursor) -> Self { + CellbaseWitness { cursor } + } +} +impl CellbaseWitness { + pub fn lock(&self) -> Result { + let cur = self.cursor.table_slice_by_index(0usize)?; + Ok(cur.into()) + } +} +impl CellbaseWitness { + pub fn message(&self) -> Result { + let cur = self.cursor.table_slice_by_index(1usize)?; + cur.convert_to_rawbytes() + } +} +impl CellbaseWitness { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(2usize, compatible)?; + self.lock()?.verify(compatible)?; + Ok(()) + } +} +pub struct WitnessArgs { + pub cursor: Cursor, +} +impl From for WitnessArgs { + fn from(cursor: Cursor) -> Self { + WitnessArgs { cursor } + } +} +impl WitnessArgs { + pub fn lock(&self) -> Result, Error> { + let cur = self.cursor.table_slice_by_index(0usize)?; + if cur.option_is_none() { + Ok(None) + } else { + let cur = cur.convert_to_rawbytes()?; + Ok(Some(cur.into())) + } + } +} +impl WitnessArgs { + pub fn input_type(&self) -> Result, Error> { + let cur = self.cursor.table_slice_by_index(1usize)?; + if cur.option_is_none() { + Ok(None) + } else { + let cur = cur.convert_to_rawbytes()?; + Ok(Some(cur.into())) + } + } +} +impl WitnessArgs { + pub fn output_type(&self) -> Result, Error> { + let cur = self.cursor.table_slice_by_index(2usize)?; + if cur.option_is_none() { + Ok(None) + } else { + let cur = cur.convert_to_rawbytes()?; + Ok(Some(cur.into())) + } + } +} +impl WitnessArgs { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + self.cursor.verify_table(3usize, compatible)?; + Ok(()) + } +} diff --git a/ckb-transaction-cobuild/src/schemas2/mod.rs b/ckb-transaction-cobuild/src/schemas2/mod.rs new file mode 100644 index 0000000..ac77eac --- /dev/null +++ b/ckb-transaction-cobuild/src/schemas2/mod.rs @@ -0,0 +1,4 @@ +#![allow(unused_imports)] +pub mod basic; +pub mod blockchain; +pub mod top_level; diff --git a/ckb-transaction-cobuild/src/schemas2/top_level.rs b/ckb-transaction-cobuild/src/schemas2/top_level.rs new file mode 100644 index 0000000..5838be8 --- /dev/null +++ b/ckb-transaction-cobuild/src/schemas2/top_level.rs @@ -0,0 +1,48 @@ +extern crate alloc; +use super::basic::*; +use core::convert::TryInto; +use molecule::lazy_reader::{Cursor, Error, NUMBER_SIZE}; +pub enum WitnessLayout { + SighashAll(SighashAll), + SighashAllOnly(SighashAllOnly), + Otx(Otx), + OtxStart(OtxStart), +} +impl TryFrom for WitnessLayout { + type Error = Error; + fn try_from(cur: Cursor) -> Result { + let item = cur.union_unpack()?; + let mut cur = cur; + cur.add_offset(NUMBER_SIZE)?; + cur.sub_size(NUMBER_SIZE)?; + match item.item_id { + 4278190081usize => Ok(Self::SighashAll(cur.into())), + 4278190082usize => Ok(Self::SighashAllOnly(cur.into())), + 4278190083usize => Ok(Self::Otx(cur.into())), + 4278190084usize => Ok(Self::OtxStart(cur.into())), + _ => Err(Error::UnknownItem), + } + } +} +impl WitnessLayout { + pub fn verify(&self, compatible: bool) -> Result<(), Error> { + match self { + Self::SighashAll(v) => { + v.verify(compatible)?; + Ok(()) + } + Self::SighashAllOnly(v) => { + v.verify(compatible)?; + Ok(()) + } + Self::Otx(v) => { + v.verify(compatible)?; + Ok(()) + } + Self::OtxStart(v) => { + v.verify(compatible)?; + Ok(()) + } + } + } +} diff --git a/contracts/transaction-cobuild-lock-demo/src/entry.rs b/contracts/transaction-cobuild-lock-demo/src/entry.rs index 2b856d3..5320461 100644 --- a/contracts/transaction-cobuild-lock-demo/src/entry.rs +++ b/contracts/transaction-cobuild-lock-demo/src/entry.rs @@ -32,9 +32,9 @@ impl Callback for Verifier { &self, seal: &[u8], signing_message_hash: &[u8; 32], - ) -> Result<(), ckb_transaction_cobuild::Error> { + ) -> Result<(), ckb_transaction_cobuild::error::Error> { ckb_auth(&self.entry, &self.id, seal, signing_message_hash) - .map_err(|_| ckb_transaction_cobuild::Error::AuthError)?; + .map_err(|_| ckb_transaction_cobuild::error::Error::AuthError)?; Ok(()) } } diff --git a/contracts/transaction-cobuild-lock-demo/src/error.rs b/contracts/transaction-cobuild-lock-demo/src/error.rs index d0b788d..a4b4034 100644 --- a/contracts/transaction-cobuild-lock-demo/src/error.rs +++ b/contracts/transaction-cobuild-lock-demo/src/error.rs @@ -17,6 +17,7 @@ pub enum Error { NoSealFound, ScriptHashAbsent, WrongCount, + LazyReader, } impl From for Error { @@ -32,19 +33,20 @@ impl From for Error { } } -impl From for Error { - fn from(err: ckb_transaction_cobuild::Error) -> Self { +impl From for Error { + fn from(err: ckb_transaction_cobuild::error::Error) -> Self { match err { - ckb_transaction_cobuild::Error::Sys(e) => e.into(), - ckb_transaction_cobuild::Error::MoleculeEncoding => Error::Encoding, - ckb_transaction_cobuild::Error::WrongSighashAll => Error::WrongSighashAll, - ckb_transaction_cobuild::Error::WrongWitnessLayout => Error::WrongWitnessLayout, - ckb_transaction_cobuild::Error::WrongOtxStart => Error::WrongOtxStart, - ckb_transaction_cobuild::Error::AuthError => Error::AuthError, - ckb_transaction_cobuild::Error::WrongOtx => Error::WrongOtx, - ckb_transaction_cobuild::Error::NoSealFound => Error::NoSealFound, - ckb_transaction_cobuild::Error::ScriptHashAbsent => Error::ScriptHashAbsent, - ckb_transaction_cobuild::Error::WrongCount => Error::WrongCount, + ckb_transaction_cobuild::error::Error::Sys(e) => e.into(), + ckb_transaction_cobuild::error::Error::MoleculeEncoding => Error::Encoding, + ckb_transaction_cobuild::error::Error::WrongSighashAll => Error::WrongSighashAll, + ckb_transaction_cobuild::error::Error::WrongWitnessLayout => Error::WrongWitnessLayout, + ckb_transaction_cobuild::error::Error::WrongOtxStart => Error::WrongOtxStart, + ckb_transaction_cobuild::error::Error::AuthError => Error::AuthError, + ckb_transaction_cobuild::error::Error::WrongOtx => Error::WrongOtx, + ckb_transaction_cobuild::error::Error::NoSealFound => Error::NoSealFound, + ckb_transaction_cobuild::error::Error::ScriptHashAbsent => Error::ScriptHashAbsent, + ckb_transaction_cobuild::error::Error::WrongCount => Error::WrongCount, + ckb_transaction_cobuild::error::Error::LazyReader(_) => Error::LazyReader, } } } diff --git a/contracts/transaction-cobuild-otx-lock-demo/src/entry.rs b/contracts/transaction-cobuild-otx-lock-demo/src/entry.rs index fc22e99..d37c985 100644 --- a/contracts/transaction-cobuild-otx-lock-demo/src/entry.rs +++ b/contracts/transaction-cobuild-otx-lock-demo/src/entry.rs @@ -32,11 +32,11 @@ impl Callback for Verifier { &self, seal: &[u8], signing_message_hash: &[u8; 32], - ) -> Result<(), ckb_transaction_cobuild::Error> { + ) -> Result<(), ckb_transaction_cobuild::error::Error> { let auth_result = ckb_auth(&self.entry, &self.id, seal, signing_message_hash); match auth_result { Ok(_) => Ok(()), - Err(_) => Err(ckb_transaction_cobuild::Error::AuthError), + Err(_) => Err(ckb_transaction_cobuild::error::Error::AuthError), } } } diff --git a/contracts/transaction-cobuild-otx-lock-demo/src/error.rs b/contracts/transaction-cobuild-otx-lock-demo/src/error.rs index d0b788d..a4b4034 100644 --- a/contracts/transaction-cobuild-otx-lock-demo/src/error.rs +++ b/contracts/transaction-cobuild-otx-lock-demo/src/error.rs @@ -17,6 +17,7 @@ pub enum Error { NoSealFound, ScriptHashAbsent, WrongCount, + LazyReader, } impl From for Error { @@ -32,19 +33,20 @@ impl From for Error { } } -impl From for Error { - fn from(err: ckb_transaction_cobuild::Error) -> Self { +impl From for Error { + fn from(err: ckb_transaction_cobuild::error::Error) -> Self { match err { - ckb_transaction_cobuild::Error::Sys(e) => e.into(), - ckb_transaction_cobuild::Error::MoleculeEncoding => Error::Encoding, - ckb_transaction_cobuild::Error::WrongSighashAll => Error::WrongSighashAll, - ckb_transaction_cobuild::Error::WrongWitnessLayout => Error::WrongWitnessLayout, - ckb_transaction_cobuild::Error::WrongOtxStart => Error::WrongOtxStart, - ckb_transaction_cobuild::Error::AuthError => Error::AuthError, - ckb_transaction_cobuild::Error::WrongOtx => Error::WrongOtx, - ckb_transaction_cobuild::Error::NoSealFound => Error::NoSealFound, - ckb_transaction_cobuild::Error::ScriptHashAbsent => Error::ScriptHashAbsent, - ckb_transaction_cobuild::Error::WrongCount => Error::WrongCount, + ckb_transaction_cobuild::error::Error::Sys(e) => e.into(), + ckb_transaction_cobuild::error::Error::MoleculeEncoding => Error::Encoding, + ckb_transaction_cobuild::error::Error::WrongSighashAll => Error::WrongSighashAll, + ckb_transaction_cobuild::error::Error::WrongWitnessLayout => Error::WrongWitnessLayout, + ckb_transaction_cobuild::error::Error::WrongOtxStart => Error::WrongOtxStart, + ckb_transaction_cobuild::error::Error::AuthError => Error::AuthError, + ckb_transaction_cobuild::error::Error::WrongOtx => Error::WrongOtx, + ckb_transaction_cobuild::error::Error::NoSealFound => Error::NoSealFound, + ckb_transaction_cobuild::error::Error::ScriptHashAbsent => Error::ScriptHashAbsent, + ckb_transaction_cobuild::error::Error::WrongCount => Error::WrongCount, + ckb_transaction_cobuild::error::Error::LazyReader(_) => Error::LazyReader, } } } diff --git a/tests/Cargo.lock b/tests/Cargo.lock index 1cbae1c..9a56d22 100644 --- a/tests/Cargo.lock +++ b/tests/Cargo.lock @@ -834,8 +834,6 @@ dependencies = [ [[package]] name = "molecule" version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd9767ab5e5f2ea40f71ff4c8bdb633c50509052e093c2fdd0e390a749dfa3" dependencies = [ "bytes", "cfg-if", diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 08517ac..81e5838 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -11,3 +11,6 @@ ckb-testtool = "0.10" ckb-auth-rs = { git = "https://github.com/nervosnetwork/ckb-auth.git", rev="df6e9ef"} rand = "0.6.5" molecule = { version = "0.7.5", default-features = false } + +[patch.crates-io] +molecule = { path = "../../molecule/bindings/rust" }