blockgen/
test_api.rs

1use cfx_parameters::consensus::GENESIS_GAS_LIMIT;
2use cfx_types::{H256, U256};
3
4use cfxcore::pow::{ProofOfWorkProblem, ProofOfWorkSolution};
5use log::debug;
6
7use primitives::*;
8use std::{ops::Deref, sync::Arc, thread, time::Duration};
9
10use crate::BlockGenerator;
11
12#[derive(Clone)]
13pub struct BlockGeneratorTestApi(Arc<BlockGenerator>);
14
15// Generate Block APIs for test only
16impl BlockGeneratorTestApi {
17    pub(crate) fn new(bg: Arc<BlockGenerator>) -> Self {
18        BlockGeneratorTestApi(bg)
19    }
20
21    pub fn auto_block_generation(&self, interval_ms: u64) {
22        let interval = Duration::from_millis(interval_ms);
23        while self.is_running() {
24            if !self.sync.catch_up_mode() {
25                let block =
26                    self.assembler.assemble_new_mining_block(Some(3000));
27                self.generate_block_impl(block);
28            }
29            thread::sleep(interval);
30        }
31    }
32
33    // This function is used in test only to simulate attacker behavior.
34    pub fn generate_fixed_block(
35        &self, parent_hash: H256, referee: Vec<H256>, num_txs: usize,
36        difficulty: u64, adaptive: bool, pos_reference: Option<H256>,
37    ) -> Result<H256, String> {
38        let block = self.assembler.assemble_new_fixed_block(
39            parent_hash,
40            referee,
41            num_txs,
42            difficulty,
43            adaptive,
44            GENESIS_GAS_LIMIT,
45            pos_reference,
46        )?;
47        Ok(self.generate_block_impl(block))
48    }
49
50    /// Generate a block with transactions in the pool
51    /// This is used for testing only
52    pub fn generate_block(
53        &self, num_txs: usize, block_size_limit: usize,
54        additional_transactions: Vec<Arc<SignedTransaction>>,
55    ) -> H256 {
56        let block = self.assembler.assemble_new_block(
57            num_txs,
58            block_size_limit,
59            additional_transactions,
60        );
61        self.generate_block_impl(block)
62    }
63
64    /// Generate a block with transactions in the pool.
65    /// This is used for testing only
66    pub fn generate_block_with_blame_info(
67        &self, num_txs: usize, block_size_limit: usize,
68        additional_transactions: Vec<Arc<SignedTransaction>>,
69        blame: Option<u32>, state_root: Option<H256>,
70        receipts_root: Option<H256>, logs_bloom_hash: Option<H256>,
71    ) -> H256 {
72        let block = self.assembler.assemble_new_block_with_blame_info(
73            num_txs,
74            block_size_limit,
75            additional_transactions,
76            blame,
77            state_root,
78            receipts_root,
79            logs_bloom_hash,
80        );
81        self.generate_block_impl(block)
82    }
83
84    pub fn generate_custom_block(
85        &self, transactions: Vec<Arc<SignedTransaction>>,
86        adaptive: Option<bool>,
87    ) -> H256 {
88        let block =
89            self.assembler.assemble_custom_block(transactions, adaptive);
90
91        self.generate_block_impl(block)
92    }
93
94    pub fn generate_custom_block_with_parent(
95        &self, parent_hash: H256, referee: Vec<H256>,
96        transactions: Vec<Arc<SignedTransaction>>, adaptive: bool,
97        maybe_custom: Option<Vec<Vec<u8>>>,
98    ) -> Result<H256, String> {
99        let block = self.assembler.assemble_custom_block_with_parent(
100            parent_hash,
101            referee,
102            transactions,
103            adaptive,
104            maybe_custom,
105        )?;
106
107        Ok(self.generate_block_impl(block))
108    }
109
110    pub fn generate_block_with_nonce_and_timestamp(
111        &self, parent_hash: H256, referee: Vec<H256>,
112        transactions: Vec<Arc<SignedTransaction>>, nonce: U256, timestamp: u64,
113        adaptive: bool,
114    ) -> Result<H256, String> {
115        let block = self.assembler.assemble_block_with_nonce_and_timestamp(
116            parent_hash,
117            referee,
118            transactions,
119            nonce,
120            timestamp,
121            adaptive,
122        )?;
123
124        Ok(self.generate_block_impl(block))
125    }
126
127    fn generate_block_impl(&self, block_init: Block) -> H256 {
128        let mut block = block_init;
129        let difficulty = block.block_header.difficulty();
130        let problem = ProofOfWorkProblem::new(
131            block.block_header.height(),
132            block.block_header.problem_hash(),
133            *difficulty,
134        );
135        let mut nonce: u64 = rand::random();
136        loop {
137            if self.pow.validate(
138                &problem,
139                &ProofOfWorkSolution {
140                    nonce: U256::from(nonce),
141                },
142            ) {
143                block.block_header.set_nonce(U256::from(nonce));
144                break;
145            }
146            nonce += 1;
147        }
148        let hash = block.block_header.compute_hash();
149        debug!(
150            "generate_block with block header:{:?} tx_number:{}, block_size:{}",
151            block.block_header,
152            block.transactions.len(),
153            block.size(),
154        );
155        self.on_mined_block(block);
156
157        debug!("generate_block finished on_mined_block()");
158        // FIXME: We should add a flag to enable/disable this wait
159        // Ensure that when `generate**` function returns, the block has been
160        // handled by Consensus This order is assumed by some tests, and
161        // this function is also only used in tests.
162        self.consensus.wait_for_generation(&hash);
163        debug!("generate_block finished wait_for_generation()");
164
165        hash
166    }
167}
168
169impl Deref for BlockGeneratorTestApi {
170    type Target = BlockGenerator;
171
172    fn deref(&self) -> &Self::Target { &*self.0 }
173}