diff --git a/Cargo.lock b/Cargo.lock index b53a56d40e..1e39b8e623 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,8 +31,10 @@ dependencies = [ name = "aggregator-common" version = "0.1.0" dependencies = [ + "ckb-gen-types 0.116.1", "ckb-hash 0.116.1", "ckb-types 0.116.1", + "molecule", "secp256k1", "thiserror", ] @@ -848,6 +850,7 @@ dependencies = [ name = "ckb-chain-spec" version = "0.116.1" dependencies = [ + "aggregator-common", "cacache", "ckb-constant 0.116.1", "ckb-crypto 0.116.1", diff --git a/aggregator/util/common/Cargo.toml b/aggregator/util/common/Cargo.toml index de13f5cc5f..7278d55323 100644 --- a/aggregator/util/common/Cargo.toml +++ b/aggregator/util/common/Cargo.toml @@ -6,8 +6,10 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ckb-gen-types = { path = "../../../util/gen-types", version = "= 0.116.1" } ckb-hash = { path = "../../../util/hash", version = "= 0.116.1" } ckb-types = { path = "../../../util/types", version = "= 0.116.1" } +molecule = { version = "0.7.5", default-features = false } secp256k1 = { version = "0.24", features = ["recovery"] } thiserror = "1.0" \ No newline at end of file diff --git a/aggregator/util/common/src/lib.rs b/aggregator/util/common/src/lib.rs index cb45d0e1e5..a226438c8c 100644 --- a/aggregator/util/common/src/lib.rs +++ b/aggregator/util/common/src/lib.rs @@ -1,5 +1,6 @@ #![allow(missing_docs)] pub mod error; +pub mod schemas; pub mod types; pub mod utils; diff --git a/aggregator/util/common/src/schemas/leap.rs b/aggregator/util/common/src/schemas/leap.rs new file mode 100644 index 0000000000..2f72438277 --- /dev/null +++ b/aggregator/util/common/src/schemas/leap.rs @@ -0,0 +1,1983 @@ +// Generated by Molecule 0.7.5 + +use super::blockchain::*; +use molecule::prelude::*; +#[derive(Clone)] +pub struct RequestLockArgs(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for RequestLockArgs { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for RequestLockArgs { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for RequestLockArgs { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "request_type_hash", self.request_type_hash())?; + write!(f, ", {}: {}", "owner_lock_hash", self.owner_lock_hash())?; + write!(f, ", {}: {}", "timeout", self.timeout())?; + write!(f, ", {}: {}", "content", self.content())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for RequestLockArgs { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + RequestLockArgs::new_unchecked(v) + } +} +impl RequestLockArgs { + const DEFAULT_VALUE: [u8; 205] = [ + 205, 0, 0, 0, 20, 0, 0, 0, 52, 0, 0, 0, 84, 0, 0, 0, 92, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 113, 0, 0, 0, 20, 0, 0, 0, 21, 0, 0, 0, 25, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn request_type_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn owner_lock_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn timeout(&self) -> Uint64 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Uint64::new_unchecked(self.0.slice(start..end)) + } + pub fn content(&self) -> RequestContent { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + RequestContent::new_unchecked(self.0.slice(start..end)) + } else { + RequestContent::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> RequestLockArgsReader<'r> { + RequestLockArgsReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for RequestLockArgs { + type Builder = RequestLockArgsBuilder; + const NAME: &'static str = "RequestLockArgs"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + RequestLockArgs(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + RequestLockArgsReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + RequestLockArgsReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .request_type_hash(self.request_type_hash()) + .owner_lock_hash(self.owner_lock_hash()) + .timeout(self.timeout()) + .content(self.content()) + } +} +#[derive(Clone, Copy)] +pub struct RequestLockArgsReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for RequestLockArgsReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for RequestLockArgsReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for RequestLockArgsReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "request_type_hash", self.request_type_hash())?; + write!(f, ", {}: {}", "owner_lock_hash", self.owner_lock_hash())?; + write!(f, ", {}: {}", "timeout", self.timeout())?; + write!(f, ", {}: {}", "content", self.content())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> RequestLockArgsReader<'r> { + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn request_type_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn owner_lock_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn timeout(&self) -> Uint64Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn content(&self) -> RequestContentReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + RequestContentReader::new_unchecked(&self.as_slice()[start..end]) + } else { + RequestContentReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for RequestLockArgsReader<'r> { + type Entity = RequestLockArgs; + const NAME: &'static str = "RequestLockArgsReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + RequestLockArgsReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Byte32Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Uint64Reader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + RequestContentReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct RequestLockArgsBuilder { + pub(crate) request_type_hash: Byte32, + pub(crate) owner_lock_hash: Byte32, + pub(crate) timeout: Uint64, + pub(crate) content: RequestContent, +} +impl RequestLockArgsBuilder { + pub const FIELD_COUNT: usize = 4; + pub fn request_type_hash(mut self, v: Byte32) -> Self { + self.request_type_hash = v; + self + } + pub fn owner_lock_hash(mut self, v: Byte32) -> Self { + self.owner_lock_hash = v; + self + } + pub fn timeout(mut self, v: Uint64) -> Self { + self.timeout = v; + self + } + pub fn content(mut self, v: RequestContent) -> Self { + self.content = v; + self + } +} +impl molecule::prelude::Builder for RequestLockArgsBuilder { + type Entity = RequestLockArgs; + const NAME: &'static str = "RequestLockArgsBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.request_type_hash.as_slice().len() + + self.owner_lock_hash.as_slice().len() + + self.timeout.as_slice().len() + + self.content.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.request_type_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.owner_lock_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.timeout.as_slice().len(); + offsets.push(total_size); + total_size += self.content.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.request_type_hash.as_slice())?; + writer.write_all(self.owner_lock_hash.as_slice())?; + writer.write_all(self.timeout.as_slice())?; + writer.write_all(self.content.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + RequestLockArgs::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct CrossChainQueue(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for CrossChainQueue { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for CrossChainQueue { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for CrossChainQueue { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "locked_assets", self.locked_assets())?; + write!(f, ", {}: {}", "outbox", self.outbox())?; + write!(f, ", {}: {}", "inbox", self.inbox())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for CrossChainQueue { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + CrossChainQueue::new_unchecked(v) + } +} +impl CrossChainQueue { + const DEFAULT_VALUE: [u8; 56] = [ + 56, 0, 0, 0, 16, 0, 0, 0, 48, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn locked_assets(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn outbox(&self) -> Byte32Vec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32Vec::new_unchecked(self.0.slice(start..end)) + } + pub fn inbox(&self) -> Byte32Vec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + Byte32Vec::new_unchecked(self.0.slice(start..end)) + } else { + Byte32Vec::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> CrossChainQueueReader<'r> { + CrossChainQueueReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for CrossChainQueue { + type Builder = CrossChainQueueBuilder; + const NAME: &'static str = "CrossChainQueue"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + CrossChainQueue(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + CrossChainQueueReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + CrossChainQueueReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .locked_assets(self.locked_assets()) + .outbox(self.outbox()) + .inbox(self.inbox()) + } +} +#[derive(Clone, Copy)] +pub struct CrossChainQueueReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for CrossChainQueueReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for CrossChainQueueReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for CrossChainQueueReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "locked_assets", self.locked_assets())?; + write!(f, ", {}: {}", "outbox", self.outbox())?; + write!(f, ", {}: {}", "inbox", self.inbox())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> CrossChainQueueReader<'r> { + pub const FIELD_COUNT: usize = 3; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn locked_assets(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn outbox(&self) -> Byte32VecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Byte32VecReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn inbox(&self) -> Byte32VecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[16..]) as usize; + Byte32VecReader::new_unchecked(&self.as_slice()[start..end]) + } else { + Byte32VecReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for CrossChainQueueReader<'r> { + type Entity = CrossChainQueue; + const NAME: &'static str = "CrossChainQueueReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + CrossChainQueueReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Byte32VecReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Byte32VecReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct CrossChainQueueBuilder { + pub(crate) locked_assets: Byte32, + pub(crate) outbox: Byte32Vec, + pub(crate) inbox: Byte32Vec, +} +impl CrossChainQueueBuilder { + pub const FIELD_COUNT: usize = 3; + pub fn locked_assets(mut self, v: Byte32) -> Self { + self.locked_assets = v; + self + } + pub fn outbox(mut self, v: Byte32Vec) -> Self { + self.outbox = v; + self + } + pub fn inbox(mut self, v: Byte32Vec) -> Self { + self.inbox = v; + self + } +} +impl molecule::prelude::Builder for CrossChainQueueBuilder { + type Entity = CrossChainQueue; + const NAME: &'static str = "CrossChainQueueBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.locked_assets.as_slice().len() + + self.outbox.as_slice().len() + + self.inbox.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.locked_assets.as_slice().len(); + offsets.push(total_size); + total_size += self.outbox.as_slice().len(); + offsets.push(total_size); + total_size += self.inbox.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.locked_assets.as_slice())?; + writer.write_all(self.outbox.as_slice())?; + writer.write_all(self.inbox.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + CrossChainQueue::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct Requests(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Requests { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Requests { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Requests { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl ::core::default::Default for Requests { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Requests::new_unchecked(v) + } +} +impl Requests { + const DEFAULT_VALUE: [u8; 4] = [4, 0, 0, 0]; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> Request { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + Request::new_unchecked(self.0.slice(start..)) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + Request::new_unchecked(self.0.slice(start..end)) + } + } + pub fn as_reader<'r>(&'r self) -> RequestsReader<'r> { + RequestsReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Requests { + type Builder = RequestsBuilder; + const NAME: &'static str = "Requests"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Requests(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + RequestsReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + RequestsReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().extend(self.into_iter()) + } +} +#[derive(Clone, Copy)] +pub struct RequestsReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for RequestsReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for RequestsReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for RequestsReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} [", Self::NAME)?; + for i in 0..self.len() { + if i == 0 { + write!(f, "{}", self.get_unchecked(i))?; + } else { + write!(f, ", {}", self.get_unchecked(i))?; + } + } + write!(f, "]") + } +} +impl<'r> RequestsReader<'r> { + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn item_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn len(&self) -> usize { + self.item_count() + } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + pub fn get(&self, idx: usize) -> Option> { + if idx >= self.len() { + None + } else { + Some(self.get_unchecked(idx)) + } + } + pub fn get_unchecked(&self, idx: usize) -> RequestReader<'r> { + let slice = self.as_slice(); + let start_idx = molecule::NUMBER_SIZE * (1 + idx); + let start = molecule::unpack_number(&slice[start_idx..]) as usize; + if idx == self.len() - 1 { + RequestReader::new_unchecked(&self.as_slice()[start..]) + } else { + let end_idx = start_idx + molecule::NUMBER_SIZE; + let end = molecule::unpack_number(&slice[end_idx..]) as usize; + RequestReader::new_unchecked(&self.as_slice()[start..end]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for RequestsReader<'r> { + type Entity = Requests; + const NAME: &'static str = "RequestsReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + RequestsReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len == molecule::NUMBER_SIZE { + return Ok(()); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!( + Self, + TotalSizeNotMatch, + molecule::NUMBER_SIZE * 2, + slice_len + ); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + for pair in offsets.windows(2) { + let start = pair[0]; + let end = pair[1]; + RequestReader::verify(&slice[start..end], compatible)?; + } + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct RequestsBuilder(pub(crate) Vec); +impl RequestsBuilder { + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: Request) -> Self { + self.0.push(v); + self + } + pub fn extend>(mut self, iter: T) -> Self { + for elem in iter { + self.0.push(elem); + } + self + } + pub fn replace(&mut self, index: usize, v: Request) -> Option { + self.0 + .get_mut(index) + .map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for RequestsBuilder { + type Entity = Requests; + const NAME: &'static str = "RequestsBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (self.0.len() + 1) + + self + .0 + .iter() + .map(|inner| inner.as_slice().len()) + .sum::() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let item_count = self.0.len(); + if item_count == 0 { + writer.write_all(&molecule::pack_number( + molecule::NUMBER_SIZE as molecule::Number, + ))?; + } else { + let (total_size, offsets) = self.0.iter().fold( + ( + molecule::NUMBER_SIZE * (item_count + 1), + Vec::with_capacity(item_count), + ), + |(start, mut offsets), inner| { + offsets.push(start); + (start + inner.as_slice().len(), offsets) + }, + ); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + for inner in self.0.iter() { + writer.write_all(inner.as_slice())?; + } + } + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Requests::new_unchecked(inner.into()) + } +} +pub struct RequestsIterator(Requests, usize, usize); +impl ::core::iter::Iterator for RequestsIterator { + type Item = Request; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl ::core::iter::ExactSizeIterator for RequestsIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for Requests { + type Item = Request; + type IntoIter = RequestsIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + RequestsIterator(self, 0, len) + } +} +impl<'r> RequestsReader<'r> { + pub fn iter<'t>(&'t self) -> RequestsReaderIterator<'t, 'r> { + RequestsReaderIterator(&self, 0, self.len()) + } +} +pub struct RequestsReaderIterator<'t, 'r>(&'t RequestsReader<'r>, usize, usize); +impl<'t: 'r, 'r> ::core::iter::Iterator for RequestsReaderIterator<'t, 'r> { + type Item = RequestReader<'t>; + fn next(&mut self) -> Option { + if self.1 >= self.2 { + None + } else { + let ret = self.0.get_unchecked(self.1); + self.1 += 1; + Some(ret) + } + } +} +impl<'t: 'r, 'r> ::core::iter::ExactSizeIterator for RequestsReaderIterator<'t, 'r> { + fn len(&self) -> usize { + self.2 - self.1 + } +} +#[derive(Clone)] +pub struct Request(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Request { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Request { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Request { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "request_cell", self.request_cell())?; + write!(f, ", {}: {}", "request_content", self.request_content())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for Request { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Request::new_unchecked(v) + } +} +impl Request { + const DEFAULT_VALUE: [u8; 161] = [ + 161, 0, 0, 0, 12, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113, 0, 0, 0, 20, 0, 0, 0, 21, 0, + 0, 0, 25, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn request_cell(&self) -> OutPoint { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + OutPoint::new_unchecked(self.0.slice(start..end)) + } + pub fn request_content(&self) -> RequestContent { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + RequestContent::new_unchecked(self.0.slice(start..end)) + } else { + RequestContent::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> RequestReader<'r> { + RequestReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Request { + type Builder = RequestBuilder; + const NAME: &'static str = "Request"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Request(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + RequestReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + RequestReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .request_cell(self.request_cell()) + .request_content(self.request_content()) + } +} +#[derive(Clone, Copy)] +pub struct RequestReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for RequestReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for RequestReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for RequestReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "request_cell", self.request_cell())?; + write!(f, ", {}: {}", "request_content", self.request_content())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> RequestReader<'r> { + pub const FIELD_COUNT: usize = 2; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn request_cell(&self) -> OutPointReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + OutPointReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn request_content(&self) -> RequestContentReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[12..]) as usize; + RequestContentReader::new_unchecked(&self.as_slice()[start..end]) + } else { + RequestContentReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for RequestReader<'r> { + type Entity = Request; + const NAME: &'static str = "RequestReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + RequestReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + OutPointReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + RequestContentReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct RequestBuilder { + pub(crate) request_cell: OutPoint, + pub(crate) request_content: RequestContent, +} +impl RequestBuilder { + pub const FIELD_COUNT: usize = 2; + pub fn request_cell(mut self, v: OutPoint) -> Self { + self.request_cell = v; + self + } + pub fn request_content(mut self, v: RequestContent) -> Self { + self.request_content = v; + self + } +} +impl molecule::prelude::Builder for RequestBuilder { + type Entity = Request; + const NAME: &'static str = "RequestBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.request_cell.as_slice().len() + + self.request_content.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.request_cell.as_slice().len(); + offsets.push(total_size); + total_size += self.request_content.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.request_cell.as_slice())?; + writer.write_all(self.request_content.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Request::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct RequestContent(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for RequestContent { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for RequestContent { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for RequestContent { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "request_type", self.request_type())?; + write!(f, ", {}: {}", "initial_chain_id", self.initial_chain_id())?; + write!(f, ", {}: {}", "target_chain_id", self.target_chain_id())?; + write!(f, ", {}: {}", "message", self.message())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for RequestContent { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + RequestContent::new_unchecked(v) + } +} +impl RequestContent { + const DEFAULT_VALUE: [u8; 113] = [ + 113, 0, 0, 0, 20, 0, 0, 0, 21, 0, 0, 0, 25, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn request_type(&self) -> Byte { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Byte::new_unchecked(self.0.slice(start..end)) + } + pub fn initial_chain_id(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } + pub fn target_chain_id(&self) -> Bytes { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + Bytes::new_unchecked(self.0.slice(start..end)) + } + pub fn message(&self) -> Message { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + Message::new_unchecked(self.0.slice(start..end)) + } else { + Message::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> RequestContentReader<'r> { + RequestContentReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for RequestContent { + type Builder = RequestContentBuilder; + const NAME: &'static str = "RequestContent"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + RequestContent(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + RequestContentReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + RequestContentReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .request_type(self.request_type()) + .initial_chain_id(self.initial_chain_id()) + .target_chain_id(self.target_chain_id()) + .message(self.message()) + } +} +#[derive(Clone, Copy)] +pub struct RequestContentReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for RequestContentReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for RequestContentReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for RequestContentReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "request_type", self.request_type())?; + write!(f, ", {}: {}", "initial_chain_id", self.initial_chain_id())?; + write!(f, ", {}: {}", "target_chain_id", self.target_chain_id())?; + write!(f, ", {}: {}", "message", self.message())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> RequestContentReader<'r> { + pub const FIELD_COUNT: usize = 4; + pub fn total_size(&self) -> usize { + molecule::unpack_number(self.as_slice()) as usize + } + pub fn field_count(&self) -> usize { + if self.total_size() == molecule::NUMBER_SIZE { + 0 + } else { + (molecule::unpack_number(&self.as_slice()[molecule::NUMBER_SIZE..]) as usize / 4) - 1 + } + } + pub fn count_extra_fields(&self) -> usize { + self.field_count() - Self::FIELD_COUNT + } + pub fn has_extra_fields(&self) -> bool { + Self::FIELD_COUNT != self.field_count() + } + pub fn request_type(&self) -> ByteReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + ByteReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn initial_chain_id(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn target_chain_id(&self) -> BytesReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + BytesReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn message(&self) -> MessageReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[20..]) as usize; + MessageReader::new_unchecked(&self.as_slice()[start..end]) + } else { + MessageReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for RequestContentReader<'r> { + type Entity = RequestContent; + const NAME: &'static str = "RequestContentReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + RequestContentReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let total_size = molecule::unpack_number(slice) as usize; + if slice_len != total_size { + return ve!(Self, TotalSizeNotMatch, total_size, slice_len); + } + if slice_len < molecule::NUMBER_SIZE * 2 { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE * 2, slice_len); + } + let offset_first = molecule::unpack_number(&slice[molecule::NUMBER_SIZE..]) as usize; + if offset_first % molecule::NUMBER_SIZE != 0 || offset_first < molecule::NUMBER_SIZE * 2 { + return ve!(Self, OffsetsNotMatch); + } + if slice_len < offset_first { + return ve!(Self, HeaderIsBroken, offset_first, slice_len); + } + let field_count = offset_first / molecule::NUMBER_SIZE - 1; + if field_count < Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + } else if !compatible && field_count > Self::FIELD_COUNT { + return ve!(Self, FieldCountNotMatch, Self::FIELD_COUNT, field_count); + }; + let mut offsets: Vec = slice[molecule::NUMBER_SIZE..offset_first] + .chunks_exact(molecule::NUMBER_SIZE) + .map(|x| molecule::unpack_number(x) as usize) + .collect(); + offsets.push(total_size); + if offsets.windows(2).any(|i| i[0] > i[1]) { + return ve!(Self, OffsetsNotMatch); + } + ByteReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + BytesReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + MessageReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct RequestContentBuilder { + pub(crate) request_type: Byte, + pub(crate) initial_chain_id: Bytes, + pub(crate) target_chain_id: Bytes, + pub(crate) message: Message, +} +impl RequestContentBuilder { + pub const FIELD_COUNT: usize = 4; + pub fn request_type(mut self, v: Byte) -> Self { + self.request_type = v; + self + } + pub fn initial_chain_id(mut self, v: Bytes) -> Self { + self.initial_chain_id = v; + self + } + pub fn target_chain_id(mut self, v: Bytes) -> Self { + self.target_chain_id = v; + self + } + pub fn message(mut self, v: Message) -> Self { + self.message = v; + self + } +} +impl molecule::prelude::Builder for RequestContentBuilder { + type Entity = RequestContent; + const NAME: &'static str = "RequestContentBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.request_type.as_slice().len() + + self.initial_chain_id.as_slice().len() + + self.target_chain_id.as_slice().len() + + self.message.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); + let mut offsets = Vec::with_capacity(Self::FIELD_COUNT); + offsets.push(total_size); + total_size += self.request_type.as_slice().len(); + offsets.push(total_size); + total_size += self.initial_chain_id.as_slice().len(); + offsets.push(total_size); + total_size += self.target_chain_id.as_slice().len(); + offsets.push(total_size); + total_size += self.message.as_slice().len(); + writer.write_all(&molecule::pack_number(total_size as molecule::Number))?; + for offset in offsets.into_iter() { + writer.write_all(&molecule::pack_number(offset as molecule::Number))?; + } + writer.write_all(self.request_type.as_slice())?; + writer.write_all(self.initial_chain_id.as_slice())?; + writer.write_all(self.target_chain_id.as_slice())?; + writer.write_all(self.message.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + RequestContent::new_unchecked(inner.into()) + } +} +#[derive(Clone)] +pub struct Message(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Message { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Message { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Message { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl ::core::default::Default for Message { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Message::new_unchecked(v) + } +} +impl Message { + const DEFAULT_VALUE: [u8; 84] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const ITEMS_COUNT: usize = 1; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> MessageUnion { + let inner = self.0.slice(molecule::NUMBER_SIZE..); + match self.item_id() { + 0 => Transfer::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } + pub fn as_reader<'r>(&'r self) -> MessageReader<'r> { + MessageReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Message { + type Builder = MessageBuilder; + const NAME: &'static str = "Message"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Message(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + MessageReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + MessageReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder().set(self.to_enum()) + } +} +#[derive(Clone, Copy)] +pub struct MessageReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for MessageReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for MessageReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for MessageReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}(", Self::NAME)?; + self.to_enum().display_inner(f)?; + write!(f, ")") + } +} +impl<'r> MessageReader<'r> { + pub const ITEMS_COUNT: usize = 1; + pub fn item_id(&self) -> molecule::Number { + molecule::unpack_number(self.as_slice()) + } + pub fn to_enum(&self) -> MessageUnionReader<'r> { + let inner = &self.as_slice()[molecule::NUMBER_SIZE..]; + match self.item_id() { + 0 => TransferReader::new_unchecked(inner).into(), + _ => panic!("{}: invalid data", Self::NAME), + } + } +} +impl<'r> molecule::prelude::Reader<'r> for MessageReader<'r> { + type Entity = Message; + const NAME: &'static str = "MessageReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + MessageReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len < molecule::NUMBER_SIZE { + return ve!(Self, HeaderIsBroken, molecule::NUMBER_SIZE, slice_len); + } + let item_id = molecule::unpack_number(slice); + let inner_slice = &slice[molecule::NUMBER_SIZE..]; + match item_id { + 0 => TransferReader::verify(inner_slice, compatible), + _ => ve!(Self, UnknownItem, Self::ITEMS_COUNT, item_id), + }?; + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct MessageBuilder(pub(crate) MessageUnion); +impl MessageBuilder { + pub const ITEMS_COUNT: usize = 1; + pub fn set(mut self, v: I) -> Self + where + I: ::core::convert::Into, + { + self.0 = v.into(); + self + } +} +impl molecule::prelude::Builder for MessageBuilder { + type Entity = Message; + const NAME: &'static str = "MessageBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE + self.0.as_slice().len() + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(&molecule::pack_number(self.0.item_id()))?; + writer.write_all(self.0.as_slice()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Message::new_unchecked(inner.into()) + } +} +#[derive(Debug, Clone)] +pub enum MessageUnion { + Transfer(Transfer), +} +#[derive(Debug, Clone, Copy)] +pub enum MessageUnionReader<'r> { + Transfer(TransferReader<'r>), +} +impl ::core::default::Default for MessageUnion { + fn default() -> Self { + MessageUnion::Transfer(::core::default::Default::default()) + } +} +impl ::core::fmt::Display for MessageUnion { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + MessageUnion::Transfer(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Transfer::NAME, item) + } + } + } +} +impl<'r> ::core::fmt::Display for MessageUnionReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + MessageUnionReader::Transfer(ref item) => { + write!(f, "{}::{}({})", Self::NAME, Transfer::NAME, item) + } + } + } +} +impl MessageUnion { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + MessageUnion::Transfer(ref item) => write!(f, "{}", item), + } + } +} +impl<'r> MessageUnionReader<'r> { + pub(crate) fn display_inner(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + match self { + MessageUnionReader::Transfer(ref item) => write!(f, "{}", item), + } + } +} +impl ::core::convert::From for MessageUnion { + fn from(item: Transfer) -> Self { + MessageUnion::Transfer(item) + } +} +impl<'r> ::core::convert::From> for MessageUnionReader<'r> { + fn from(item: TransferReader<'r>) -> Self { + MessageUnionReader::Transfer(item) + } +} +impl MessageUnion { + pub const NAME: &'static str = "MessageUnion"; + pub fn as_bytes(&self) -> molecule::bytes::Bytes { + match self { + MessageUnion::Transfer(item) => item.as_bytes(), + } + } + pub fn as_slice(&self) -> &[u8] { + match self { + MessageUnion::Transfer(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + MessageUnion::Transfer(_) => 0, + } + } + pub fn item_name(&self) -> &str { + match self { + MessageUnion::Transfer(_) => "Transfer", + } + } + pub fn as_reader<'r>(&'r self) -> MessageUnionReader<'r> { + match self { + MessageUnion::Transfer(item) => item.as_reader().into(), + } + } +} +impl<'r> MessageUnionReader<'r> { + pub const NAME: &'r str = "MessageUnionReader"; + pub fn as_slice(&self) -> &'r [u8] { + match self { + MessageUnionReader::Transfer(item) => item.as_slice(), + } + } + pub fn item_id(&self) -> molecule::Number { + match self { + MessageUnionReader::Transfer(_) => 0, + } + } + pub fn item_name(&self) -> &str { + match self { + MessageUnionReader::Transfer(_) => "Transfer", + } + } +} +#[derive(Clone)] +pub struct Transfer(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for Transfer { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl ::core::fmt::Debug for Transfer { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for Transfer { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "owner_lock_hash", self.owner_lock_hash())?; + write!(f, ", {}: {}", "amount", self.amount())?; + write!(f, ", {}: {}", "asset_type", self.asset_type())?; + write!(f, " }}") + } +} +impl ::core::default::Default for Transfer { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + Transfer::new_unchecked(v) + } +} +impl Transfer { + const DEFAULT_VALUE: [u8; 80] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + pub const TOTAL_SIZE: usize = 80; + pub const FIELD_SIZES: [usize; 3] = [32, 16, 32]; + pub const FIELD_COUNT: usize = 3; + pub fn owner_lock_hash(&self) -> Byte32 { + Byte32::new_unchecked(self.0.slice(0..32)) + } + pub fn amount(&self) -> Uint128 { + Uint128::new_unchecked(self.0.slice(32..48)) + } + pub fn asset_type(&self) -> Byte32 { + Byte32::new_unchecked(self.0.slice(48..80)) + } + pub fn as_reader<'r>(&'r self) -> TransferReader<'r> { + TransferReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for Transfer { + type Builder = TransferBuilder; + const NAME: &'static str = "Transfer"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + Transfer(data) + } + fn as_bytes(&self) -> molecule::bytes::Bytes { + self.0.clone() + } + fn as_slice(&self) -> &[u8] { + &self.0[..] + } + fn from_slice(slice: &[u8]) -> molecule::error::VerificationResult { + TransferReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + TransferReader::from_compatible_slice(slice).map(|reader| reader.to_entity()) + } + fn new_builder() -> Self::Builder { + ::core::default::Default::default() + } + fn as_builder(self) -> Self::Builder { + Self::new_builder() + .owner_lock_hash(self.owner_lock_hash()) + .amount(self.amount()) + .asset_type(self.asset_type()) + } +} +#[derive(Clone, Copy)] +pub struct TransferReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for TransferReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + use molecule::hex_string; + if f.alternate() { + write!(f, "0x")?; + } + write!(f, "{}", hex_string(self.as_slice())) + } +} +impl<'r> ::core::fmt::Debug for TransferReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for TransferReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "owner_lock_hash", self.owner_lock_hash())?; + write!(f, ", {}: {}", "amount", self.amount())?; + write!(f, ", {}: {}", "asset_type", self.asset_type())?; + write!(f, " }}") + } +} +impl<'r> TransferReader<'r> { + pub const TOTAL_SIZE: usize = 80; + pub const FIELD_SIZES: [usize; 3] = [32, 16, 32]; + pub const FIELD_COUNT: usize = 3; + pub fn owner_lock_hash(&self) -> Byte32Reader<'r> { + Byte32Reader::new_unchecked(&self.as_slice()[0..32]) + } + pub fn amount(&self) -> Uint128Reader<'r> { + Uint128Reader::new_unchecked(&self.as_slice()[32..48]) + } + pub fn asset_type(&self) -> Byte32Reader<'r> { + Byte32Reader::new_unchecked(&self.as_slice()[48..80]) + } +} +impl<'r> molecule::prelude::Reader<'r> for TransferReader<'r> { + type Entity = Transfer; + const NAME: &'static str = "TransferReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + TransferReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], _compatible: bool) -> molecule::error::VerificationResult<()> { + use molecule::verification_error as ve; + let slice_len = slice.len(); + if slice_len != Self::TOTAL_SIZE { + return ve!(Self, TotalSizeNotMatch, Self::TOTAL_SIZE, slice_len); + } + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct TransferBuilder { + pub(crate) owner_lock_hash: Byte32, + pub(crate) amount: Uint128, + pub(crate) asset_type: Byte32, +} +impl TransferBuilder { + pub const TOTAL_SIZE: usize = 80; + pub const FIELD_SIZES: [usize; 3] = [32, 16, 32]; + pub const FIELD_COUNT: usize = 3; + pub fn owner_lock_hash(mut self, v: Byte32) -> Self { + self.owner_lock_hash = v; + self + } + pub fn amount(mut self, v: Uint128) -> Self { + self.amount = v; + self + } + pub fn asset_type(mut self, v: Byte32) -> Self { + self.asset_type = v; + self + } +} +impl molecule::prelude::Builder for TransferBuilder { + type Entity = Transfer; + const NAME: &'static str = "TransferBuilder"; + fn expected_length(&self) -> usize { + Self::TOTAL_SIZE + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + writer.write_all(self.owner_lock_hash.as_slice())?; + writer.write_all(self.amount.as_slice())?; + writer.write_all(self.asset_type.as_slice())?; + Ok(()) + } + fn build(&self) -> Self::Entity { + let mut inner = Vec::with_capacity(self.expected_length()); + self.write(&mut inner) + .unwrap_or_else(|_| panic!("{} build should be ok", Self::NAME)); + Transfer::new_unchecked(inner.into()) + } +} diff --git a/aggregator/util/common/src/schemas/mod.rs b/aggregator/util/common/src/schemas/mod.rs new file mode 100644 index 0000000000..c41fda299f --- /dev/null +++ b/aggregator/util/common/src/schemas/mod.rs @@ -0,0 +1,12 @@ +#![allow(clippy::needless_lifetimes)] +#![allow(clippy::write_literal)] +#![allow(clippy::if_same_then_else)] +#![allow(clippy::needless_borrow)] +#![allow(clippy::derivable_impls)] +#![allow(clippy::useless_conversion)] +#![allow(clippy::redundant_slicing)] +#![allow(clippy::wrong_self_convention)] +#![allow(dead_code)] + +pub mod leap; +pub use ckb_gen_types::packed as blockchain; diff --git a/benches/benches/benchmarks/resolve.rs b/benches/benches/benchmarks/resolve.rs index 29ce56bc8c..14673966f4 100644 --- a/benches/benches/benchmarks/resolve.rs +++ b/benches/benches/benchmarks/resolve.rs @@ -79,6 +79,7 @@ pub fn setup_chain(txs_size: usize) -> (Shared, ChainController) { spec.genesis.issued_cells = (0..txs_size) .map(|_| IssuedCell { capacity: capacity_bytes!(100_000), + with_queue: false, lock: secp_script.clone().into(), }) .collect(); diff --git a/resource/build.rs b/resource/build.rs index ff4e01583a..0bbe96d9a2 100644 --- a/resource/build.rs +++ b/resource/build.rs @@ -21,6 +21,7 @@ fn main() { "ckb-aggregator.toml", "default.db-options", "xudt_rce", + "request-cell-lock", ] { bundled .add_file(f, Compression::Gzip) diff --git a/resource/ckb-aggregator.toml b/resource/ckb-aggregator.toml index 004c008436..442c2fe435 100644 --- a/resource/ckb-aggregator.toml +++ b/resource/ckb-aggregator.toml @@ -50,6 +50,7 @@ rgbpp_custodian_lock_key_path = "../dev/rgbpp_custodian_lock_key" branch_uri = "http://localhost:8114" branch_chain_capacity_provider_key_path = "../dev/branch_chain_capacity_provider_key" branch_chain_token_manager_lock_key_path = "../dev/branch_chain_token_manager_key" +branch_chain_token_manager_outbox_lock_key_path = "../dev/branch_chain_token_manager_outbox_key" [[aggregator.gbpp_scripts]] script_name = "secp256k1_blake160" @@ -141,7 +142,7 @@ cell_dep = ''' "dep_type": "dep_group", "out_point": { "index": "0x0", - "tx_hash": "0x8cca9bc6626cd5bd9890e5468cee855b87943b1fa4c0db92c39ba4f0dd61b90c" + "tx_hash": "0xdd4fea4dc94ae5b3bd5a8a169f7edf6ea731689eec39b94f395a1a8ea1321205" } } ''' @@ -160,7 +161,26 @@ cell_dep = ''' "dep_type": "code", "out_point": { "index": "0x5", - "tx_hash": "0xad501cf59dc57021e4e4879a5f54aff4fe91771685e9fcfa3896ecdbf0664ed4" + "tx_hash": "0x7f1180615b86b8216cfb4a9b5421828c41f766f8d3111239e63d253d2ad81381" + } +} +''' + +[[aggregator.branch_scripts]] +script_name = "request_lock" +script = ''' +{ + "args": "0x", + "code_hash": "0x1a1e4fef34f5982906f745b048fe7b1089647e82346074e0f32c2ece26cf6b1e", + "hash_type": "type" +} +''' +cell_dep = ''' +{ + "dep_type": "code", + "out_point": { + "index": "0x6", + "tx_hash": "0x7f1180615b86b8216cfb4a9b5421828c41f766f8d3111239e63d253d2ad81381" } } ''' @@ -196,4 +216,14 @@ script = ''' "code_hash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", "hash_type": "type" } +''' + +[[aggregator.rgbpp_asset_locks]] +lock_hash = "0a97a585361f3deabb69f28b2bc08d05f3a224cd1ce805996526c8f041a733fb" +script = ''' +{ + "args": "0xa0c73e84d827b87073a2a0e6448921870d114d02", + "code_hash": "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", + "hash_type": "type" +} ''' \ No newline at end of file diff --git a/resource/request-cell-lock b/resource/request-cell-lock new file mode 100755 index 0000000000..5cece257b9 Binary files /dev/null and b/resource/request-cell-lock differ diff --git a/resource/specs/dev.toml b/resource/specs/dev.toml index 68f1f14616..771dc700f4 100644 --- a/resource/specs/dev.toml +++ b/resource/specs/dev.toml @@ -40,6 +40,10 @@ capacity = 100_000_0000_0000 file = { bundled = "xudt_rce" } create_type_id = true capacity = 1_0000_0000 +[[genesis.system_cells]] +file = { bundled = "request-cell-lock" } +create_type_id = true +capacity = 1_0000_0000 [genesis.system_cells_lock] code_hash = "0x0000000000000000000000000000000000000000000000000000000000000000" @@ -87,6 +91,14 @@ lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3 lock.args = "0x470dcdc5e44064909650113a274b3b36aecb6dc7" lock.hash_type = "type" +# issue for random generated private key: f0c764b96a2760739090bb14638f481222292026667d089dcb7e8d34d71fab61 +[[genesis.issued_cells]] +capacity = 200_00000000 +with_queue = true +lock.code_hash = "0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8" +lock.args = "0x1444d370978d96e4d68bbbd9cca99d93b20b0bc6" +lock.hash_type = "type" + [params] max_block_cycles = 10_000_000_000 cellbase_maturity = 1 diff --git a/spec/Cargo.toml b/spec/Cargo.toml index 027b0a4911..7ff23a795d 100644 --- a/spec/Cargo.toml +++ b/spec/Cargo.toml @@ -24,7 +24,7 @@ ckb-hash = { path = "../util/hash", version = "= 0.116.1"} ckb-error = { path = "../error", version = "= 0.116.1" } ckb-traits = { path = "../traits", version = "= 0.116.1" } ckb-logger = {path = "../util/logger", version = "= 0.116.1"} - +aggregator-common = { path = "../aggregator/util/common", version = "= 0.1.0" } [dev-dependencies] tempfile.workspace = true diff --git a/spec/src/lib.rs b/spec/src/lib.rs index 1c25e1dce3..5a47d9c034 100644 --- a/spec/src/lib.rs +++ b/spec/src/lib.rs @@ -16,6 +16,7 @@ use crate::consensus::{ TYPE_ID_CODE_HASH, }; use crate::versionbits::{ActiveMode, Deployment, DeploymentPos}; +use aggregator_common::schemas::leap; use ckb_constant::hardfork::{mainnet, testnet}; use ckb_crypto::secp::Privkey; use ckb_hash::{blake2b_256, new_blake2b}; @@ -66,7 +67,7 @@ pub const OUTPUT_INDEX_SECP256K1_DATA: u64 = 3; /// The output index of SECP256K1/multisig script in the genesis no.0 transaction pub const OUTPUT_INDEX_SECP256K1_BLAKE160_MULTISIG_ALL: u64 = 4; /// The output index of Token Manager script in the genesis no.0 transaction -pub const OUTPUT_INDEX_TOKEN_MANAGER: u64 = 9; +pub const OUTPUT_INDEX_TOKEN_MANAGER: u64 = 10; /// The CKB block chain specification #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] @@ -403,6 +404,9 @@ pub struct GenesisCell { pub struct IssuedCell { /// The cell capacity pub capacity: Capacity, + /// The cell data + #[serde(default)] + pub with_queue: bool, /// The cell lock pub lock: Script, } @@ -811,7 +815,14 @@ impl ChainSpec { .iter() .map(IssuedCell::build_output), ); - outputs_data.extend(self.genesis.issued_cells.iter().map(|_| Bytes::new())); + outputs_data.extend(self.genesis.issued_cells.iter().map(|cell| { + if cell.with_queue { + let queue = leap::CrossChainQueue::new_builder().build(); + queue.as_bytes() + } else { + Bytes::new() + } + })); let script: packed::Script = self.genesis.bootstrap_lock.clone().into(); diff --git a/test/src/specs/dao/satoshi_dao_occupied.rs b/test/src/specs/dao/satoshi_dao_occupied.rs index 5756d25ceb..46e7393bf4 100644 --- a/test/src/specs/dao/satoshi_dao_occupied.rs +++ b/test/src/specs/dao/satoshi_dao_occupied.rs @@ -156,6 +156,7 @@ fn issue_satoshi_cell() -> IssuedCell { .build(); IssuedCell { capacity: SATOSHI_CELL_CAPACITY, + with_queue: false, lock: lock.into(), } }