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    #[allow(clippy::too_many_arguments)]
67    pub fn generate_block_with_blame_info(
68        &self, num_txs: usize, block_size_limit: usize,
69        additional_transactions: Vec<Arc<SignedTransaction>>,
70        blame: Option<u32>, state_root: Option<H256>,
71        receipts_root: Option<H256>, logs_bloom_hash: Option<H256>,
72    ) -> H256 {
73        let block = self.assembler.assemble_new_block_with_blame_info(
74            num_txs,
75            block_size_limit,
76            additional_transactions,
77            blame,
78            state_root,
79            receipts_root,
80            logs_bloom_hash,
81        );
82        self.generate_block_impl(block)
83    }
84
85    pub fn generate_custom_block(
86        &self, transactions: Vec<Arc<SignedTransaction>>,
87        adaptive: Option<bool>,
88    ) -> H256 {
89        let block =
90            self.assembler.assemble_custom_block(transactions, adaptive);
91
92        self.generate_block_impl(block)
93    }
94
95    pub fn generate_custom_block_with_parent(
96        &self, parent_hash: H256, referee: Vec<H256>,
97        transactions: Vec<Arc<SignedTransaction>>, adaptive: bool,
98        maybe_custom: Option<Vec<Vec<u8>>>,
99    ) -> Result<H256, String> {
100        let block = self.assembler.assemble_custom_block_with_parent(
101            parent_hash,
102            referee,
103            transactions,
104            adaptive,
105            maybe_custom,
106        )?;
107
108        Ok(self.generate_block_impl(block))
109    }
110
111    pub fn generate_block_with_nonce_and_timestamp(
112        &self, parent_hash: H256, referee: Vec<H256>,
113        transactions: Vec<Arc<SignedTransaction>>, nonce: U256, timestamp: u64,
114        adaptive: bool,
115    ) -> Result<H256, String> {
116        let block = self.assembler.assemble_block_with_nonce_and_timestamp(
117            parent_hash,
118            referee,
119            transactions,
120            nonce,
121            timestamp,
122            adaptive,
123        )?;
124
125        Ok(self.generate_block_impl(block))
126    }
127
128    fn generate_block_impl(&self, block_init: Block) -> H256 {
129        let mut block = block_init;
130        let difficulty = block.block_header.difficulty();
131        let problem = ProofOfWorkProblem::new(
132            block.block_header.height(),
133            block.block_header.problem_hash(),
134            *difficulty,
135        );
136        let mut nonce: u64 = rand::random();
137        loop {
138            if self.pow.validate(
139                &problem,
140                &ProofOfWorkSolution {
141                    nonce: U256::from(nonce),
142                },
143            ) {
144                block.block_header.set_nonce(U256::from(nonce));
145                break;
146            }
147            nonce += 1;
148        }
149        let hash = block.block_header.compute_hash();
150        debug!(
151            "generate_block with block header:{:?} tx_number:{}, block_size:{}",
152            block.block_header,
153            block.transactions.len(),
154            block.size(),
155        );
156        self.on_mined_block(block);
157
158        debug!("generate_block finished on_mined_block()");
159        // FIXME: We should add a flag to enable/disable this wait
160        // Ensure that when `generate**` function returns, the block has been
161        // handled by Consensus This order is assumed by some tests, and
162        // this function is also only used in tests.
163        self.consensus.wait_for_generation(&hash);
164        debug!("generate_block finished wait_for_generation()");
165
166        hash
167    }
168}
169
170impl Deref for BlockGeneratorTestApi {
171    type Target = BlockGenerator;
172
173    fn deref(&self) -> &Self::Target { &self.0 }
174}