From c8d201403c7ec1f86cfc7cbb5494991cdbe9a84d Mon Sep 17 00:00:00 2001 From: quake Date: Wed, 11 Oct 2023 14:27:38 +0900 Subject: [PATCH] feat: tweak `SendBlocksProof` message to support ckb2023 --- util/gen-types/schemas/blockchain.mol | 2 +- util/gen-types/schemas/extensions.mol | 6 + util/gen-types/src/generated/blockchain.rs | 340 ++++++++++++++++++ util/gen-types/src/generated/extensions.rs | 87 ++++- .../src/components/get_blocks_proof.rs | 18 +- .../src/utilities/merkle_mountain_range.rs | 6 +- 6 files changed, 442 insertions(+), 17 deletions(-) diff --git a/util/gen-types/schemas/blockchain.mol b/util/gen-types/schemas/blockchain.mol index 3ab343d856a..c6c9b03d3a8 100644 --- a/util/gen-types/schemas/blockchain.mol +++ b/util/gen-types/schemas/blockchain.mol @@ -10,7 +10,7 @@ array Uint256 [byte; 32]; vector Bytes ; option BytesOpt (Bytes); - +vector BytesOptVec ; vector BytesVec ; vector Byte32Vec ; diff --git a/util/gen-types/schemas/extensions.mol b/util/gen-types/schemas/extensions.mol index 8a58212200f..b447abcdf66 100644 --- a/util/gen-types/schemas/extensions.mol +++ b/util/gen-types/schemas/extensions.mol @@ -373,6 +373,12 @@ table SendBlocksProof { // Block hashes for the blocks which were not found. missing_block_hashes: Byte32Vec, + + // Uncle hashes for the blocks which require verifying. + blocks_uncles_hash: Byte32Vec, + + // Block extension for the blocks which require verifying. + blocks_extension: BytesOptVec, } table GetTransactionsProof { diff --git a/util/gen-types/src/generated/blockchain.rs b/util/gen-types/src/generated/blockchain.rs index c7f33186fa5..3eb5b9b6b9f 100644 --- a/util/gen-types/src/generated/blockchain.rs +++ b/util/gen-types/src/generated/blockchain.rs @@ -2386,6 +2386,346 @@ impl molecule::prelude::Builder for BytesOptBuilder { } } #[derive(Clone)] +pub struct BytesOptVec(molecule::bytes::Bytes); +impl ::core::fmt::LowerHex for BytesOptVec { + 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 BytesOptVec { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl ::core::fmt::Display for BytesOptVec { + 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 BytesOptVec { + fn default() -> Self { + let v = molecule::bytes::Bytes::from_static(&Self::DEFAULT_VALUE); + BytesOptVec::new_unchecked(v) + } +} +impl BytesOptVec { + 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) -> BytesOpt { + 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 { + BytesOpt::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; + BytesOpt::new_unchecked(self.0.slice(start..end)) + } + } + pub fn as_reader<'r>(&'r self) -> BytesOptVecReader<'r> { + BytesOptVecReader::new_unchecked(self.as_slice()) + } +} +impl molecule::prelude::Entity for BytesOptVec { + type Builder = BytesOptVecBuilder; + const NAME: &'static str = "BytesOptVec"; + fn new_unchecked(data: molecule::bytes::Bytes) -> Self { + BytesOptVec(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 { + BytesOptVecReader::from_slice(slice).map(|reader| reader.to_entity()) + } + fn from_compatible_slice(slice: &[u8]) -> molecule::error::VerificationResult { + BytesOptVecReader::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 BytesOptVecReader<'r>(&'r [u8]); +impl<'r> ::core::fmt::LowerHex for BytesOptVecReader<'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 BytesOptVecReader<'r> { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{}({:#x})", Self::NAME, self) + } +} +impl<'r> ::core::fmt::Display for BytesOptVecReader<'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> BytesOptVecReader<'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) -> BytesOptReader<'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 { + BytesOptReader::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; + BytesOptReader::new_unchecked(&self.as_slice()[start..end]) + } + } +} +impl<'r> molecule::prelude::Reader<'r> for BytesOptVecReader<'r> { + type Entity = BytesOptVec; + const NAME: &'static str = "BytesOptVecReader"; + fn to_entity(&self) -> Self::Entity { + Self::Entity::new_unchecked(self.as_slice().to_owned().into()) + } + fn new_unchecked(slice: &'r [u8]) -> Self { + BytesOptVecReader(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]; + BytesOptReader::verify(&slice[start..end], compatible)?; + } + Ok(()) + } +} +#[derive(Debug, Default)] +pub struct BytesOptVecBuilder(pub(crate) Vec); +impl BytesOptVecBuilder { + pub fn set(mut self, v: Vec) -> Self { + self.0 = v; + self + } + pub fn push(mut self, v: BytesOpt) -> 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: BytesOpt) -> Option { + self.0 + .get_mut(index) + .map(|item| ::core::mem::replace(item, v)) + } +} +impl molecule::prelude::Builder for BytesOptVecBuilder { + type Entity = BytesOptVec; + const NAME: &'static str = "BytesOptVecBuilder"; + 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)); + BytesOptVec::new_unchecked(inner.into()) + } +} +pub struct BytesOptVecIterator(BytesOptVec, usize, usize); +impl ::core::iter::Iterator for BytesOptVecIterator { + type Item = BytesOpt; + 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 BytesOptVecIterator { + fn len(&self) -> usize { + self.2 - self.1 + } +} +impl ::core::iter::IntoIterator for BytesOptVec { + type Item = BytesOpt; + type IntoIter = BytesOptVecIterator; + fn into_iter(self) -> Self::IntoIter { + let len = self.len(); + BytesOptVecIterator(self, 0, len) + } +} +impl<'r> BytesOptVecReader<'r> { + pub fn iter<'t>(&'t self) -> BytesOptVecReaderIterator<'t, 'r> { + BytesOptVecReaderIterator(&self, 0, self.len()) + } +} +pub struct BytesOptVecReaderIterator<'t, 'r>(&'t BytesOptVecReader<'r>, usize, usize); +impl<'t: 'r, 'r> ::core::iter::Iterator for BytesOptVecReaderIterator<'t, 'r> { + type Item = BytesOptReader<'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 BytesOptVecReaderIterator<'t, 'r> { + fn len(&self) -> usize { + self.2 - self.1 + } +} +#[derive(Clone)] pub struct BytesVec(molecule::bytes::Bytes); impl ::core::fmt::LowerHex for BytesVec { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { diff --git a/util/gen-types/src/generated/extensions.rs b/util/gen-types/src/generated/extensions.rs index 7c7bcd0729c..bb3f1b14154 100644 --- a/util/gen-types/src/generated/extensions.rs +++ b/util/gen-types/src/generated/extensions.rs @@ -17260,6 +17260,13 @@ impl ::core::fmt::Display for SendBlocksProof { "missing_block_hashes", self.missing_block_hashes() )?; + write!( + f, + ", {}: {}", + "blocks_uncles_hash", + self.blocks_uncles_hash() + )?; + write!(f, ", {}: {}", "blocks_extension", self.blocks_extension())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; @@ -17274,9 +17281,9 @@ impl ::core::default::Default for SendBlocksProof { } } impl SendBlocksProof { - const DEFAULT_VALUE: [u8; 412] = [ - 156, 1, 0, 0, 20, 0, 0, 0, 144, 1, 0, 0, 148, 1, 0, 0, 152, 1, 0, 0, 124, 1, 0, 0, 20, 0, - 0, 0, 228, 0, 0, 0, 4, 1, 0, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + const DEFAULT_VALUE: [u8; 428] = [ + 172, 1, 0, 0, 28, 0, 0, 0, 152, 1, 0, 0, 156, 1, 0, 0, 160, 1, 0, 0, 164, 1, 0, 0, 168, 1, + 0, 0, 124, 1, 0, 0, 20, 0, 0, 0, 228, 0, 0, 0, 4, 1, 0, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -17288,9 +17295,10 @@ impl SendBlocksProof { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, ]; - pub const FIELD_COUNT: usize = 4; + pub const FIELD_COUNT: usize = 6; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -17328,11 +17336,23 @@ impl SendBlocksProof { pub fn missing_block_hashes(&self) -> Byte32Vec { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Byte32Vec::new_unchecked(self.0.slice(start..end)) + } + pub fn blocks_uncles_hash(&self) -> Byte32Vec { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + Byte32Vec::new_unchecked(self.0.slice(start..end)) + } + pub fn blocks_extension(&self) -> BytesOptVec { + 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[20..]) as usize; - Byte32Vec::new_unchecked(self.0.slice(start..end)) + let end = molecule::unpack_number(&slice[28..]) as usize; + BytesOptVec::new_unchecked(self.0.slice(start..end)) } else { - Byte32Vec::new_unchecked(self.0.slice(start..)) + BytesOptVec::new_unchecked(self.0.slice(start..)) } } pub fn as_reader<'r>(&'r self) -> SendBlocksProofReader<'r> { @@ -17366,6 +17386,8 @@ impl molecule::prelude::Entity for SendBlocksProof { .proof(self.proof()) .headers(self.headers()) .missing_block_hashes(self.missing_block_hashes()) + .blocks_uncles_hash(self.blocks_uncles_hash()) + .blocks_extension(self.blocks_extension()) } } #[derive(Clone, Copy)] @@ -17396,6 +17418,13 @@ impl<'r> ::core::fmt::Display for SendBlocksProofReader<'r> { "missing_block_hashes", self.missing_block_hashes() )?; + write!( + f, + ", {}: {}", + "blocks_uncles_hash", + self.blocks_uncles_hash() + )?; + write!(f, ", {}: {}", "blocks_extension", self.blocks_extension())?; let extra_count = self.count_extra_fields(); if extra_count != 0 { write!(f, ", .. ({} fields)", extra_count)?; @@ -17404,7 +17433,7 @@ impl<'r> ::core::fmt::Display for SendBlocksProofReader<'r> { } } impl<'r> SendBlocksProofReader<'r> { - pub const FIELD_COUNT: usize = 4; + pub const FIELD_COUNT: usize = 6; pub fn total_size(&self) -> usize { molecule::unpack_number(self.as_slice()) as usize } @@ -17442,11 +17471,23 @@ impl<'r> SendBlocksProofReader<'r> { pub fn missing_block_hashes(&self) -> Byte32VecReader<'r> { let slice = self.as_slice(); let start = molecule::unpack_number(&slice[16..]) as usize; + let end = molecule::unpack_number(&slice[20..]) as usize; + Byte32VecReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn blocks_uncles_hash(&self) -> Byte32VecReader<'r> { + let slice = self.as_slice(); + let start = molecule::unpack_number(&slice[20..]) as usize; + let end = molecule::unpack_number(&slice[24..]) as usize; + Byte32VecReader::new_unchecked(&self.as_slice()[start..end]) + } + pub fn blocks_extension(&self) -> BytesOptVecReader<'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[20..]) as usize; - Byte32VecReader::new_unchecked(&self.as_slice()[start..end]) + let end = molecule::unpack_number(&slice[28..]) as usize; + BytesOptVecReader::new_unchecked(&self.as_slice()[start..end]) } else { - Byte32VecReader::new_unchecked(&self.as_slice()[start..]) + BytesOptVecReader::new_unchecked(&self.as_slice()[start..]) } } } @@ -17500,6 +17541,8 @@ impl<'r> molecule::prelude::Reader<'r> for SendBlocksProofReader<'r> { HeaderDigestVecReader::verify(&slice[offsets[1]..offsets[2]], compatible)?; HeaderVecReader::verify(&slice[offsets[2]..offsets[3]], compatible)?; Byte32VecReader::verify(&slice[offsets[3]..offsets[4]], compatible)?; + Byte32VecReader::verify(&slice[offsets[4]..offsets[5]], compatible)?; + BytesOptVecReader::verify(&slice[offsets[5]..offsets[6]], compatible)?; Ok(()) } } @@ -17509,9 +17552,11 @@ pub struct SendBlocksProofBuilder { pub(crate) proof: HeaderDigestVec, pub(crate) headers: HeaderVec, pub(crate) missing_block_hashes: Byte32Vec, + pub(crate) blocks_uncles_hash: Byte32Vec, + pub(crate) blocks_extension: BytesOptVec, } impl SendBlocksProofBuilder { - pub const FIELD_COUNT: usize = 4; + pub const FIELD_COUNT: usize = 6; pub fn last_header(mut self, v: VerifiableHeader) -> Self { self.last_header = v; self @@ -17528,6 +17573,14 @@ impl SendBlocksProofBuilder { self.missing_block_hashes = v; self } + pub fn blocks_uncles_hash(mut self, v: Byte32Vec) -> Self { + self.blocks_uncles_hash = v; + self + } + pub fn blocks_extension(mut self, v: BytesOptVec) -> Self { + self.blocks_extension = v; + self + } } impl molecule::prelude::Builder for SendBlocksProofBuilder { type Entity = SendBlocksProof; @@ -17538,6 +17591,8 @@ impl molecule::prelude::Builder for SendBlocksProofBuilder { + self.proof.as_slice().len() + self.headers.as_slice().len() + self.missing_block_hashes.as_slice().len() + + self.blocks_uncles_hash.as_slice().len() + + self.blocks_extension.as_slice().len() } fn write(&self, writer: &mut W) -> molecule::io::Result<()> { let mut total_size = molecule::NUMBER_SIZE * (Self::FIELD_COUNT + 1); @@ -17550,6 +17605,10 @@ impl molecule::prelude::Builder for SendBlocksProofBuilder { total_size += self.headers.as_slice().len(); offsets.push(total_size); total_size += self.missing_block_hashes.as_slice().len(); + offsets.push(total_size); + total_size += self.blocks_uncles_hash.as_slice().len(); + offsets.push(total_size); + total_size += self.blocks_extension.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))?; @@ -17558,6 +17617,8 @@ impl molecule::prelude::Builder for SendBlocksProofBuilder { writer.write_all(self.proof.as_slice())?; writer.write_all(self.headers.as_slice())?; writer.write_all(self.missing_block_hashes.as_slice())?; + writer.write_all(self.blocks_uncles_hash.as_slice())?; + writer.write_all(self.blocks_extension.as_slice())?; Ok(()) } fn build(&self) -> Self::Entity { diff --git a/util/light-client-protocol-server/src/components/get_blocks_proof.rs b/util/light-client-protocol-server/src/components/get_blocks_proof.rs index dd8e0ae174e..26dbd21e685 100644 --- a/util/light-client-protocol-server/src/components/get_blocks_proof.rs +++ b/util/light-client-protocol-server/src/components/get_blocks_proof.rs @@ -73,6 +73,9 @@ impl<'a> GetBlocksProofProcess<'a> { let mut positions = Vec::with_capacity(found.len()); let mut block_headers = Vec::with_capacity(found.len()); + let mut uncles_hash = Vec::with_capacity(found.len()); + let mut extensions = Vec::with_capacity(found.len()); + let ckb2023 = self.nc.ckb2023(); for block_hash in found { let header = snapshot @@ -80,9 +83,22 @@ impl<'a> GetBlocksProofProcess<'a> { .expect("header should be in store"); positions.push(leaf_index_to_pos(header.number())); block_headers.push(header.data()); + if ckb2023 { + let uncles = snapshot + .get_block_uncles(&block_hash) + .expect("block uncles must be stored"); + let extension = snapshot.get_block_extension(&block_hash); + + uncles_hash.push(uncles.data().calc_uncles_hash()); + extensions.push(packed::BytesOpt::new_builder().set(extension).build()); + } } - let proved_items = block_headers.pack(); + let proved_items = ( + block_headers.pack(), + uncles_hash.pack(), + packed::BytesOptVec::new_builder().set(extensions).build(), + ); let missing_items = missing.pack(); self.protocol.reply_proof::( diff --git a/util/types/src/utilities/merkle_mountain_range.rs b/util/types/src/utilities/merkle_mountain_range.rs index a6a58ff2302..42f49794e65 100644 --- a/util/types/src/utilities/merkle_mountain_range.rs +++ b/util/types/src/utilities/merkle_mountain_range.rs @@ -305,7 +305,7 @@ impl ProverMessageBuilder for packed::SendLastStateProofBuilder { } impl ProverMessageBuilder for packed::SendBlocksProofBuilder { - type ProvedItems = packed::HeaderVec; + type ProvedItems = (packed::HeaderVec, packed::Byte32Vec, packed::BytesOptVec); type MissingItems = packed::Byte32Vec; fn set_last_header(self, last_header: packed::VerifiableHeader) -> Self { self.last_header(last_header) @@ -314,7 +314,9 @@ impl ProverMessageBuilder for packed::SendBlocksProofBuilder { self.proof(proof) } fn set_proved_items(self, items: Self::ProvedItems) -> Self { - self.headers(items) + self.headers(items.0) + .blocks_uncles_hash(items.1) + .blocks_extension(items.2) } fn set_missing_items(self, items: Self::MissingItems) -> Self { self.missing_block_hashes(items)