1use std::borrow::Borrow;
2
3use bytes::{Bytes, BytesMut};
4use exocore_core::{
5 cell::{Cell, CellNodeRole, FullCell, NodeId},
6 framing::{
7 CapnpFrameBuilder, FrameBuilder, FrameReader, MultihashFrame, MultihashFrameBuilder,
8 PaddedFrame, PaddedFrameBuilder, SizedFrame, SizedFrameBuilder, TypedCapnpFrame,
9 },
10 sec::{
11 hash::{Multihash, MultihashDigestExt, Sha3_256},
12 signature::Signature,
13 },
14};
15use exocore_protos::{
16 capnp,
17 generated::data_chain_capnp::{
18 block_header, block_operation_header, block_signature, block_signatures,
19 },
20};
21
22use crate::{data::Data, operation::OperationId};
23
24pub type BlockOffset = u64;
25pub type BlockHeight = u64;
26pub type BlockOperationsSize = u32;
27pub type BlockSignaturesSize = u16;
28
29pub type BlockHeaderFrame<I> =
30 TypedCapnpFrame<MultihashFrame<32, Sha3_256, SizedFrame<I>>, block_header::Owned>;
31pub type BlockHeaderFrameBuilder =
32 SizedFrameBuilder<MultihashFrameBuilder<32, Sha3_256, CapnpFrameBuilder<block_header::Owned>>>;
33pub type SignaturesFrame<I> = TypedCapnpFrame<PaddedFrame<SizedFrame<I>>, block_signatures::Owned>;
34
35pub trait Block {
50 type UnderlyingFrame: FrameReader<OwnedType = Bytes>;
51
52 fn offset(&self) -> BlockOffset;
53 fn header(&self) -> &BlockHeaderFrame<Self::UnderlyingFrame>;
54 fn operations_data(&self) -> &[u8];
55 fn signatures(&self) -> &SignaturesFrame<Self::UnderlyingFrame>;
56
57 #[inline]
58 fn total_size(&self) -> usize {
59 self.header().whole_data_size()
60 + self.operations_data().len()
61 + self.signatures().whole_data_size()
62 }
63
64 #[inline]
65 fn next_offset(&self) -> BlockOffset {
66 self.offset() + self.total_size() as BlockOffset
67 }
68
69 #[inline]
70 fn copy_data_into(&self, data: &mut [u8]) {
71 let operations_data = self.operations_data();
72 let operations_offset = self.header().whole_data_size();
73 let signatures_offset = operations_offset + operations_data.len();
74
75 self.header()
76 .copy_into(data)
77 .expect("Couldn't write block into given buffer");
78
79 data[operations_offset..signatures_offset].copy_from_slice(operations_data);
80
81 self.signatures()
82 .copy_into(&mut data[signatures_offset..])
83 .expect("Couldn't write signatures into given buffer");
84 }
85
86 fn as_data_vec(&self) -> Bytes {
87 Bytes::from(
88 [
89 self.header().whole_data(),
90 self.operations_data(),
91 self.signatures().whole_data(),
92 ]
93 .concat(),
94 )
95 }
96
97 fn to_owned(&self) -> DataBlock<Bytes> {
98 DataBlock {
99 offset: self.offset(),
100 header: self.header().to_owned(),
101 operations_data: Bytes::from(self.operations_data().to_vec()),
102 signatures: self.signatures().to_owned(),
103 }
104 }
105
106 fn get_height(&self) -> Result<BlockHeight, Error> {
107 let reader = self.header().get_reader()?;
108 Ok(reader.get_height())
109 }
110
111 fn get_proposed_operation_id(&self) -> Result<OperationId, Error> {
112 let reader = self.header().get_reader()?;
113 Ok(reader.get_proposed_operation_id())
114 }
115
116 fn operations_iter(&self) -> Result<BlockOperationsIterator, Error> {
117 let block_header = self.header().get_reader()?;
118 let operations_header = block_header
119 .get_operations_header()?
120 .iter()
121 .map(|reader| BlockOperationHeader::from_reader(&reader))
122 .collect::<Vec<_>>();
123
124 Ok(BlockOperationsIterator {
125 index: 0,
126 operations_header,
127 operations_data: self.operations_data(),
128 last_error: None,
129 })
130 }
131
132 fn get_operation(
133 &self,
134 operation_id: OperationId,
135 ) -> Result<Option<crate::operation::OperationFrame<&[u8]>>, Error> {
136 let block_header = self.header().get_reader()?;
137 let operations_header: Vec<BlockOperationHeader> = block_header
138 .get_operations_header()?
139 .iter()
140 .map(|reader| BlockOperationHeader::from_reader(&reader))
141 .collect();
142
143 let operation_index =
144 operations_header.binary_search_by_key(&operation_id, |header| header.operation_id);
145
146 if let Ok(operation_index) = operation_index {
147 if operation_index > operations_header.len() {
148 return Err(Error::OutOfBound(format!(
149 "Operation id={} of block={} had an invalid index {} out of {} operations",
150 operation_id,
151 self.offset(),
152 operation_index,
153 operations_header.len()
154 )));
155 }
156
157 let frame = operations_header[operation_index].read_frame(self.operations_data())?;
158
159 Ok(Some(frame))
160 } else {
161 Ok(None)
162 }
163 }
164
165 fn validate<PB: Block>(&self, previous_block: Option<PB>) -> Result<(), Error> {
166 let header = self.header();
170 let header_reader: block_header::Reader = header.get_reader()?;
171
172 header.inner().inner().verify()?;
173
174 if let Some(previous_block) = previous_block {
175 let previous_hash = previous_block.header().inner().inner().multihash_bytes();
176 if previous_hash != header_reader.get_previous_hash()? {
177 return Err(Error::Integrity(
178 "Hash of previous block doesn't match current block hash".to_string(),
179 ));
180 }
181 }
182
183 let sig_size_header = header_reader.get_signatures_size() as usize;
184 let sig_size_stored = self.signatures().whole_data_size();
185 if sig_size_header != sig_size_stored {
186 return Err(Error::Integrity(format!(
187 "Signatures size don't match: sig_size_header={}, sig_size_stored={}",
188 sig_size_header, sig_size_stored
189 )));
190 }
191
192 let ops_size_header = header_reader.get_operations_size() as usize;
193 let ops_size_stored = self.operations_data().len();
194 if ops_size_header != ops_size_stored {
195 return Err(Error::Integrity(format!(
196 "Operations size don't match: ops_size_header={}, ops_size_stored={}",
197 ops_size_header, ops_size_stored
198 )));
199 }
200
201 if ops_size_header > 0 {
202 let operations = self.operations_iter()?;
203 let ops_hash_stored = BlockOperations::hash_operations(operations)?;
204 let ops_hash_header = Multihash::<32>::from_bytes(header_reader.get_operations_hash()?)
205 .map_err(|err| {
206 Error::Integrity(format!("Hash in block header couldn't be decoded: {}", err))
207 })?;
208
209 if ops_hash_stored != ops_hash_header {
210 return Err(Error::Integrity(format!(
211 "Operations hash don't match: ops_hash_header={:?}, ops_hash_stored={:?}",
212 ops_hash_header, ops_hash_stored
213 )));
214 }
215 }
216
217 Ok(())
218 }
219}
220
221pub fn read_header_frame<I: FrameReader>(inner: I) -> Result<BlockHeaderFrame<I>, Error> {
223 let sized_frame = SizedFrame::new(inner)?;
224 let multihash_frame = MultihashFrame::new(sized_frame)?;
225 let frame = TypedCapnpFrame::new(multihash_frame)?;
226 Ok(frame)
227}
228
229pub fn read_header_frame_from_next_offset<I: FrameReader>(
230 inner: I,
231 next_offset: usize,
232) -> Result<BlockHeaderFrame<I>, Error> {
233 let sized_frame = SizedFrame::new_from_next_offset(inner, next_offset)?;
234 let multihash_frame = MultihashFrame::new(sized_frame)?;
235 let frame = TypedCapnpFrame::new(multihash_frame)?;
236 Ok(frame)
237}
238
239pub fn build_header_frame(
240 header: CapnpFrameBuilder<block_header::Owned>,
241) -> BlockHeaderFrameBuilder {
242 SizedFrameBuilder::new(MultihashFrameBuilder::<32, Sha3_256, _>::new(header))
243}
244
245pub struct DataBlock<D: Data> {
247 pub offset: BlockOffset,
248 pub header: BlockHeaderFrame<D>,
249 pub operations_data: D,
250 pub signatures: SignaturesFrame<D>,
251}
252
253impl<D: Data> DataBlock<D> {
254 pub fn new(data: D) -> Result<DataBlock<D>, Error> {
255 let header = read_header_frame(data.clone())?;
256 let header_reader: block_header::Reader = header.get_reader()?;
257
258 let operations_offset = header.whole_data_size();
259 let operations_size = header_reader.get_operations_size() as usize;
260 let signatures_offset = operations_offset + operations_size;
261 let signatures_size = header_reader.get_signatures_size() as usize;
262
263 if signatures_offset >= data.len() {
264 return Err(Error::OutOfBound(format!(
265 "Signature offset {} is after data len {}",
266 signatures_offset,
267 data.len()
268 )));
269 }
270
271 let signatures_data = data.view(signatures_offset..signatures_offset + signatures_size);
272 let signatures = BlockSignatures::read_frame(signatures_data)?;
273
274 let operations_data = data.view(operations_offset..signatures_offset);
275
276 Ok(DataBlock {
277 offset: header_reader.get_offset(),
278 header,
279 operations_data,
280 signatures,
281 })
282 }
283
284 pub fn new_from_next_offset(data: D, next_offset: usize) -> Result<DataBlock<D>, Error> {
285 let signatures = BlockSignatures::read_frame_from_next_offset(data.clone(), next_offset)?;
286 let signatures_reader: block_signatures::Reader = signatures.get_reader()?;
287 let signatures_offset = next_offset - signatures.whole_data_size();
288
289 let operations_size = signatures_reader.get_operations_size() as usize;
290 if operations_size > signatures_offset {
291 return Err(Error::OutOfBound(format!(
292 "Tried to read block from next offset {}, but its operations size would exceed beginning of file (operations_size={} signatures_offset={})",
293 next_offset, operations_size, signatures_offset,
294 )));
295 }
296
297 let operations_offset = signatures_offset - operations_size;
298 let operations_data = data.view(operations_offset..signatures_offset);
299
300 let header = read_header_frame_from_next_offset(data, operations_offset)?;
301 let header_reader: block_header::Reader = header.get_reader()?;
302
303 Ok(DataBlock {
304 offset: header_reader.get_offset(),
305 operations_data,
306 header,
307 signatures,
308 })
309 }
310}
311
312impl<D: Data> Block for DataBlock<D> {
313 type UnderlyingFrame = D;
314
315 fn offset(&self) -> u64 {
316 self.offset
317 }
318
319 fn header(&self) -> &BlockHeaderFrame<Self::UnderlyingFrame> {
320 &self.header
321 }
322
323 fn operations_data(&self) -> &[u8] {
324 self.operations_data.slice(..)
325 }
326
327 fn signatures(&self) -> &SignaturesFrame<Self::UnderlyingFrame> {
328 &self.signatures
329 }
330}
331
332pub struct BlockBuilder;
334
335impl BlockBuilder {
336 pub fn build(
337 offset: BlockOffset,
338 header: BlockHeaderFrame<Bytes>,
339 operations_data: Bytes,
340 signatures: SignaturesFrame<Bytes>,
341 ) -> DataBlock<Bytes> {
342 DataBlock {
343 offset,
344 header,
345 operations_data,
346 signatures,
347 }
348 }
349
350 pub fn build_genesis(full_cell: &FullCell) -> Result<DataBlock<Bytes>, Error> {
351 let operations = BlockOperations::empty();
352 let block = Self::build_with_prev_info(full_cell.cell(), 0, 0, 0, &[], 0, operations)?;
353 Ok(block)
355 }
356
357 pub fn build_with_prev_block<B>(
358 cell: &Cell,
359 previous_block: &B,
360 proposed_operation_id: u64,
361 operations: BlockOperations,
362 ) -> Result<DataBlock<Bytes>, Error>
363 where
364 B: Block,
365 {
366 let previous_block_header_reader = previous_block.header().get_reader()?;
367
368 let previous_offset = previous_block.offset();
369 let previous_hash = previous_block.header().inner().inner().multihash_bytes();
370
371 let offset = previous_block.next_offset();
372 let height = previous_block_header_reader.get_height();
373
374 Self::build_with_prev_info(
375 cell,
376 offset,
377 height,
378 previous_offset,
379 previous_hash,
380 proposed_operation_id,
381 operations,
382 )
383 }
384
385 pub fn build_with_prev_info(
386 cell: &Cell,
387 offset: BlockOffset,
388 height: BlockHeight,
389 previous_offset: BlockOffset,
390 previous_hash: &[u8],
391 proposed_operation_id: u64,
392 operations: BlockOperations,
393 ) -> Result<DataBlock<Bytes>, Error> {
394 let local_node = cell.local_node();
395 let operations_data_size = operations.data.len() as u32;
396
397 let mut header_frame_builder = CapnpFrameBuilder::<block_header::Owned>::new();
399 let mut header_msg_builder = header_frame_builder.get_builder();
400 header_msg_builder.set_offset(offset);
401 header_msg_builder.set_height(height + 1);
402 header_msg_builder.set_previous_offset(previous_offset);
403 header_msg_builder.set_previous_hash(previous_hash);
404 header_msg_builder.set_proposed_operation_id(proposed_operation_id);
405 header_msg_builder.set_proposed_node_id(local_node.id().to_string().as_str());
406 header_msg_builder.set_operations_size(operations_data_size);
407 header_msg_builder.set_operations_hash(&operations.hash.to_bytes());
408
409 let mut operations_builder = header_msg_builder
410 .reborrow()
411 .init_operations_header(operations.headers.len() as u32);
412 for (i, header_builder) in operations.headers.iter().enumerate() {
413 let mut entry_builder = operations_builder.reborrow().get(i as u32);
414 header_builder.copy_into_builder(&mut entry_builder);
415 }
416
417 let signature_frame = BlockSignatures::empty_signatures_for_nodes(cell)
420 .to_frame_for_new_block(operations_data_size)?;
421
422 header_msg_builder
424 .set_signatures_size(signature_frame.whole_data_size() as BlockSignaturesSize);
425
426 let final_frame_builder = build_header_frame(header_frame_builder);
428 let final_frame_data = final_frame_builder.as_bytes();
429 let block_header = read_header_frame(final_frame_data)?;
430
431 Ok(DataBlock {
432 offset,
433 header: block_header,
434 operations_data: operations.data,
435 signatures: signature_frame,
436 })
437 }
438}
439
440pub struct BlockOperationsIterator<'a> {
442 index: usize,
443 operations_header: Vec<BlockOperationHeader>,
444 operations_data: &'a [u8],
445 last_error: Option<Error>,
446}
447
448impl<'a> Iterator for BlockOperationsIterator<'a> {
449 type Item = crate::operation::OperationFrame<&'a [u8]>;
450
451 fn next(&mut self) -> Option<Self::Item> {
452 if self.index >= self.operations_header.len() {
453 return None;
454 }
455
456 let header = &self.operations_header[self.index];
457 self.index += 1;
458
459 let frame_res = header.read_frame(self.operations_data);
460 match frame_res {
461 Ok(frame) => Some(frame),
462 Err(err) => {
463 self.last_error = Some(err);
464 None
465 }
466 }
467 }
468
469 fn size_hint(&self) -> (usize, Option<usize>) {
470 (self.index, Some(self.operations_data.len()))
471 }
472}
473
474pub struct BlockOperations {
476 hash: Multihash<32>,
477 headers: Vec<BlockOperationHeader>,
478 data: Bytes,
479}
480
481impl BlockOperations {
482 pub fn empty() -> BlockOperations {
483 BlockOperations {
484 hash: Multihash::default(),
485 headers: Vec::new(),
486 data: Bytes::new(),
487 }
488 }
489
490 pub fn from_operations<I, M, F>(sorted_operations: I) -> Result<BlockOperations, Error>
491 where
492 I: Iterator<Item = M>,
493 M: Borrow<crate::operation::OperationFrame<F>>,
494 F: FrameReader,
495 {
496 let mut hasher = Sha3_256::default();
497 let mut headers = Vec::new();
498 let mut data = BytesMut::new();
499 let mut last_operation_id = 0;
500
501 for operation in sorted_operations {
502 let operation = operation.borrow();
503 let operation_reader = operation.get_reader()?;
504 let offset = data.len();
505 let entry_data = operation.whole_data();
506 hasher.input_signed_frame(operation.inner().inner());
507 data.extend_from_slice(entry_data);
508
509 let operation_id = operation_reader.get_operation_id();
510 if operation_id < last_operation_id {
511 panic!(
512 "Tried to build a block from unsorted operations op={} < last={}",
513 operation_id, last_operation_id
514 );
515 }
516 last_operation_id = operation_id;
517
518 headers.push(BlockOperationHeader {
519 operation_id,
520 data_offset: offset as u32,
521 data_size: (data.len() - offset) as u32,
522 });
523 }
524
525 Ok(BlockOperations {
526 hash: hasher.to_multihash(),
527 headers,
528 data: data.into(),
529 })
530 }
531
532 pub fn hash_operations<I, M, F>(sorted_operations: I) -> Result<Multihash<32>, Error>
533 where
534 I: Iterator<Item = M>,
535 M: Borrow<crate::operation::OperationFrame<F>>,
536 F: FrameReader,
537 {
538 let mut hasher = Sha3_256::default();
539 for operation in sorted_operations {
540 hasher.input_signed_frame(operation.borrow().inner().inner());
541 }
542 Ok(hasher.to_multihash())
543 }
544
545 pub fn operations_count(&self) -> usize {
546 self.headers.len()
547 }
548
549 pub fn operations_id(&self) -> impl Iterator<Item = OperationId> + '_ {
550 self.headers.iter().map(|header| header.operation_id)
551 }
552
553 pub fn multihash(&self) -> Multihash<32> {
554 self.hash
555 }
556
557 pub fn data(&self) -> &[u8] {
558 &self.data
559 }
560}
561
562struct BlockOperationHeader {
565 operation_id: u64,
566 data_offset: u32,
567 data_size: u32,
568}
569
570impl BlockOperationHeader {
571 fn from_reader(reader: &block_operation_header::Reader) -> BlockOperationHeader {
572 BlockOperationHeader {
573 operation_id: reader.get_operation_id(),
574 data_offset: reader.get_data_offset(),
575 data_size: reader.get_data_size(),
576 }
577 }
578
579 fn copy_into_builder(&self, builder: &mut block_operation_header::Builder) {
580 builder.set_operation_id(self.operation_id);
581 builder.set_data_size(self.data_size);
582 builder.set_data_offset(self.data_offset);
583 }
584
585 fn read_frame<'a>(
586 &self,
587 operations_data: &'a [u8],
588 ) -> Result<crate::operation::OperationFrame<&'a [u8]>, Error> {
589 let offset_from = self.data_offset as usize;
590 let offset_to = self.data_offset as usize + self.data_size as usize;
591
592 let frame =
593 crate::operation::read_operation_frame(&operations_data[offset_from..offset_to])?;
594
595 Ok(frame)
596 }
597}
598
599pub struct BlockSignatures {
605 signatures: Vec<BlockSignature>,
606}
607
608impl BlockSignatures {
609 pub fn new_from_signatures(signatures: Vec<BlockSignature>) -> BlockSignatures {
610 BlockSignatures { signatures }
611 }
612
613 pub fn empty_signatures_for_nodes(cell: &Cell) -> BlockSignatures {
616 let nodes = cell.nodes();
617 let signatures = nodes
618 .iter()
619 .all()
620 .filter(|cn| cn.has_role(CellNodeRole::Chain))
621 .map(|cell_node| BlockSignature {
622 node_id: cell_node.node().id().clone(),
623 signature: Signature::empty(),
624 })
625 .collect();
626
627 BlockSignatures { signatures }
628 }
629
630 fn to_frame_builder(&self) -> CapnpFrameBuilder<block_signatures::Owned> {
631 let mut frame_builder = CapnpFrameBuilder::new();
632
633 let signatures_builder: block_signatures::Builder = frame_builder.get_builder();
634 let mut signatures_array = signatures_builder.init_signatures(self.signatures.len() as u32);
635 for (i, signature) in self.signatures.iter().enumerate() {
636 let mut signature_builder = signatures_array.reborrow().get(i as u32);
637 signature.copy_into_builder(&mut signature_builder);
638 }
639
640 frame_builder
641 }
642
643 pub fn to_frame_for_new_block(
644 &self,
645 operations_size: BlockOperationsSize,
646 ) -> Result<SignaturesFrame<Bytes>, Error> {
647 let mut signatures_frame_builder = self.to_frame_builder();
648 let mut signatures_builder = signatures_frame_builder.get_builder();
649 signatures_builder.set_operations_size(operations_size);
650
651 let frame_builder =
652 SizedFrameBuilder::new(PaddedFrameBuilder::new(signatures_frame_builder, 0));
653 let frame_data = frame_builder.as_bytes();
654 Self::read_frame(frame_data)
655 }
656
657 pub fn to_frame_for_existing_block(
658 &self,
659 header_reader: &block_header::Reader,
660 ) -> Result<SignaturesFrame<Bytes>, Error> {
661 let expected_signatures_size = usize::from(header_reader.get_signatures_size());
662
663 let mut signatures_frame_builder = self.to_frame_builder();
665 let mut signatures_builder = signatures_frame_builder.get_builder();
666 signatures_builder.set_operations_size(header_reader.get_operations_size());
667 let signatures_frame_data = signatures_frame_builder.as_bytes();
668 let signatures_frame_data_len = signatures_frame_data.len();
669
670 let mut frame_builder =
672 SizedFrameBuilder::new(PaddedFrameBuilder::new(signatures_frame_data, 0));
673 let frame_expected_size = frame_builder
674 .expected_size()
675 .expect("Frame should had been sized");
676
677 if frame_expected_size < expected_signatures_size {
679 let diff = expected_signatures_size - frame_expected_size;
680 frame_builder
681 .inner_mut()
682 .set_minimum_size(signatures_frame_data_len + diff);
683 }
684
685 let signatures_frame = Self::read_frame(frame_builder.as_bytes())?;
687
688 if signatures_frame.whole_data_size() != expected_signatures_size {
691 return Err(Error::Integrity(format!(
692 "Block local signatures isn't the same size as expected (this={} expected={})",
693 signatures_frame.whole_data_size(),
694 header_reader.get_signatures_size()
695 )));
696 }
697
698 Ok(signatures_frame)
699 }
700
701 pub fn read_frame<I: FrameReader>(inner: I) -> Result<SignaturesFrame<I>, Error> {
702 let sized_frame = SizedFrame::new(inner)?;
703 let padded_frame = PaddedFrame::new(sized_frame)?;
704 let frame = TypedCapnpFrame::new(padded_frame)?;
705 Ok(frame)
706 }
707
708 pub fn read_frame_from_next_offset<I: FrameReader>(
709 inner: I,
710 next_offset: usize,
711 ) -> Result<SignaturesFrame<I>, Error> {
712 let sized_frame = SizedFrame::new_from_next_offset(inner, next_offset)?;
713 let padded_frame = PaddedFrame::new(sized_frame)?;
714 let frame = TypedCapnpFrame::new(padded_frame)?;
715 Ok(frame)
716 }
717}
718
719pub struct BlockSignature {
722 pub node_id: NodeId,
723 pub signature: Signature,
724}
725
726impl BlockSignature {
727 pub fn new(node_id: NodeId, signature: Signature) -> BlockSignature {
728 BlockSignature { node_id, signature }
729 }
730
731 pub fn copy_into_builder(&self, builder: &mut block_signature::Builder) {
732 builder.set_node_id(self.node_id.to_string().as_str());
733 builder.set_node_signature(self.signature.get_bytes());
734 }
735}
736
737#[derive(Debug, thiserror::Error)]
739pub enum Error {
740 #[error("Block integrity error: {0}")]
741 Integrity(String),
742
743 #[error("An offset is out of the block data: {0}")]
744 OutOfBound(String),
745
746 #[error("Operations related error: {0}")]
747 Operation(#[from] crate::operation::Error),
748
749 #[error("Framing error: {0}")]
750 Framing(#[from] exocore_core::framing::Error),
751
752 #[error("Error in capnp serialization: {0}")]
753 Serialization(#[from] capnp::Error),
754
755 #[error("Field is not in capnp schema: code={0}")]
756 SerializationNotInSchema(u16),
757
758 #[error("Other operation error: {0}")]
759 Other(String),
760}
761
762impl From<capnp::NotInSchema> for Error {
763 fn from(err: capnp::NotInSchema) -> Self {
764 Error::SerializationNotInSchema(err.0)
765 }
766}
767
768#[cfg(test)]
769mod tests {
770 use exocore_core::{
771 cell::{FullCell, LocalNode, Node},
772 framing::FrameReader,
773 };
774
775 use super::*;
776 use crate::{
777 block::{Block, BlockBuilder, BlockOperations},
778 data::RefData,
779 operation::OperationBuilder,
780 };
781
782 #[test]
783 fn block_create_and_read() -> anyhow::Result<()> {
784 let local_node = LocalNode::generate();
785 let full_cell = FullCell::generate(local_node.clone())?;
786
787 {
788 let mut nodes = full_cell.cell().nodes_mut();
790 let local_cell_node = nodes.get_mut(local_node.id()).unwrap();
791 local_cell_node.add_role(CellNodeRole::Chain);
792
793 nodes.add(Node::generate_temporary());
795 }
796
797 let genesis = BlockBuilder::build_genesis(&full_cell)?;
798
799 let operations = vec![
800 OperationBuilder::new_entry(123, local_node.id(), b"some_data")
801 .sign_and_build(&local_node)?
802 .frame,
803 ];
804 let operations = BlockOperations::from_operations(operations.into_iter())?;
805
806 let second_block =
807 BlockBuilder::build_with_prev_block(full_cell.cell(), &genesis, 0, operations)?;
808
809 let mut data = [0u8; 5000];
810 second_block.copy_data_into(&mut data);
811
812 let block_data = RefData::new(&data[0..second_block.total_size()]);
813 let read_second_block = DataBlock::new(block_data)?;
814 assert_eq!(
815 second_block.header.whole_data(),
816 read_second_block.header.whole_data()
817 );
818
819 assert_eq!(
820 second_block.operations_data.as_ref(),
821 read_second_block.operations_data.slice(..),
822 );
823 assert_eq!(
824 second_block.signatures.whole_data(),
825 read_second_block.signatures.whole_data()
826 );
827
828 let header_reader = second_block.header.get_reader()?;
829 assert_eq!(header_reader.get_offset(), genesis.next_offset());
830 assert_eq!(
831 header_reader.get_signatures_size(),
832 second_block.signatures.whole_data_size() as u16
833 );
834 assert_eq!(
835 header_reader.get_operations_size(),
836 second_block.operations_data.len() as u32
837 );
838
839 let signatures_reader = second_block.signatures.get_reader()?;
840 assert_eq!(
841 signatures_reader.get_operations_size(),
842 second_block.operations_data.len() as u32
843 );
844
845 let signatures = signatures_reader.get_signatures()?;
847 assert_eq!(signatures.len(), 1);
848
849 Ok(())
850 }
851
852 #[test]
853 fn block_operations() -> anyhow::Result<()> {
854 let local_node = LocalNode::generate();
855 let full_cell = FullCell::generate(local_node.clone())?;
856 let genesis = BlockBuilder::build_genesis(&full_cell)?;
857
858 let block = BlockBuilder::build_with_prev_block(
860 full_cell.cell(),
861 &genesis,
862 0,
863 BlockOperations::empty(),
864 )?;
865 assert_eq!(block.operations_iter()?.count(), 0);
866
867 let operations = (0..5).map(|i| {
869 OperationBuilder::new_entry(i, local_node.id(), b"op1")
870 .sign_and_build(&local_node)
871 .unwrap()
872 .frame
873 });
874
875 let block_operations = BlockOperations::from_operations(operations)?;
876 let block =
877 BlockBuilder::build_with_prev_block(full_cell.cell(), &genesis, 0, block_operations)?;
878 assert_eq!(block.operations_iter()?.count(), 5);
879
880 Ok(())
881 }
882
883 #[test]
884 fn should_allocate_signatures_space_for_nodes() -> anyhow::Result<()> {
885 let local_node = LocalNode::generate();
886 let full_cell = FullCell::generate(local_node.clone())?;
887 let cell = full_cell.cell();
888
889 let node2 = {
890 let mut nodes = cell.nodes_mut();
892 let local_cell_node = nodes.get_mut(local_node.id()).unwrap();
893 local_cell_node.add_role(CellNodeRole::Chain);
894
895 let node2 = Node::generate_temporary();
897 nodes.add(node2.clone());
898 node2
899 };
900
901 let genesis_block = BlockBuilder::build_genesis(&full_cell)?;
902
903 let block_ops = BlockOperations::empty();
905 let block1 = BlockBuilder::build_with_prev_block(cell, &genesis_block, 0, block_ops)?;
906 assert!(block1.signatures.whole_data_size() > 100);
907
908 {
910 let mut nodes = cell.nodes_mut();
911 let cell_node_2 = nodes.get_mut(node2.id()).unwrap();
912 cell_node_2.add_role(CellNodeRole::Chain);
913 }
914
915 let block_ops = BlockOperations::empty();
916 let block2 = BlockBuilder::build_with_prev_block(cell, &genesis_block, 0, block_ops)?;
917 assert!(block2.signatures.whole_data_size() > block1.signatures.whole_data_size());
918
919 Ok(())
920 }
921
922 #[test]
923 fn should_pad_signatures_from_block_signature_size() -> anyhow::Result<()> {
924 let local_node = LocalNode::generate();
925 let full_cell = FullCell::generate(local_node)?;
926 let cell = full_cell.cell();
927 let genesis_block = BlockBuilder::build_genesis(&full_cell)?;
928
929 let block_ops = BlockOperations::empty();
930 let block1 = BlockBuilder::build_with_prev_block(cell, &genesis_block, 0, block_ops)?;
931 let block1_reader: block_header::Reader = block1.header().get_reader()?;
932
933 let block_signatures = BlockSignatures::new_from_signatures(Vec::new());
935 let signatures_frame = block_signatures.to_frame_for_existing_block(&block1_reader)?;
936
937 assert_eq!(
940 usize::from(block1_reader.get_signatures_size()),
941 signatures_frame.whole_data_size()
942 );
943
944 Ok(())
945 }
946}