cfxcore/sync/
utils.rs

1use std::{
2    collections::HashMap, path::Path, str::FromStr, sync::Arc, time::Duration,
3};
4
5use parking_lot::Mutex;
6use rand_08::{prelude::StdRng, SeedableRng};
7use threadpool::ThreadPool;
8
9use cfx_internal_common::ChainIdParamsInner;
10use cfx_parameters::{
11    block::{MAX_BLOCK_SIZE_IN_BYTES, REFEREE_DEFAULT_BOUND},
12    consensus::{GENESIS_GAS_LIMIT, TRANSACTION_DEFAULT_EPOCH_BOUND},
13    tx_pool::TXPOOL_DEFAULT_NONCE_BITS,
14    WORKER_COMPUTATION_PARALLELISM,
15};
16use cfx_storage::{StorageConfiguration, StorageManager};
17use cfx_types::{
18    address_util::AddressUtil, Address, AddressSpaceUtil, AllChainID, H256,
19    U256,
20};
21use diem_config::keys::ConfigKey;
22use diem_crypto::Uniform;
23use diem_types::validator_config::{
24    ConsensusPrivateKey, ConsensusVRFPrivateKey,
25};
26use primitives::{Block, BlockHeaderBuilder};
27
28use crate::{
29    block_data_manager::{BlockDataManager, DataManagerConfiguration, DbType},
30    cache_config::CacheConfig,
31    consensus::{
32        consensus_inner::consensus_executor::ConsensusExecutionConfiguration,
33        pos_handler::{PosConfiguration, PosVerifier},
34        ConsensusConfig, ConsensusInnerConfig,
35    },
36    db::NUM_COLUMNS,
37    genesis_block::{genesis_block, GenesisPosState},
38    pow::{self, PowComputer, ProofOfWorkConfig},
39    statistics::Statistics,
40    sync::{SyncGraphConfig, SynchronizationGraph},
41    transaction_pool::TxPoolConfig,
42    verification::VerificationConfig,
43    ConsensusGraph, NodeType, Notifications, TransactionPool,
44};
45use cfx_executor::{
46    machine::{Machine, VmFactory},
47    spec::CommonParams,
48};
49
50pub fn create_simple_block_impl(
51    parent_hash: H256, ref_hashes: Vec<H256>, height: u64, nonce: U256,
52    diff: U256, block_weight: u32, adaptive: bool,
53) -> (H256, Block) {
54    let mut b = BlockHeaderBuilder::new();
55    let mut author = Address::zero();
56    author.set_user_account_type_bits();
57    let mut header = b
58        .with_parent_hash(parent_hash)
59        .with_height(height)
60        .with_referee_hashes(ref_hashes)
61        .with_gas_limit(GENESIS_GAS_LIMIT.into())
62        .with_nonce(nonce)
63        .with_difficulty(diff)
64        .with_adaptive(adaptive)
65        .with_author(author)
66        .build();
67    header.compute_hash();
68    let pow_quality = if block_weight > 1 {
69        diff * block_weight
70    } else {
71        diff
72    };
73    // To convert pow_quality back to pow_hash can be inaccurate, but it should
74    // be okay in tests.
75    header.pow_hash =
76        Some(pow::pow_quality_to_hash(&pow_quality, &header.nonce()));
77    // println!("simple_block: difficulty={:?} pow_hash={:?} pow_quality={}",
78    // pow_quality, header.pow_hash,
79    // pow::pow_hash_to_quality(&header.pow_hash.unwrap(), &header.nonce()));
80    let block = Block::new(header, vec![]);
81    (block.hash(), block)
82}
83
84pub fn create_simple_block(
85    sync: Arc<SynchronizationGraph>, parent_hash: H256, ref_hashes: Vec<H256>,
86    height: u64, block_weight: u32, adaptive: bool,
87) -> (H256, Block) {
88    //    sync.consensus.wait_for_generation(&parent_hash);
89    // let parent_header = sync.block_header_by_hash(&parent_hash).unwrap();
90    //    let exp_diff = sync.expected_difficulty(&parent_hash);
91    //    assert!(
92    //        exp_diff == U256::from(10),
93    //        "Difficulty hike in bench is not supported yet!"
94    //    );
95    // Note that because we do not fill the timestamp, it should keep at the
96    // minimum difficulty of 10.
97    let exp_diff = U256::from(10);
98    let nonce = U256::from(sync.block_count() as u64 + 1);
99    create_simple_block_impl(
100        parent_hash,
101        ref_hashes,
102        height,
103        nonce,
104        exp_diff,
105        block_weight,
106        adaptive,
107    )
108}
109
110pub fn initialize_data_manager(
111    db_dir: &str, dbtype: DbType, pow: Arc<PowComputer>, vm: VmFactory,
112) -> (Arc<BlockDataManager>, Arc<Block>) {
113    let ledger_db = db::open_database(
114        db_dir,
115        &db::db_config(
116            Path::new(db_dir),
117            Some(128),
118            db::DatabaseCompactionProfile::default(),
119            NUM_COLUMNS,
120            false,
121        ),
122    )
123    .map_err(|e| format!("Failed to open database {:?}", e))
124    .unwrap();
125
126    let worker_thread_pool = Arc::new(Mutex::new(ThreadPool::with_name(
127        "Tx Recover".into(),
128        WORKER_COMPUTATION_PARALLELISM,
129    )));
130
131    let storage_manager = Arc::new(
132        StorageManager::new(StorageConfiguration::new_default(
133            db_dir,
134            cfx_parameters::consensus::SNAPSHOT_EPOCHS_CAPACITY,
135            cfx_parameters::consensus::ERA_DEFAULT_EPOCH_COUNT,
136        ))
137        .expect("Failed to initialize storage."),
138    );
139
140    let mut genesis_accounts = HashMap::new();
141    genesis_accounts.insert(
142        Address::from_str("1000000000000000000000000000000000000008")
143            .unwrap()
144            .with_native_space(),
145        U256::from(0),
146    );
147
148    let machine = Arc::new(Machine::new_with_builtin(Default::default(), vm));
149
150    let genesis_block = Arc::new(genesis_block(
151        &storage_manager,
152        genesis_accounts,
153        Address::from_str("1000000000000000000000000000000000000008").unwrap(),
154        U256::from(10),
155        machine.clone(),
156        false, /* need_to_execute */
157        None,
158        &Some(GenesisPosState {
159            initial_nodes: vec![],
160            initial_committee: vec![],
161            initial_seed: Default::default(),
162        }),
163    ));
164
165    let data_man = Arc::new(BlockDataManager::new(
166        CacheConfig::default(),
167        genesis_block.clone(),
168        ledger_db.clone(),
169        storage_manager,
170        worker_thread_pool,
171        DataManagerConfiguration::new(
172            false,                          /* do not persist transaction
173                                             * address */
174            false, /* do not persist block number index */
175            Duration::from_millis(300_000), /* max cached tx count */
176            dbtype,
177        ),
178        pow,
179    ));
180    (data_man, genesis_block)
181}
182
183pub fn initialize_synchronization_graph_with_data_manager(
184    data_man: Arc<BlockDataManager>, beta: u64, h: u64, tcr: u64, tcb: u64,
185    era_epoch_count: u64, pow: Arc<PowComputer>, vm: VmFactory,
186) -> (Arc<SynchronizationGraph>, Arc<ConsensusGraph>) {
187    let mut params = CommonParams::default();
188    params.transition_heights.cip1559 = u64::MAX;
189    let machine = Arc::new(Machine::new_with_builtin(params.clone(), vm));
190    let mut rng = StdRng::from_seed([0u8; 32]);
191    let pos_verifier = Arc::new(PosVerifier::new(
192        None,
193        // These configurations will not be used.
194        PosConfiguration {
195            bls_key: ConfigKey::new(ConsensusPrivateKey::generate(&mut rng)),
196            vrf_key: ConfigKey::new(ConsensusVRFPrivateKey::generate(&mut rng)),
197            diem_conf_path: Default::default(),
198            protocol_conf: Default::default(),
199            pos_initial_nodes_path: "".to_string(),
200            vrf_proposal_threshold: Default::default(),
201            pos_state_config: Default::default(),
202        },
203        u64::MAX,
204    ));
205
206    let pow_config = ProofOfWorkConfig::new(
207        true,      /* test_mode */
208        false,     /* use_octopus_in_test_mode */
209        "disable", /* mining_type */
210        Some(10),
211        String::from(""), /* stratum_listen_addr */
212        0,                /* stratum_port */
213        None,             /* stratum_secret */
214        1,                /* pow_problem_window_size */
215        0,                /* cip_height */
216    );
217    let verification_config = VerificationConfig::new(
218        true, /* test_mode */
219        REFEREE_DEFAULT_BOUND,
220        MAX_BLOCK_SIZE_IN_BYTES,
221        TRANSACTION_DEFAULT_EPOCH_BOUND,
222        TXPOOL_DEFAULT_NONCE_BITS,
223        pos_verifier.enable_height(),
224        pow_config.initial_difficulty,
225        machine.clone(),
226    );
227
228    let txpool = Arc::new(TransactionPool::new(
229        TxPoolConfig::default(),
230        verification_config.clone(),
231        data_man.clone(),
232        machine.clone(),
233    ));
234    let statistics = Arc::new(Statistics::new());
235
236    let sync_config = SyncGraphConfig {
237        future_block_buffer_capacity: 1,
238        enable_state_expose: false,
239        is_consortium: false,
240    };
241    let notifications = Notifications::init();
242    let consensus = Arc::new(ConsensusGraph::new(
243        ConsensusConfig {
244            chain_id: ChainIdParamsInner::new_simple(AllChainID::new(1, 1)),
245            inner_conf: ConsensusInnerConfig {
246                adaptive_weight_beta: beta,
247                heavy_block_difficulty_ratio: h,
248                timer_chain_block_difficulty_ratio: tcr,
249                timer_chain_beta: tcb,
250                era_epoch_count,
251                enable_optimistic_execution: false,
252                enable_state_expose: false,
253                pos_pivot_decision_defer_epoch_count: 50,
254                cip113_pivot_decision_defer_epoch_count: 50,
255                cip113_transition_height: u64::MAX,
256                debug_dump_dir_invalid_state_root: None,
257                debug_invalid_state_root_epoch: None,
258                force_recompute_height_during_construct_pivot: None,
259                recovery_latest_mpt_snapshot: false,
260                use_isolated_db_for_mpt_table: false,
261            },
262            bench_mode: true, /* Set bench_mode to true so that we skip
263                               * execution */
264            transaction_epoch_bound: TRANSACTION_DEFAULT_EPOCH_BOUND,
265            referee_bound: REFEREE_DEFAULT_BOUND,
266            get_logs_epoch_batch_size: 32,
267            get_logs_filter_max_epoch_range: None,
268            get_logs_filter_max_block_number_range: None,
269            get_logs_filter_max_limit: None,
270            sync_state_starting_epoch: None,
271            sync_state_epoch_gap: None,
272            pivot_hint_conf: None,
273        },
274        txpool.clone(),
275        statistics.clone(),
276        data_man.clone(),
277        pow_config.clone(),
278        pow.clone(),
279        notifications.clone(),
280        ConsensusExecutionConfiguration {
281            executive_trace: false,
282        },
283        verification_config.clone(),
284        NodeType::Archive,
285        pos_verifier.clone(),
286        /* pivot_hint */ None,
287        params,
288    ));
289
290    let sync = Arc::new(SynchronizationGraph::new(
291        consensus.clone(),
292        data_man.clone(),
293        statistics.clone(),
294        verification_config,
295        pow_config,
296        pow.clone(),
297        sync_config,
298        notifications,
299        machine,
300        pos_verifier.clone(),
301    ));
302
303    (sync, consensus)
304}
305
306/// This method is only used in tests and benchmarks.
307pub fn initialize_synchronization_graph(
308    db_dir: &str, beta: u64, h: u64, tcr: u64, tcb: u64, era_epoch_count: u64,
309    dbtype: DbType,
310) -> (
311    Arc<SynchronizationGraph>,
312    Arc<ConsensusGraph>,
313    Arc<BlockDataManager>,
314    Arc<Block>,
315) {
316    let vm = VmFactory::new(1024 * 32);
317    let pow = Arc::new(PowComputer::new(true));
318
319    let (data_man, genesis_block) =
320        initialize_data_manager(db_dir, dbtype, pow.clone(), vm.clone());
321
322    let (sync, consensus) = initialize_synchronization_graph_with_data_manager(
323        data_man.clone(),
324        beta,
325        h,
326        tcr,
327        tcb,
328        era_epoch_count,
329        pow,
330        vm,
331    );
332
333    (sync, consensus, data_man, genesis_block)
334}