1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use crate::{packed, prelude::*};

macro_rules! impl_serialized_size_for_entity {
    ($entity:ident, $func:ident) => {
        impl packed::$entity {
            pub fn $func(&self) -> usize {
                self.as_reader().$func()
            }
        }
    };
}

impl<'r> packed::TransactionReader<'r> {
    pub fn serialized_size_in_block(&self) -> usize {
        // the offset in TransactionVec header is u32
        self.as_slice().len() + molecule::NUMBER_SIZE
    }
}
impl_serialized_size_for_entity!(Transaction, serialized_size_in_block);

impl<'r> packed::BlockReader<'r> {
    pub fn serialized_size_without_uncle_proposals(&self) -> usize {
        let block_size = self.as_slice().len();
        // the header of ProposalShortIdVec header is u32
        let uncles_proposals_size = self
            .uncles()
            .iter()
            .map(|x| x.proposals().as_slice().len() - molecule::NUMBER_SIZE)
            .sum::<usize>();
        block_size - uncles_proposals_size
    }
}
impl_serialized_size_for_entity!(Block, serialized_size_without_uncle_proposals);

#[cfg(test)]
mod tests {
    use crate::{packed, prelude::*};

    #[test]
    fn block_size_should_not_include_uncles_proposals() {
        let proposal1 = [1; 10].pack();
        let proposal2 = [2; 10].pack();
        let proposal3 = [3; 10].pack();
        let proposals1 = vec![proposal1.clone()].pack();
        let proposals2 = vec![proposal1.clone(), proposal2.clone()].pack();
        let proposals3 = vec![proposal1, proposal2, proposal3].pack();
        let uncle0 = packed::UncleBlock::new_builder().build();
        let uncle1 = packed::UncleBlock::new_builder()
            .proposals(proposals1)
            .build();
        let uncle2 = packed::UncleBlock::new_builder()
            .proposals(proposals2)
            .build();
        let uncle3 = packed::UncleBlock::new_builder()
            .proposals(proposals3)
            .build();
        let mut empty_uncles = vec![
            uncle0.clone(),
            uncle0.clone(),
            uncle0.clone(),
            uncle0.clone(),
        ];
        let mut uncles = vec![uncle0, uncle1, uncle2, uncle3];
        loop {
            let block_with_empty_uncles = packed::Block::new_builder()
                .uncles(empty_uncles.clone().pack())
                .build();
            let block_with_uncles = packed::Block::new_builder()
                .uncles(uncles.clone().pack())
                .build();
            let actual = block_with_uncles.serialized_size_without_uncle_proposals();
            let actual_empty = block_with_empty_uncles.serialized_size_without_uncle_proposals();
            let expected = block_with_empty_uncles.as_slice().len();
            assert_eq!(actual, actual_empty);
            assert_eq!(actual, expected);
            if uncles.is_empty() {
                break;
            } else {
                empty_uncles.pop();
                uncles.pop();
            }
        }
    }
}