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
use chain_storage::{
    test_utils::{Block, BlockId},
    BlockInfo, BlockStore,
};
use rand::RngCore;
use rand_core::OsRng;
use std::path::{Path, PathBuf};

pub enum BranchCount {
    Unlimited,
    Limited(u32),
}

pub enum StopCriteria {
    BlocksCount(u32),
    SizeInMb(u32),
}

impl StopCriteria {
    pub fn criterion_met(&self, iteration_counter: u32) -> bool {
        iteration_counter >= self.end()
    }

    pub fn end(&self) -> u32 {
        match self {
            StopCriteria::BlocksCount(count) => *count,
            StopCriteria::SizeInMb(size) => size * 333,
        }
    }
}

const BLOCK_DATA_LENGTH: usize = 1024;

pub struct StorageBuilder {
    path: PathBuf,
    branches: BranchCount,
    stop_criteria: StopCriteria,
}

impl StorageBuilder {
    pub fn new<P: AsRef<Path>>(
        branches: BranchCount,
        stop_criteria: StopCriteria,
        path: P,
    ) -> Self {
        Self {
            branches,
            stop_criteria,
            path: path.as_ref().to_path_buf(),
        }
    }

    pub fn build(&self) {
        let mut rng = OsRng;
        let mut block_data = [0; BLOCK_DATA_LENGTH];

        rng.fill_bytes(&mut block_data);
        let genesis_block = Block::genesis(Some(Box::new(block_data)));

        let store = BlockStore::file(self.path.clone(), BlockId(0).serialize_as_vec()).unwrap();

        let genesis_block_info = BlockInfo::new(
            genesis_block.id.serialize_as_vec(),
            genesis_block.parent.serialize_as_vec(),
            genesis_block.chain_length,
        );

        store
            .put_block(&genesis_block.serialize_as_vec(), genesis_block_info)
            .unwrap();

        let mut blocks = vec![genesis_block];

        let mut iterations_counter = 0;
        loop {
            if self.stop_criteria.criterion_met(iterations_counter) {
                break;
            }

            let last_block = {
                match self.branches {
                    BranchCount::Unlimited => {
                        blocks.get(rng.next_u32() as usize % blocks.len()).unwrap()
                    }
                    BranchCount::Limited(count) => {
                        let limit = std::cmp::min(count, blocks.len() as u32);
                        blocks.get(limit as usize).unwrap()
                    }
                }
            };

            if iterations_counter % 100 == 0 {
                println!("{}/{}", iterations_counter, self.stop_criteria.end())
            }

            rng.fill_bytes(&mut block_data);
            let block = last_block.make_child(Some(Box::new(block_data)));
            blocks.push(block.clone());

            let block_info = BlockInfo::new(
                block.id.serialize_as_vec(),
                block.parent.serialize_as_vec(),
                block.chain_length,
            );
            store
                .put_block(&block.serialize_as_vec(), block_info)
                .unwrap();
            iterations_counter += 1;
        }
    }
}