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 verification_config = VerificationConfig::new(
207        true, /* test_mode */
208        REFEREE_DEFAULT_BOUND,
209        MAX_BLOCK_SIZE_IN_BYTES,
210        TRANSACTION_DEFAULT_EPOCH_BOUND,
211        TXPOOL_DEFAULT_NONCE_BITS,
212        pos_verifier.enable_height(),
213        machine.clone(),
214    );
215
216    let txpool = Arc::new(TransactionPool::new(
217        TxPoolConfig::default(),
218        verification_config.clone(),
219        data_man.clone(),
220        machine.clone(),
221    ));
222    let statistics = Arc::new(Statistics::new());
223
224    let pow_config = ProofOfWorkConfig::new(
225        true,      /* test_mode */
226        false,     /* use_octopus_in_test_mode */
227        "disable", /* mining_type */
228        Some(10),
229        String::from(""), /* stratum_listen_addr */
230        0,                /* stratum_port */
231        None,             /* stratum_secret */
232        1,                /* pow_problem_window_size */
233        0,                /* cip_height */
234    );
235    let sync_config = SyncGraphConfig {
236        future_block_buffer_capacity: 1,
237        enable_state_expose: false,
238        is_consortium: false,
239    };
240    let notifications = Notifications::init();
241    let consensus = Arc::new(ConsensusGraph::new(
242        ConsensusConfig {
243            chain_id: ChainIdParamsInner::new_simple(AllChainID::new(1, 1)),
244            inner_conf: ConsensusInnerConfig {
245                adaptive_weight_beta: beta,
246                heavy_block_difficulty_ratio: h,
247                timer_chain_block_difficulty_ratio: tcr,
248                timer_chain_beta: tcb,
249                era_epoch_count,
250                enable_optimistic_execution: false,
251                enable_state_expose: false,
252                pos_pivot_decision_defer_epoch_count: 50,
253                cip113_pivot_decision_defer_epoch_count: 50,
254                cip113_transition_height: u64::MAX,
255                debug_dump_dir_invalid_state_root: None,
256                debug_invalid_state_root_epoch: None,
257                force_recompute_height_during_construct_pivot: None,
258                recovery_latest_mpt_snapshot: false,
259                use_isolated_db_for_mpt_table: false,
260            },
261            bench_mode: true, /* Set bench_mode to true so that we skip
262                               * execution */
263            transaction_epoch_bound: TRANSACTION_DEFAULT_EPOCH_BOUND,
264            referee_bound: REFEREE_DEFAULT_BOUND,
265            get_logs_epoch_batch_size: 32,
266            get_logs_filter_max_epoch_range: None,
267            get_logs_filter_max_block_number_range: None,
268            get_logs_filter_max_limit: None,
269            sync_state_starting_epoch: None,
270            sync_state_epoch_gap: None,
271            pivot_hint_conf: None,
272        },
273        txpool.clone(),
274        statistics.clone(),
275        data_man.clone(),
276        pow_config.clone(),
277        pow.clone(),
278        notifications.clone(),
279        ConsensusExecutionConfiguration {
280            executive_trace: false,
281        },
282        verification_config.clone(),
283        NodeType::Archive,
284        pos_verifier.clone(),
285        /* pivot_hint */ None,
286        params,
287    ));
288
289    let sync = Arc::new(SynchronizationGraph::new(
290        consensus.clone(),
291        data_man.clone(),
292        statistics.clone(),
293        verification_config,
294        pow_config,
295        pow.clone(),
296        sync_config,
297        notifications,
298        machine,
299        pos_verifier.clone(),
300    ));
301
302    (sync, consensus)
303}
304
305/// This method is only used in tests and benchmarks.
306pub fn initialize_synchronization_graph(
307    db_dir: &str, beta: u64, h: u64, tcr: u64, tcb: u64, era_epoch_count: u64,
308    dbtype: DbType,
309) -> (
310    Arc<SynchronizationGraph>,
311    Arc<ConsensusGraph>,
312    Arc<BlockDataManager>,
313    Arc<Block>,
314) {
315    let vm = VmFactory::new(1024 * 32);
316    let pow = Arc::new(PowComputer::new(true));
317
318    let (data_man, genesis_block) =
319        initialize_data_manager(db_dir, dbtype, pow.clone(), vm.clone());
320
321    let (sync, consensus) = initialize_synchronization_graph_with_data_manager(
322        data_man.clone(),
323        beta,
324        h,
325        tcr,
326        tcb,
327        era_epoch_count,
328        pow,
329        vm,
330    );
331
332    (sync, consensus, data_man, genesis_block)
333}