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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#![allow(clippy::all)]
#[cfg(test)]
use crate::block::Header;
#[cfg(test)]
use crate::header::HeaderDesc;
#[cfg(test)]
use crate::testing::serialization::serialization_bijection;
use crate::{
    block::{Block, BlockVersion},
    fragment::{Contents, ContentsBuilder, Fragment},
    header::{BftProof, GenesisPraosProof, HeaderBuilderNew},
};
#[cfg(test)]
use chain_core::{
    packer::Codec,
    property::{Block as _, Deserialize, Serialize},
};
#[cfg(test)]
#[cfg(test)]
use quickcheck::TestResult;
use quickcheck::{Arbitrary, Gen};

quickcheck! {
    fn header_serialization_bijection(b: Header) -> TestResult {
        serialization_bijection(b)
    }

    fn block_serialization_bijection(b: Block) -> TestResult {
        serialization_bijection(b)
    }

    fn header_properties(block: Block) -> TestResult {
        use chain_core::property::Header as Prop;
        let header = block.header.clone();
        assert_eq!(header.hash(),block.id());
        assert_eq!(header.id(),block.id());
        assert_eq!(header.parent_id(),block.parent_id());
        assert_eq!(header.date(),block.date());
        assert_eq!(header.version(),block.version());

        assert_eq!(header.get_bft_leader_id(),block.header.get_bft_leader_id());
        assert_eq!(header.get_stakepool_id(),block.header.get_stakepool_id());
        assert_eq!(header.common(),block.header.common());
        assert_eq!(header.to_raw(),block.header.to_raw());
        assert_eq!(header.as_auth_slice(),block.header.as_auth_slice());
        assert!(are_desc_equal(header.description(),block.header.description()));
        assert_eq!(header.size(),block.header.size());

        TestResult::from_bool(header.chain_length() == block.chain_length())
    }

    // TODO: add a separate test with headers with correct content size to stress hash
    // checking when tests are migrated to proptest
    fn inconsistent_block_deserialization(header: Header, contents: Contents) -> bool {
        let (content_hash, content_size) = contents.compute_hash_size();

        let maybe_block = Block { header: header.clone(), contents };

        let block = Block::deserialize(&mut Codec::new(maybe_block.serialize_as_vec().unwrap().as_slice()));

        (content_hash != header.block_content_hash() || content_size != header.block_content_size()) == block.is_err()
    }
}

#[cfg(test)]
fn are_desc_equal(left: HeaderDesc, right: HeaderDesc) -> bool {
    left.id == right.id
}

impl Arbitrary for Contents {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let len = u8::arbitrary(g) % 12;
        let fragments: Vec<Fragment> = std::iter::repeat_with(|| Arbitrary::arbitrary(g))
            .take(len as usize)
            .collect();
        let mut content = ContentsBuilder::new();
        content.push_many(fragments);
        content.into()
    }
}

impl Arbitrary for Block {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        let content = Contents::arbitrary(g);
        let ver = BlockVersion::arbitrary(g);
        let parent_hash = Arbitrary::arbitrary(g);
        let chain_length = Arbitrary::arbitrary(g);
        let date = Arbitrary::arbitrary(g);
        let hdrbuilder = HeaderBuilderNew::new(ver, &content)
            .set_parent(&parent_hash, chain_length)
            .set_date(date);
        let header = match ver {
            BlockVersion::Genesis => hdrbuilder.into_unsigned_header().unwrap().generalize(),
            BlockVersion::Ed25519Signed => {
                let bft_proof: BftProof = Arbitrary::arbitrary(g);
                hdrbuilder
                    .into_bft_builder()
                    .unwrap()
                    .set_consensus_data(&bft_proof.leader_id)
                    .set_signature(bft_proof.signature)
                    .generalize()
            }
            BlockVersion::KesVrfproof => {
                let gp_proof: GenesisPraosProof = Arbitrary::arbitrary(g);
                hdrbuilder
                    .into_genesis_praos_builder()
                    .unwrap()
                    .set_consensus_data(&gp_proof.node_id, &gp_proof.vrf_proof)
                    .set_signature(gp_proof.kes_proof)
                    .generalize()
            }
        };
        Block {
            header,
            contents: content,
        }
    }
}