diff --git a/src/fiber/gen/fiber.rs b/src/fiber/gen/fiber.rs index a553f2eed..a9a1bf644 100644 --- a/src/fiber/gen/fiber.rs +++ b/src/fiber/gen/fiber.rs @@ -11764,3 +11764,705 @@ impl From for FiberMessage { Self::new_builder().set(value).build() } } +#[derive(Clone)] +pub struct PaymentPreimageOpt(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for PaymentPreimageOpt { + 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 PaymentPreimageOpt { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for PaymentPreimageOpt { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) + } else { + write!(f, "{}(None)", Self::NAME) + } + } +} +impl ::core::default::Default for PaymentPreimageOpt { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + PaymentPreimageOpt::new_unchecked(v) + } +} +impl PaymentPreimageOpt { + const DEFAULT_VALUE: [u8; 0] = []; + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option { + if self.is_none() { + None + } else { + Some(Byte32::new_unchecked(self.0.clone())) + } + } + pub fn as_reader<'r>(&'r self) -> PaymentPreimageOptReader<'r> { + PaymentPreimageOptReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for PaymentPreimageOpt { + type Builder = PaymentPreimageOptBuilder; + const NAME: &'static str = "PaymentPreimageOpt"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + PaymentPreimageOpt(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 { + PaymentPreimageOptReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + PaymentPreimageOptReader::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_opt()) + } +} +#[derive(Clone, Copy)] +pub struct PaymentPreimageOptReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for PaymentPreimageOptReader<'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 PaymentPreimageOptReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for PaymentPreimageOptReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) + } else { + write!(f, "{}(None)", Self::NAME) + } + } +} +impl<'r> PaymentPreimageOptReader<'r> { + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option> { + if self.is_none() { + None + } else { + Some(Byte32Reader::new_unchecked(self.as_slice())) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for PaymentPreimageOptReader<'r> { + type Entity = PaymentPreimageOpt; + const NAME: &'static str = "PaymentPreimageOptReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + PaymentPreimageOptReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + if !slice.is_empty() { + Byte32Reader::verify(&slice[..], compatible)?; + } + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct PaymentPreimageOptBuilder(pub(crate) Option); +impl PaymentPreimageOptBuilder { + pub fn set(mut self, v: Option) -> Self { + self.0 = v; + self + } +} +impl molecule::prelude::Builder for PaymentPreimageOptBuilder { + type Entity = PaymentPreimageOpt; + const NAME: &'static str = "PaymentPreimageOptBuilder"; + fn expected_length(&self) -> usize { + self.0 + .as_ref() + .map(|ref inner| inner.as_slice().len()) + .unwrap_or(0) + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + self.0 + .as_ref() + .map(|ref inner| writer.write_all(inner.as_slice())) + .unwrap_or(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)); + PaymentPreimageOpt::new_unchecked(inner.into()) + } +} +impl From for PaymentPreimageOpt { + fn from(value: Byte32) -> Self { + Self::new_builder().set(Some(value)).build() + } +} +#[derive(Clone)] +pub struct PubkeyOpt(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for PubkeyOpt { + 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 PubkeyOpt { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for PubkeyOpt { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) + } else { + write!(f, "{}(None)", Self::NAME) + } + } +} +impl ::core::default::Default for PubkeyOpt { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + PubkeyOpt::new_unchecked(v) + } +} +impl PubkeyOpt { + const DEFAULT_VALUE: [u8; 0] = []; + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option { + if self.is_none() { + None + } else { + Some(Pubkey::new_unchecked(self.0.clone())) + } + } + pub fn as_reader<'r>(&'r self) -> PubkeyOptReader<'r> { + PubkeyOptReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for PubkeyOpt { + type Builder = PubkeyOptBuilder; + const NAME: &'static str = "PubkeyOpt"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + PubkeyOpt(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 { + PubkeyOptReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + PubkeyOptReader::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_opt()) + } +} +#[derive(Clone, Copy)] +pub struct PubkeyOptReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for PubkeyOptReader<'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 PubkeyOptReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for PubkeyOptReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + if let Some(v) = self.to_opt() { + write!(f, "{}(Some({}))", Self::NAME, v) + } else { + write!(f, "{}(None)", Self::NAME) + } + } +} +impl<'r> PubkeyOptReader<'r> { + pub fn is_none(&self) -> bool { + self.0.is_empty() + } + pub fn is_some(&self) -> bool { + !self.0.is_empty() + } + pub fn to_opt(&self) -> Option> { + if self.is_none() { + None + } else { + Some(PubkeyReader::new_unchecked(self.as_slice())) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for PubkeyOptReader<'r> { + type Entity = PubkeyOpt; + const NAME: &'static str = "PubkeyOptReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + PubkeyOptReader(slice) + } + fn as_slice(&self) -> &'r [u8] { + self.0 + } + fn verify(slice: &[u8], compatible: bool) -> molecule::error::VerificationResult<()> { + if !slice.is_empty() { + PubkeyReader::verify(&slice[..], compatible)?; + } + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct PubkeyOptBuilder(pub(crate) Option); +impl PubkeyOptBuilder { + pub fn set(mut self, v: Option) -> Self { + self.0 = v; + self + } +} +impl molecule::prelude::Builder for PubkeyOptBuilder { + type Entity = PubkeyOpt; + const NAME: &'static str = "PubkeyOptBuilder"; + fn expected_length(&self) -> usize { + self.0 + .as_ref() + .map(|ref inner| inner.as_slice().len()) + .unwrap_or(0) + } + fn write(&self, writer: &mut W) -> molecule::io::Result<()> { + self.0 + .as_ref() + .map(|ref inner| writer.write_all(inner.as_slice())) + .unwrap_or(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)); + PubkeyOpt::new_unchecked(inner.into()) + } +} +impl From for PubkeyOpt { + fn from(value: Pubkey) -> Self { + Self::new_builder().set(Some(value)).build() + } +} +#[derive(Clone)] +pub struct PaymentHopData(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for PaymentHopData { + 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 PaymentHopData { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for PaymentHopData { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "amount", self.amount())?; + write!(f, ", {}: {}", "expiry", self.expiry())?; + write!(f, ", {}: {}", "payment_preimage", self.payment_preimage())?; + write!(f, ", {}: {}", "hash_algorithm", self.hash_algorithm())?; + write!(f, ", {}: {}", "funding_tx_hash", self.funding_tx_hash())?; + write!(f, ", {}: {}", "next_hop", self.next_hop())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl ::core::default::Default for PaymentHopData { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + PaymentHopData::new_unchecked(v) + } +} +impl PaymentHopData { + const DEFAULT_VALUE: [u8; 85] = [ + 85, 0, 0, 0, 28, 0, 0, 0, 44, 0, 0, 0, 52, 0, 0, 0, 52, 0, 0, 0, 53, 0, 0, 0, 85, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 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 = 6; + 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 amount(&self) -> Uint128 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Uint128::new_unchecked(self.0.slice(start..end)) + } + pub fn expiry(&self) -> Uint64 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Uint64::new_unchecked(self.0.slice(start..end)) + } + pub fn payment_preimage(&self) -> PaymentPreimageOpt { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + PaymentPreimageOpt::new_unchecked(self.0.slice(start..end)) + } + pub fn hash_algorithm(&self) -> Byte { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Byte::new_unchecked(self.0.slice(start..end)) + } + pub fn funding_tx_hash(&self) -> Byte32 { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + Byte32::new_unchecked(self.0.slice(start..end)) + } + pub fn next_hop(&self) -> PubkeyOpt { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[28..]) as usize; + PubkeyOpt::new_unchecked(self.0.slice(start..end)) + } else { + PubkeyOpt::new_unchecked(self.0.slice(start..)) + } + } + pub fn as_reader<'r>(&'r self) -> PaymentHopDataReader<'r> { + PaymentHopDataReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for PaymentHopData { + type Builder = PaymentHopDataBuilder; + const NAME: &'static str = "PaymentHopData"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + PaymentHopData(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 { + PaymentHopDataReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + PaymentHopDataReader::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() + .amount(self.amount()) + .expiry(self.expiry()) + .payment_preimage(self.payment_preimage()) + .hash_algorithm(self.hash_algorithm()) + .funding_tx_hash(self.funding_tx_hash()) + .next_hop(self.next_hop()) + } +} +#[derive(Clone, Copy)] +pub struct PaymentHopDataReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for PaymentHopDataReader<'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 PaymentHopDataReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for PaymentHopDataReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{} {{ ", Self::NAME)?; + write!(f, "{}: {}", "amount", self.amount())?; + write!(f, ", {}: {}", "expiry", self.expiry())?; + write!(f, ", {}: {}", "payment_preimage", self.payment_preimage())?; + write!(f, ", {}: {}", "hash_algorithm", self.hash_algorithm())?; + write!(f, ", {}: {}", "funding_tx_hash", self.funding_tx_hash())?; + write!(f, ", {}: {}", "next_hop", self.next_hop())?; + let extra_count = self.count_extra_fields(); + if extra_count != 0 { + write!(f, ", .. ({} fields)", extra_count)?; + } + write!(f, " }}") + } +} +impl<'r> PaymentHopDataReader<'r> { + pub const FIELD_COUNT: usize = 6; + 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 amount(&self) -> Uint128Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[4..]) as usize; + let end = molecule::unpack_number(&slice[8..]) as usize; + Uint128Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn expiry(&self) -> Uint64Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[8..]) as usize; + let end = molecule::unpack_number(&slice[12..]) as usize; + Uint64Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn payment_preimage(&self) -> PaymentPreimageOptReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[12..]) as usize; + let end = molecule::unpack_number(&slice[16..]) as usize; + PaymentPreimageOptReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn hash_algorithm(&self) -> ByteReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + ByteReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn funding_tx_hash(&self) -> Byte32Reader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + Byte32Reader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn next_hop(&self) -> PubkeyOptReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[24..]) as usize; + if self.has_extra_fields() { + let end = molecule::unpack_number(&slice[28..]) as usize; + PubkeyOptReader::new_unchecked(&self.as_slice()[start..end]) + } else { + PubkeyOptReader::new_unchecked(&self.as_slice()[start..]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for PaymentHopDataReader<'r> { + type Entity = PaymentHopData; + const NAME: &'static str = "PaymentHopDataReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + PaymentHopDataReader(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); + } + Uint128Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + Uint64Reader::verify(&slice[offsets[1]..offsets[2]], compatible)?; + PaymentPreimageOptReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; + ByteReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + Byte32Reader::verify(&slice[offsets[4]..offsets[5]], compatible)?; + PubkeyOptReader::verify(&slice[offsets[5]..offsets[6]], compatible)?; + Ok(()) + } +} +#[derive(Clone, Debug, Default)] +pub struct PaymentHopDataBuilder { + pub(crate) amount: Uint128, + pub(crate) expiry: Uint64, + pub(crate) payment_preimage: PaymentPreimageOpt, + pub(crate) hash_algorithm: Byte, + pub(crate) funding_tx_hash: Byte32, + pub(crate) next_hop: PubkeyOpt, +} +impl PaymentHopDataBuilder { + pub const FIELD_COUNT: usize = 6; + pub fn amount(mut self, v: Uint128) -> Self { + self.amount = v; + self + } + pub fn expiry(mut self, v: Uint64) -> Self { + self.expiry = v; + self + } + pub fn payment_preimage(mut self, v: PaymentPreimageOpt) -> Self { + self.payment_preimage = v; + self + } + pub fn hash_algorithm(mut self, v: Byte) -> Self { + self.hash_algorithm = v; + self + } + pub fn funding_tx_hash(mut self, v: Byte32) -> Self { + self.funding_tx_hash = v; + self + } + pub fn next_hop(mut self, v: PubkeyOpt) -> Self { + self.next_hop = v; + self + } +} +impl molecule::prelude::Builder for PaymentHopDataBuilder { + type Entity = PaymentHopData; + const NAME: &'static str = "PaymentHopDataBuilder"; + fn expected_length(&self) -> usize { + molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1) + + self.amount.as_slice().len() + + self.expiry.as_slice().len() + + self.payment_preimage.as_slice().len() + + self.hash_algorithm.as_slice().len() + + self.funding_tx_hash.as_slice().len() + + self.next_hop.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.amount.as_slice().len(); + offsets.push(total_size); + total_size += self.expiry.as_slice().len(); + offsets.push(total_size); + total_size += self.payment_preimage.as_slice().len(); + offsets.push(total_size); + total_size += self.hash_algorithm.as_slice().len(); + offsets.push(total_size); + total_size += self.funding_tx_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.next_hop.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.amount.as_slice())?; + writer.write_all(self.expiry.as_slice())?; + writer.write_all(self.payment_preimage.as_slice())?; + writer.write_all(self.hash_algorithm.as_slice())?; + writer.write_all(self.funding_tx_hash.as_slice())?; + writer.write_all(self.next_hop.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)); + PaymentHopData::new_unchecked(inner.into()) + } +} diff --git a/src/fiber/gen/gossip.rs b/src/fiber/gen/gossip.rs index b4d849c66..b8e8a0010 100644 --- a/src/fiber/gen/gossip.rs +++ b/src/fiber/gen/gossip.rs @@ -8707,10 +8707,7 @@ impl ::core::default::Default for TlcErr { } } impl TlcErr { - const DEFAULT_VALUE: [u8; 44] = [ - 44, 0, 0, 0, 12, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]; + const DEFAULT_VALUE: [u8; 16] = [16, 0, 0, 0, 12, 0, 0, 0, 16, 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 @@ -8728,11 +8725,11 @@ impl TlcErr { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn error_code(&self) -> Byte32 { + pub fn error_code(&self) -> Bytes { 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)) + Bytes::new_unchecked(self.0.slice(start..end)) } pub fn extra_data(&self) -> TlcErrDataOpt { let slice = self.as_slice(); @@ -8821,11 +8818,11 @@ impl<'r> TlcErrReader<'r> { pub fn has_extra_fields(&self) -> bool { Self::FIELD_COUNT != self.field_count() } - pub fn error_code(&self) -> Byte32Reader<'r> { + pub fn error_code(&self) -> BytesReader<'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]) + BytesReader::new_unchecked(&self.as_slice()[start..end]) } pub fn extra_data(&self) -> TlcErrDataOptReader<'r> { let slice = self.as_slice(); @@ -8884,19 +8881,19 @@ impl<'r> molecule::prelude::Reader<'r> for TlcErrReader<'r> { if offsets.windows(2).any(|i| i[0] > i[1]) { return ve!(Self, OffsetsNotMatch); } - Byte32Reader::verify(&slice[offsets[0]..offsets[1]], compatible)?; + BytesReader::verify(&slice[offsets[0]..offsets[1]], compatible)?; TlcErrDataOptReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; Ok(()) } } #[derive(Clone, Debug, Default)] pub struct TlcErrBuilder { - pub(crate) error_code: Byte32, + pub(crate) error_code: Bytes, pub(crate) extra_data: TlcErrDataOpt, } impl TlcErrBuilder { pub const FIELD_COUNT: usize = 2; - pub fn error_code(mut self, v: Byte32) -> Self { + pub fn error_code(mut self, v: Bytes) -> Self { self.error_code = v; self } diff --git a/src/fiber/schema/fiber.mol b/src/fiber/schema/fiber.mol index 19f0691e9..99a876c26 100644 --- a/src/fiber/schema/fiber.mol +++ b/src/fiber/schema/fiber.mol @@ -187,3 +187,14 @@ union FiberMessage { ReestablishChannel, AnnouncementSignatures, } + +option PaymentPreimageOpt (Byte32); +option PubkeyOpt (Pubkey); +table PaymentHopData { + amount: Uint128, + expiry: Uint64, + payment_preimage: PaymentPreimageOpt, + hash_algorithm: byte, + funding_tx_hash: Byte32, + next_hop: PubkeyOpt, +} \ No newline at end of file diff --git a/src/fiber/schema/gossip.mol b/src/fiber/schema/gossip.mol index 7f1ea634c..8e0abd85c 100644 --- a/src/fiber/schema/gossip.mol +++ b/src/fiber/schema/gossip.mol @@ -185,6 +185,6 @@ union TlcErrData { option TlcErrDataOpt (TlcErrData); table TlcErr { - error_code: Byte32, + error_code: Bytes, extra_data: TlcErrDataOpt, } \ No newline at end of file diff --git a/src/fiber/tests/channel.rs b/src/fiber/tests/channel.rs index 2ec3cc2a1..95d0f459c 100644 --- a/src/fiber/tests/channel.rs +++ b/src/fiber/tests/channel.rs @@ -1452,8 +1452,9 @@ async fn test_send_payment_with_max_nodes() { let res = res.unwrap(); assert_eq!(res.status, PaymentSessionStatus::Inflight); assert!(res.fee > 0); - // sleep for 2 seconds to make sure the payment is sent - tokio::time::sleep(tokio::time::Duration::from_millis(3000)).await; + + // sleep for 5 seconds to make sure the payment is sent + tokio::time::sleep(tokio::time::Duration::from_millis(5000)).await; let message = |rpc_reply| -> NetworkActorMessage { NetworkActorMessage::Command(NetworkActorCommand::GetPayment(res.payment_hash, rpc_reply)) }; diff --git a/src/fiber/tests/types.rs b/src/fiber/tests/types.rs index 9ee86d259..b630d222a 100644 --- a/src/fiber/tests/types.rs +++ b/src/fiber/tests/types.rs @@ -234,3 +234,11 @@ fn test_tlc_err_packet_encryption() { assert_eq!(decrypted_tlc_fail_detail, tlc_fail_detail); } } + +#[test] +fn test_tlc_error_code() { + let code = TlcErrorCode::PermanentNodeFailure; + let str = code.as_ref().to_string(); + let code2 = TlcErrorCode::from_str(&str).expect("parse"); + assert_eq!(code, code2); +} diff --git a/src/fiber/types.rs b/src/fiber/types.rs index 6e69de18a..46b8b020d 100644 --- a/src/fiber/types.rs +++ b/src/fiber/types.rs @@ -1,7 +1,10 @@ use super::channel::{ChannelFlags, CHANNEL_DISABLED_FLAG, MESSAGE_OF_NODE2_FLAG}; use super::config::AnnouncedNodeName; -use super::gen::fiber::{self as molecule_fiber, PubNonce as Byte66, UdtCellDeps, Uint128Opt}; -use super::gen::gossip::{self as molecule_gossip}; +use super::gen::fiber::{ + self as molecule_fiber, PaymentPreimageOpt, PubNonce as Byte66, PubkeyOpt, UdtCellDeps, + Uint128Opt, +}; +use super::gen::gossip::{self as molecule_gossip, ChannelUpdateOpt, TlcErrDataOpt}; use super::hash_algorithm::{HashAlgorithm, UnknownHashAlgorithmError}; use super::network::get_chain_hash; use super::r#gen::fiber::PubNonceOpt; @@ -1107,70 +1110,6 @@ impl TryFrom for RemoveTlcFulfill { } } -// impl From for molecule_gossip::TlcErr { -// fn from(tlc_err: TlcErr) -> Self { -// molecule_gossip::TlcErr::new_builder() -// .error_code(ckb_types::packed::Byte32::new(tlc_err.error_code as u32)) -// .extra_data( -// tlc_err -// .extra_data -// .map(|data| match data { -// TlcErrData::ChannelFailed { -// channel_outpoint, -// channel_update, -// node_id, -// } => molecule_gossip::TlcErrDataBuilder::set( -// molecule_gossip::ChannelFailed::new_builder() -// .channel_outpoint(channel_outpoint.into()) -// .channel_update(channel_update.into()) -// .node_id(node_id.into()) -// .build(), -// ) -// .build() -// .to_opt(), -// TlcErrData::NodeFailed { node_id } => { -// molecule_gossip::TlcErrDataBuilder::set( -// molecule_gossip::NodeFailed::new_builder() -// .node_id(node_id.into()) -// .build(), -// ) -// .build() -// .to_opt() -// } -// }) -// .pack(), -// ) -// .build() -// } -// } - -// impl TryFrom for TlcErr { -// type Error = Error; - -// fn try_from(tlc_err: molecule_gossip::TlcErr) -> Result { -// Ok(TlcErr { -// error_code: tlc_err.error_code().into(), -// extra_data: tlc_err -// .extra_data() -// .to_opt() -// .map(|data| match data.unpack() { -// TlcErrData::ChannelFailed { -// channel_outpoint, -// channel_update, -// node_id, -// } => TlcErrData::ChannelFailed { -// channel_outpoint: channel_outpoint.into(), -// channel_update: channel_update.to_opt(), -// node_id: node_id.into(), -// }, -// TlcErrData::NodeFailed { node_id } => TlcErrData::NodeFailed { -// node_id: node_id.into(), -// }, -// }), -// }) -// } -// } - #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum TlcErrData { @@ -1260,11 +1199,95 @@ impl TlcErr { } fn serialize(&self) -> Vec { - bincode::serialize(self).expect("serialize hop data") + molecule_gossip::TlcErr::from(self.clone()) + .as_slice() + .to_vec() } fn deserialize(data: &[u8]) -> Option { - bincode::deserialize(data).ok() + molecule_gossip::TlcErr::from_slice(data) + .map(TlcErr::from) + .ok() + } +} + +impl TryFrom for molecule_gossip::TlcErrData { + type Error = Error; + + fn try_from(tlc_err_data: TlcErrData) -> Result { + match tlc_err_data { + TlcErrData::ChannelFailed { + channel_outpoint, + channel_update, + node_id, + } => Ok(molecule_gossip::ChannelFailed::new_builder() + .channel_outpoint(channel_outpoint.into()) + .channel_update( + ChannelUpdateOpt::new_builder() + .set(channel_update.map(|x| x.into())) + .build(), + ) + .node_id(node_id.into()) + .build() + .into()), + TlcErrData::NodeFailed { node_id } => Ok(molecule_gossip::NodeFailed::new_builder() + .node_id(node_id.into()) + .build() + .into()), + } + } +} + +impl TryFrom for TlcErrData { + type Error = Error; + + fn try_from(tlc_err_data: molecule_gossip::TlcErrData) -> Result { + match tlc_err_data.to_enum() { + molecule_gossip::TlcErrDataUnion::ChannelFailed(channel_failed) => { + Ok(TlcErrData::ChannelFailed { + channel_outpoint: channel_failed.channel_outpoint().into(), + channel_update: channel_failed + .channel_update() + .to_opt() + .map(|x| x.try_into().unwrap()), + node_id: channel_failed.node_id().try_into()?, + }) + } + molecule_gossip::TlcErrDataUnion::NodeFailed(node_failed) => { + Ok(TlcErrData::NodeFailed { + node_id: node_failed.node_id().try_into()?, + }) + } + } + } +} + +impl From for molecule_gossip::TlcErr { + fn from(tlc_err: TlcErr) -> Self { + molecule_gossip::TlcErr::new_builder() + .error_code(tlc_err.error_code_as_str().pack()) + .extra_data( + TlcErrDataOpt::new_builder() + .set(tlc_err.extra_data.map(|data| data.try_into().unwrap())) + .build(), + ) + .build() + } +} + +impl From for TlcErr { + fn from(tlc_err: molecule_gossip::TlcErr) -> Self { + TlcErr { + error_code: { + let s = + String::from_utf8(tlc_err.error_code().unpack()).expect("invalid error code"); + TlcErrorCode::from_str(&s).expect("parse error code failed") + }, + extra_data: tlc_err + .extra_data() + .to_opt() + .map(|data| data.try_into().unwrap()), + } } } @@ -3384,11 +3407,58 @@ impl HopData for PaymentHopData { } fn serialize(&self) -> Vec { - bincode::serialize(self).expect("serialize hop data") + molecule_fiber::PaymentHopData::from(self.clone()) + .as_bytes() + .to_vec() } fn deserialize(data: &[u8]) -> Option { - bincode::deserialize(data).ok() + molecule_fiber::PaymentHopData::from_slice(data) + .ok() + .map(|x| x.into()) + } +} + +impl From for molecule_fiber::PaymentHopData { + fn from(payment_hop_data: PaymentHopData) -> Self { + molecule_fiber::PaymentHopData::new_builder() + .amount(payment_hop_data.amount.pack()) + .expiry(payment_hop_data.expiry.pack()) + .payment_preimage( + PaymentPreimageOpt::new_builder() + .set(payment_hop_data.payment_preimage.map(|x| x.into())) + .build(), + ) + .hash_algorithm(Byte::new(payment_hop_data.hash_algorithm as u8)) + .funding_tx_hash(payment_hop_data.funding_tx_hash.into()) + .next_hop( + PubkeyOpt::new_builder() + .set(payment_hop_data.next_hop.map(|x| x.into())) + .build(), + ) + .build() + } +} + +impl From for PaymentHopData { + fn from(payment_hop_data: molecule_fiber::PaymentHopData) -> Self { + PaymentHopData { + amount: payment_hop_data.amount().unpack(), + expiry: payment_hop_data.expiry().unpack(), + payment_preimage: payment_hop_data + .payment_preimage() + .to_opt() + .map(|x| x.into()), + hash_algorithm: payment_hop_data + .hash_algorithm() + .try_into() + .expect("valid hash algorithm"), + funding_tx_hash: payment_hop_data.funding_tx_hash().into(), + next_hop: payment_hop_data + .next_hop() + .to_opt() + .map(|x| x.try_into().expect("invalid pubkey")), + } } }