cfxcore/
genesis_block.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5use std::{
6    collections::HashMap,
7    fs::File,
8    io::{BufRead, BufReader, Read},
9    sync::Arc,
10};
11
12use rustc_hex::FromHex;
13use serde::{Deserialize, Serialize};
14use toml::Value;
15
16use crate::keylib::KeyPair;
17use cfx_executor::internal_contract::initialize_internal_contract_accounts;
18use cfx_internal_common::debug::ComputeEpochDebugRecord;
19use cfx_parameters::{
20    consensus::{GENESIS_GAS_LIMIT, ONE_CFX_IN_DRIP},
21    consensus_internal::{
22        GENESIS_TOKEN_COUNT_IN_CFX, TWO_YEAR_UNLOCK_TOKEN_COUNT_IN_CFX,
23    },
24    genesis::*,
25    staking::POS_VOTE_PRICE,
26};
27use cfx_statedb::StateDb;
28use cfx_storage::{StorageManager, StorageManagerTrait};
29use cfx_types::{
30    address_util::AddressUtil, cal_contract_address_with_space, Address,
31    AddressSpaceUtil, AddressWithSpace, CreateContractAddressType, Space, H256,
32    U256,
33};
34use diem_crypto::{
35    bls::BLSPrivateKey, ec_vrf::EcVrfPublicKey, PrivateKey, ValidCryptoMaterial,
36};
37use diem_types::validator_config::{ConsensusPublicKey, ConsensusVRFPublicKey};
38use primitives::{
39    Action, Block, BlockHeaderBuilder, BlockReceipts, SignedTransaction,
40};
41use secret_store::SecretStore;
42
43use crate::verification::{compute_receipts_root, compute_transaction_root};
44use cfx_executor::{
45    executive::{ExecutionOutcome, ExecutiveContext, TransactOptions},
46    machine::Machine,
47    state::State,
48};
49use cfx_vm_types::Env;
50use diem_types::account_address::AccountAddress;
51use primitives::transaction::native_transaction::NativeTransaction;
52
53pub fn default(dev_or_test_mode: bool) -> HashMap<AddressWithSpace, U256> {
54    if !dev_or_test_mode {
55        return HashMap::new();
56    }
57    let mut accounts: HashMap<AddressWithSpace, U256> = HashMap::new();
58    // FIXME: Decide the genesis initialization for mainnet.
59    let balance = U256::from_dec_str("5000000000000000000000000000000000")
60        .expect("Not overflow"); // 5*10^33
61    accounts
62        .insert(DEV_GENESIS_KEY_PAIR.address().with_native_space(), balance);
63    accounts.insert(
64        DEV_GENESIS_KEY_PAIR_2.address().with_native_space(),
65        balance,
66    );
67    accounts
68        .insert(DEV_GENESIS_KEY_PAIR.evm_address().with_evm_space(), balance);
69    accounts.insert(
70        DEV_GENESIS_KEY_PAIR_2.evm_address().with_evm_space(),
71        balance,
72    );
73    accounts
74}
75
76pub fn load_secrets_file(
77    path: &String, secret_store: &SecretStore, space: Space,
78) -> Result<HashMap<AddressWithSpace, U256>, String> {
79    let file = File::open(path)
80        .map_err(|e| format!("failed to open file: {:?}", e))?;
81    let buffered = BufReader::new(file);
82
83    let mut accounts: HashMap<AddressWithSpace, U256> = HashMap::new();
84    let balance =
85        U256::from_dec_str("10000000000000000000000").map_err(|e| {
86            format!(
87                "failed to parse balance: value = {}, error = {:?}",
88                "10000000000000000000000", e
89            )
90        })?;
91    for line in buffered.lines() {
92        let keypair =
93            KeyPair::from_secret(line.unwrap().parse().unwrap()).unwrap();
94
95        match space {
96            Space::Native => {
97                // Insert balance for native space only
98                accounts.insert(
99                    keypair.address().with_native_space(),
100                    balance.clone(),
101                );
102            }
103            Space::Ethereum => {
104                // Insert balance for EVM space only
105                accounts.insert(
106                    keypair.evm_address().with_evm_space(),
107                    balance.clone(),
108                );
109            }
110        }
111
112        secret_store.insert(keypair);
113    }
114    Ok(accounts)
115}
116
117/// ` test_net_version` is used to update the genesis author so that after
118/// resetting, the chain of the older version will be discarded
119pub fn genesis_block(
120    storage_manager: &Arc<StorageManager>,
121    genesis_accounts: HashMap<AddressWithSpace, U256>,
122    test_net_version: Address, initial_difficulty: U256, machine: Arc<Machine>,
123    need_to_execute: bool, genesis_chain_id: Option<u32>,
124    initial_nodes: &Option<GenesisPosState>,
125) -> Block {
126    let mut state =
127        State::new(StateDb::new(storage_manager.get_state_for_genesis_write()))
128            .expect("Failed to initialize state");
129
130    let mut genesis_block_author = test_net_version;
131    genesis_block_author.set_user_account_type_bits();
132
133    initialize_internal_contract_accounts(
134        &mut state,
135        machine.internal_contracts().initialized_at_genesis(),
136    )
137    .expect("no db error");
138    trace!("genesis_accounts: {:?}", genesis_accounts);
139    for (addr, balance) in genesis_accounts {
140        state.add_balance(&addr, &balance).unwrap();
141        state.add_total_issued(balance);
142        if addr.space == Space::Ethereum {
143            state.add_total_evm_tokens(balance);
144        }
145    }
146    let genesis_account_address = GENESIS_ACCOUNT_ADDRESS.with_native_space();
147
148    let genesis_token_count =
149        U256::from(GENESIS_TOKEN_COUNT_IN_CFX) * U256::from(ONE_CFX_IN_DRIP);
150    state.add_total_issued(genesis_token_count);
151    let two_year_unlock_token_count =
152        U256::from(TWO_YEAR_UNLOCK_TOKEN_COUNT_IN_CFX)
153            * U256::from(ONE_CFX_IN_DRIP);
154    let four_year_unlock_token_count =
155        genesis_token_count - two_year_unlock_token_count;
156
157    let genesis_account_init_balance =
158        U256::from(ONE_CFX_IN_DRIP) * 100 + genesis_token_count;
159    state
160        .add_balance(&genesis_account_address, &genesis_account_init_balance)
161        .unwrap();
162    state.commit_cache(false);
163
164    let mut debug_record = Some(ComputeEpochDebugRecord::default());
165
166    let genesis_chain_id = genesis_chain_id.unwrap_or(0);
167    let mut genesis_transaction = NativeTransaction::default();
168    genesis_transaction.data = GENESIS_TRANSACTION_DATA_STR.as_bytes().into();
169    genesis_transaction.action = Action::Call(Default::default());
170    genesis_transaction.chain_id = genesis_chain_id;
171
172    let mut create_create2factory_transaction = NativeTransaction::default();
173    create_create2factory_transaction.nonce = 0.into();
174    create_create2factory_transaction.data =
175        GENESIS_TRANSACTION_CREATE_CREATE2FACTORY
176            .from_hex()
177            .unwrap();
178    create_create2factory_transaction.action = Action::Create;
179    create_create2factory_transaction.chain_id = genesis_chain_id;
180    create_create2factory_transaction.gas = 300000.into();
181    create_create2factory_transaction.gas_price = 1.into();
182    create_create2factory_transaction.storage_limit = 512;
183
184    let mut create_genesis_token_manager_two_year_unlock_transaction =
185        NativeTransaction::default();
186    create_genesis_token_manager_two_year_unlock_transaction.nonce = 1.into();
187    create_genesis_token_manager_two_year_unlock_transaction.data =
188        GENESIS_TRANSACTION_CREATE_GENESIS_TOKEN_MANAGER_TWO_YEAR_UNLOCK
189            .from_hex()
190            .unwrap();
191    create_genesis_token_manager_two_year_unlock_transaction.value =
192        two_year_unlock_token_count;
193    create_genesis_token_manager_two_year_unlock_transaction.action =
194        Action::Create;
195    create_genesis_token_manager_two_year_unlock_transaction.chain_id =
196        genesis_chain_id;
197    create_genesis_token_manager_two_year_unlock_transaction.gas =
198        2800000.into();
199    create_genesis_token_manager_two_year_unlock_transaction.gas_price =
200        1.into();
201    create_genesis_token_manager_two_year_unlock_transaction.storage_limit =
202        16000;
203
204    let mut create_genesis_token_manager_four_year_unlock_transaction =
205        NativeTransaction::default();
206    create_genesis_token_manager_four_year_unlock_transaction.nonce = 2.into();
207    create_genesis_token_manager_four_year_unlock_transaction.data =
208        GENESIS_TRANSACTION_CREATE_GENESIS_TOKEN_MANAGER_FOUR_YEAR_UNLOCK
209            .from_hex()
210            .unwrap();
211    create_genesis_token_manager_four_year_unlock_transaction.value =
212        four_year_unlock_token_count;
213    create_genesis_token_manager_four_year_unlock_transaction.action =
214        Action::Create;
215    create_genesis_token_manager_four_year_unlock_transaction.chain_id =
216        genesis_chain_id;
217    create_genesis_token_manager_four_year_unlock_transaction.gas =
218        5000000.into();
219    create_genesis_token_manager_four_year_unlock_transaction.gas_price =
220        1.into();
221    create_genesis_token_manager_four_year_unlock_transaction.storage_limit =
222        32000;
223
224    let mut create_genesis_investor_fund_transaction =
225        NativeTransaction::default();
226    create_genesis_investor_fund_transaction.nonce = 3.into();
227    create_genesis_investor_fund_transaction.data =
228        GENESIS_TRANSACTION_CREATE_FUND_POOL.from_hex().unwrap();
229    create_genesis_investor_fund_transaction.action = Action::Create;
230    create_genesis_investor_fund_transaction.chain_id = genesis_chain_id;
231    create_genesis_investor_fund_transaction.gas = 400000.into();
232    create_genesis_investor_fund_transaction.gas_price = 1.into();
233    create_genesis_investor_fund_transaction.storage_limit = 1000;
234
235    let mut create_genesis_team_fund_transaction = NativeTransaction::default();
236    create_genesis_team_fund_transaction.nonce = 4.into();
237    create_genesis_team_fund_transaction.data =
238        GENESIS_TRANSACTION_CREATE_FUND_POOL.from_hex().unwrap();
239    create_genesis_team_fund_transaction.action = Action::Create;
240    create_genesis_team_fund_transaction.chain_id = genesis_chain_id;
241    create_genesis_team_fund_transaction.gas = 400000.into();
242    create_genesis_team_fund_transaction.gas_price = 1.into();
243    create_genesis_team_fund_transaction.storage_limit = 1000;
244
245    let mut create_genesis_eco_fund_transaction = NativeTransaction::default();
246    create_genesis_eco_fund_transaction.nonce = 5.into();
247    create_genesis_eco_fund_transaction.data =
248        GENESIS_TRANSACTION_CREATE_FUND_POOL.from_hex().unwrap();
249    create_genesis_eco_fund_transaction.action = Action::Create;
250    create_genesis_eco_fund_transaction.chain_id = genesis_chain_id;
251    create_genesis_eco_fund_transaction.gas = 400000.into();
252    create_genesis_eco_fund_transaction.gas_price = 1.into();
253    create_genesis_eco_fund_transaction.storage_limit = 1000;
254
255    let mut create_genesis_community_fund_transaction =
256        NativeTransaction::default();
257    create_genesis_community_fund_transaction.nonce = 6.into();
258    create_genesis_community_fund_transaction.data =
259        GENESIS_TRANSACTION_CREATE_FUND_POOL.from_hex().unwrap();
260    create_genesis_community_fund_transaction.action = Action::Create;
261    create_genesis_community_fund_transaction.chain_id = genesis_chain_id;
262    create_genesis_community_fund_transaction.gas = 400000.into();
263    create_genesis_community_fund_transaction.gas_price = 1.into();
264    create_genesis_community_fund_transaction.storage_limit = 1000;
265
266    let genesis_transactions = vec![
267        Arc::new(genesis_transaction.fake_sign(Default::default())),
268        Arc::new(
269            create_create2factory_transaction
270                .fake_sign(genesis_account_address),
271        ),
272        Arc::new(
273            create_genesis_token_manager_two_year_unlock_transaction
274                .fake_sign(genesis_account_address),
275        ),
276        Arc::new(
277            create_genesis_token_manager_four_year_unlock_transaction
278                .fake_sign(genesis_account_address),
279        ),
280        Arc::new(
281            create_genesis_investor_fund_transaction
282                .fake_sign(genesis_account_address),
283        ),
284        Arc::new(
285            create_genesis_team_fund_transaction
286                .fake_sign(genesis_account_address),
287        ),
288        Arc::new(
289            create_genesis_eco_fund_transaction
290                .fake_sign(genesis_account_address),
291        ),
292        Arc::new(
293            create_genesis_community_fund_transaction
294                .fake_sign(genesis_account_address),
295        ),
296    ];
297
298    if need_to_execute {
299        const CREATE2FACTORY_TX_INDEX: usize = 1;
300        /*
301        const TWO_YEAR_UNLOCK_TX_INDEX: usize = 2;
302        const FOUR_YEAR_UNLOCK_TX_INDEX: usize = 3;
303        const INVESTOR_FUND_TX_INDEX: usize = 4;
304        const TEAM_FUND_TX_INDEX: usize = 5;
305        const ECO_FUND_TX_INDEX: usize = 6;
306        const COMMUNITY_FUND_TX_INDEX: usize = 7;
307        */
308        let contract_name_list = vec![
309            "CREATE2FACTORY",
310            "TWO_YEAR_UNLOCK",
311            "FOUR_YEAR_UNLOCK",
312            "INVESTOR_FUND",
313            "TEAM_FUND",
314            "ECO_FUND",
315            "COMMUNITY_FUND",
316        ];
317
318        for i in CREATE2FACTORY_TX_INDEX..=contract_name_list.len() {
319            execute_genesis_transaction(
320                genesis_transactions[i].as_ref(),
321                &mut state,
322                machine.clone(),
323            );
324
325            let (contract_address, _) = cal_contract_address_with_space(
326                CreateContractAddressType::FromSenderNonceAndCodeHash,
327                &genesis_account_address,
328                &(i - 1).into(),
329                genesis_transactions[i].as_ref().data(),
330            );
331
332            state
333                .set_admin(&contract_address.address, &Address::zero())
334                .expect("");
335            info!(
336                "Genesis {:?} addresses: {:?}",
337                contract_name_list[i - 1],
338                contract_address
339            );
340            state.commit_cache(false);
341        }
342    }
343
344    if let Some(initial_nodes) = initial_nodes {
345        for node in &initial_nodes.initial_nodes {
346            let stake_balance = U256::from(node.voting_power) * *POS_VOTE_PRICE;
347            // TODO(lpl): Pass in signed tx so they can be retired.
348            state
349                .add_balance(
350                    &node.address.with_native_space(),
351                    &(stake_balance
352                        + U256::from(ONE_CFX_IN_DRIP) * U256::from(20)),
353                )
354                .unwrap();
355            state
356                .deposit(&node.address, &stake_balance, 0, false)
357                .unwrap();
358            state.commit_cache(false);
359            let signed_tx = node
360                .register_tx
361                .clone()
362                .fake_sign(node.address.with_native_space());
363            execute_genesis_transaction(
364                &signed_tx,
365                &mut state,
366                machine.clone(),
367            );
368        }
369    }
370
371    state
372        .genesis_special_remove_account(&genesis_account_address.address)
373        .expect("Clean account failed");
374
375    let state_root = state
376        .compute_state_root_for_genesis(
377            /* debug_record = */ debug_record.as_mut(),
378        )
379        .unwrap();
380    let receipt_root = compute_receipts_root(&vec![Arc::new(BlockReceipts {
381        receipts: vec![],
382        block_number: 0,
383        secondary_reward: U256::zero(),
384        tx_execution_error_messages: vec![],
385    })]);
386
387    let mut genesis = Block::new(
388        BlockHeaderBuilder::new()
389            .with_deferred_state_root(state_root.aux_info.state_root_hash)
390            .with_deferred_receipts_root(receipt_root)
391            .with_gas_limit(GENESIS_GAS_LIMIT.into())
392            .with_author(genesis_block_author)
393            .with_difficulty(initial_difficulty)
394            .with_transactions_root(compute_transaction_root(
395                &genesis_transactions,
396            ))
397            .build(),
398        genesis_transactions,
399    );
400    genesis.block_header.compute_hash();
401    debug!(
402        "Initialize genesis_block={:?} hash={:?}",
403        genesis,
404        genesis.hash()
405    );
406
407    state
408        .commit(
409            genesis.block_header.hash(),
410            /* debug_record = */ debug_record.as_mut(),
411        )
412        .unwrap();
413    genesis.block_header.pow_hash = Some(Default::default());
414    debug!(
415        "genesis debug_record {}",
416        serde_json::to_string(&debug_record).unwrap()
417    );
418    genesis
419}
420
421pub fn register_transaction(
422    bls_priv_key: BLSPrivateKey, vrf_pub_key: EcVrfPublicKey, power: u64,
423    genesis_chain_id: u32, legacy: bool,
424) -> NativeTransaction {
425    /// TODO: test this function with new internal contracts.
426    use bls_signatures::{
427        sigma_protocol, PrivateKey as BlsPrivKey, PublicKey as BlsPubKey,
428        Serialize,
429    };
430    use cfx_parameters::internal_contract_addresses::POS_REGISTER_CONTRACT_ADDRESS;
431    use rand_08::rngs::OsRng;
432    use solidity_abi::ABIEncodable;
433    use tiny_keccak::{Hasher, Keccak};
434
435    let bls_pub_key = bls_priv_key.public_key();
436    let (commit, answer) =
437        sigma_protocol::prove(bls_priv_key.raw_key(), &mut OsRng, legacy);
438
439    let mut encoded_commit = Vec::<u8>::new();
440    BlsPubKey::from(commit)
441        .write_bytes(&mut encoded_commit)
442        .expect("write to Vec<u8> never fails");
443
444    let mut encoded_answer = Vec::<u8>::new();
445    BlsPrivKey::from(answer)
446        .write_bytes(&mut encoded_answer)
447        .expect("write to Vec<u8> never fails");
448
449    let encoded_bls_pub_key = bls_pub_key.to_bytes();
450
451    let encoded_vrf_pub_key = vrf_pub_key.to_bytes();
452
453    let mut hasher = Keccak::v256();
454    hasher.update(encoded_bls_pub_key.as_slice());
455    hasher.update(encoded_vrf_pub_key.as_slice());
456    let mut computed_identifier = H256::default();
457    hasher.finalize(computed_identifier.as_bytes_mut());
458
459    let params = (
460        computed_identifier,
461        power,
462        encoded_bls_pub_key,
463        encoded_vrf_pub_key,
464        [encoded_commit, encoded_answer],
465    );
466
467    let mut call_data: Vec<u8> = "e335b451".from_hex().unwrap();
468    call_data.extend_from_slice(&params.abi_encode());
469
470    let mut tx = NativeTransaction::default();
471    tx.nonce = 0.into();
472    tx.data = call_data;
473    tx.value = U256::zero();
474    tx.action = Action::Call(POS_REGISTER_CONTRACT_ADDRESS);
475    tx.chain_id = genesis_chain_id;
476    tx.gas = 200000.into();
477    tx.gas_price = 1.into();
478    tx.storage_limit = 16000;
479    tx
480}
481
482fn execute_genesis_transaction(
483    transaction: &SignedTransaction, state: &mut State, machine: Arc<Machine>,
484) {
485    let mut env = Env::default();
486    env.transaction_hash = transaction.hash();
487
488    let options = TransactOptions::default();
489    let r = {
490        ExecutiveContext::new(
491            state,
492            &env,
493            machine.as_ref(),
494            &machine.spec(env.number, env.epoch_height),
495        )
496        .transact(transaction, options)
497        .unwrap()
498    };
499    state.update_state_post_tx_execution(false);
500
501    match &r {
502        ExecutionOutcome::Finished(_executed) => {}
503        _ => {
504            panic!("genesis transaction should not fail! err={:?}", r);
505        }
506    }
507}
508
509pub fn load_file(
510    path: &String, address_parser: impl Fn(&str) -> Result<Address, String>,
511) -> Result<HashMap<AddressWithSpace, U256>, String> {
512    let mut content = String::new();
513    let mut file = File::open(path)
514        .map_err(|e| format!("failed to open file: {:?}", e))?;
515    file.read_to_string(&mut content)
516        .map_err(|e| format!("failed to read file content: {:?}", e))?;
517    let account_values = content
518        .parse::<toml::Value>()
519        .map_err(|e| format!("failed to parse toml file: {:?}", e))?;
520
521    let mut accounts: HashMap<AddressWithSpace, U256> = HashMap::new();
522    match account_values {
523        Value::Table(table) => {
524            for (key, value) in table {
525                let addr = address_parser(&key).map_err(|e| {
526                    format!(
527                        "failed to parse address: value = {}, error = {:?}",
528                        key, e
529                    )
530                })?;
531
532                match value {
533                    Value::String(balance) => {
534                        let balance = U256::from_dec_str(&balance).map_err(|e| format!("failed to parse balance: value = {}, error = {:?}", balance, e))?;
535                        accounts.insert(addr.with_native_space(), balance);
536                    }
537                    _ => {
538                        return Err(
539                            "balance in toml file requires String type".into(),
540                        );
541                    }
542                }
543            }
544        }
545        _ => {
546            return Err(format!(
547                "invalid root value type {:?} in toml file",
548                account_values.type_str()
549            ));
550        }
551    }
552
553    Ok(accounts)
554}
555
556#[derive(Serialize, Deserialize, Clone)]
557pub struct GenesisPosNodeInfo {
558    pub address: Address,
559    pub bls_key: ConsensusPublicKey,
560    pub vrf_key: ConsensusVRFPublicKey,
561    pub voting_power: u64,
562    pub register_tx: NativeTransaction,
563}
564
565#[derive(Serialize, Deserialize)]
566pub struct GenesisPosState {
567    pub initial_nodes: Vec<GenesisPosNodeInfo>,
568    pub initial_committee: Vec<(AccountAddress, u64)>,
569    pub initial_seed: H256,
570}