casper_storage/system/
genesis.rs

1//! Support for a genesis process.
2#![allow(unused_imports)]
3
4use std::{
5    cell::RefCell,
6    collections::{BTreeMap, BTreeSet},
7    fmt, iter,
8    rc::Rc,
9};
10
11use itertools::Itertools;
12use num::Zero;
13use num_rational::Ratio;
14use rand::{
15    distributions::{Distribution, Standard},
16    Rng,
17};
18use serde::{Deserialize, Serialize};
19
20use casper_types::{
21    addressable_entity::{
22        ActionThresholds, EntityKind, EntityKindTag, MessageTopics, NamedKeyAddr, NamedKeyValue,
23    },
24    bytesrepr,
25    contracts::NamedKeys,
26    execution::Effects,
27    system::{
28        auction::{
29            self, BidAddr, BidKind, DelegationRate, Delegator, SeigniorageRecipientV2,
30            SeigniorageRecipients, SeigniorageRecipientsSnapshot, SeigniorageRecipientsSnapshotV2,
31            SeigniorageRecipientsV2, Staking, ValidatorBid, AUCTION_DELAY_KEY,
32            DEFAULT_SEIGNIORAGE_RECIPIENTS_SNAPSHOT_VERSION, DELEGATION_RATE_DENOMINATOR,
33            ERA_END_TIMESTAMP_MILLIS_KEY, ERA_ID_KEY, INITIAL_ERA_END_TIMESTAMP_MILLIS,
34            INITIAL_ERA_ID, LOCKED_FUNDS_PERIOD_KEY, SEIGNIORAGE_RECIPIENTS_SNAPSHOT_KEY,
35            SEIGNIORAGE_RECIPIENTS_SNAPSHOT_VERSION_KEY, UNBONDING_DELAY_KEY, VALIDATOR_SLOTS_KEY,
36        },
37        handle_payment::{self, ACCUMULATION_PURSE_KEY},
38        mint::{
39            self, ARG_ROUND_SEIGNIORAGE_RATE, MINT_GAS_HOLD_HANDLING_KEY,
40            MINT_GAS_HOLD_INTERVAL_KEY, ROUND_SEIGNIORAGE_RATE_KEY, TOTAL_SUPPLY_KEY,
41        },
42        SystemEntityType, AUCTION, HANDLE_PAYMENT, MINT,
43    },
44    AccessRights, AddressableEntity, AddressableEntityHash, AdministratorAccount, BlockGlobalAddr,
45    BlockTime, ByteCode, ByteCodeAddr, ByteCodeHash, ByteCodeKind, CLValue, Chainspec,
46    ChainspecRegistry, Digest, EntityAddr, EntityVersions, EntryPointAddr, EntryPointValue,
47    EntryPoints, EraId, FeeHandling, GenesisAccount, GenesisConfig, Groups, HashAddr, Key, Motes,
48    Package, PackageHash, PackageStatus, Phase, ProtocolVersion, PublicKey, RefundHandling,
49    StoredValue, SystemConfig, SystemHashRegistry, Tagged, TimeDiff, URef, WasmConfig, U512,
50};
51
52use crate::{
53    global_state::state::StateProvider,
54    system::genesis::{
55        account_contract_installer::AccountContractInstaller,
56        entity_installer::EntityGenesisInstaller,
57    },
58    tracking_copy::{TrackingCopy, TrackingCopyError},
59    AddressGenerator,
60};
61
62mod account_contract_installer;
63mod entity_installer;
64
65const DEFAULT_ADDRESS: [u8; 32] = [0; 32];
66
67const NO_WASM: bool = true;
68
69/// Error returned as a result of a failed genesis process.
70#[derive(Clone, Debug)]
71pub enum GenesisError {
72    /// Error creating a runtime.
73    StateUninitialized,
74    /// Error obtaining the mint's contract key.
75    InvalidMintKey,
76    /// Missing mint contract.
77    MissingMintContract,
78    /// Unexpected stored value variant.
79    UnexpectedStoredValue,
80    /// Error executing the mint system contract.
81    MintError(mint::Error),
82    /// Error converting a [`CLValue`] to a concrete type.
83    CLValue(String),
84    /// Specified validator does not exist among the genesis accounts.
85    OrphanedDelegator {
86        /// Validator's public key.
87        validator_public_key: PublicKey,
88        /// Delegator's public key.
89        delegator_public_key: PublicKey,
90    },
91    /// Duplicated delegator entry found for a given validator.
92    DuplicatedDelegatorEntry {
93        /// Validator's public key.
94        validator_public_key: PublicKey,
95        /// Delegator's public key.
96        delegator_public_key: PublicKey,
97    },
98    /// Delegation rate outside the allowed range.
99    InvalidDelegationRate {
100        /// Delegator's public key.
101        public_key: PublicKey,
102        /// Invalid delegation rate specified in the genesis account entry.
103        delegation_rate: DelegationRate,
104    },
105    /// Invalid bond amount in a genesis account.
106    InvalidBondAmount {
107        /// Validator's public key.
108        public_key: PublicKey,
109    },
110    /// Invalid delegated amount in a genesis account.
111    InvalidDelegatedAmount {
112        /// Delegator's public key.
113        public_key: PublicKey,
114    },
115    /// Failed to create system registry.
116    FailedToCreateSystemRegistry,
117    /// Missing system contract hash.
118    MissingSystemContractHash(String),
119    /// Invalid number of validator slots configured.
120    InvalidValidatorSlots {
121        /// Number of validators in the genesis config.
122        validators: usize,
123        /// Number of validator slots specified.
124        validator_slots: u32,
125    },
126    /// The chainspec registry is missing a required entry.
127    MissingChainspecRegistryEntry,
128    /// Duplicated administrator entry.
129    ///
130    /// This error can occur only on some private chains.
131    DuplicatedAdministratorEntry,
132    /// A bytesrepr Error.
133    Bytesrepr(bytesrepr::Error),
134    /// Genesis process requires initial accounts.
135    MissingGenesisAccounts,
136    /// A tracking copy error.
137    TrackingCopy(TrackingCopyError),
138}
139
140impl fmt::Display for GenesisError {
141    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
142        write!(f, "GenesisError: {:?}", self)
143    }
144}
145
146/// State for genesis installer.
147pub enum GenesisInstaller<S>
148where
149    S: StateProvider,
150{
151    /// Install genesis using the Accounts/Contracts model.
152    AccountContract(AccountContractInstaller<S>),
153    /// Install genesis using the Addressable Entity model.
154    Entity(EntityGenesisInstaller<S>),
155}
156impl<S> GenesisInstaller<S>
157where
158    S: StateProvider,
159{
160    /// Ctor.
161    pub fn new(
162        genesis_config_hash: Digest,
163        protocol_version: ProtocolVersion,
164        config: GenesisConfig,
165        tracking_copy: Rc<RefCell<TrackingCopy<<S as StateProvider>::Reader>>>,
166    ) -> Self {
167        if config.enable_entity() {
168            GenesisInstaller::Entity(EntityGenesisInstaller::new(
169                genesis_config_hash,
170                protocol_version,
171                config,
172                tracking_copy,
173            ))
174        } else {
175            GenesisInstaller::AccountContract(AccountContractInstaller::new(
176                genesis_config_hash,
177                protocol_version,
178                config,
179                tracking_copy,
180            ))
181        }
182    }
183
184    /// Finalize genesis.
185    pub fn finalize(self) -> Effects {
186        match self {
187            GenesisInstaller::AccountContract(installer) => installer.finalize(),
188            GenesisInstaller::Entity(installer) => installer.finalize(),
189        }
190    }
191
192    /// Performs a complete system installation.
193    pub fn install(
194        &mut self,
195        chainspec_registry: ChainspecRegistry,
196    ) -> Result<(), Box<GenesisError>> {
197        match self {
198            GenesisInstaller::AccountContract(installer) => installer.install(chainspec_registry),
199            GenesisInstaller::Entity(installer) => installer.install(chainspec_registry),
200        }
201    }
202}
203
204#[cfg(test)]
205mod tests {
206    use super::*;
207    use casper_types::AsymmetricType;
208    use rand::RngCore;
209
210    use casper_types::{bytesrepr, SecretKey};
211
212    #[test]
213    fn bytesrepr_roundtrip() {
214        let mut rng = rand::thread_rng();
215        let genesis_account: GenesisAccount = rng.gen();
216        bytesrepr::test_serialization_roundtrip(&genesis_account);
217    }
218
219    #[test]
220    fn system_account_bytesrepr_roundtrip() {
221        let genesis_account = GenesisAccount::system();
222
223        bytesrepr::test_serialization_roundtrip(&genesis_account);
224    }
225
226    #[test]
227    fn genesis_account_bytesrepr_roundtrip() {
228        let mut rng = rand::thread_rng();
229        let mut bytes = [0u8; 32];
230        rng.fill_bytes(&mut bytes[..]);
231        let secret_key = SecretKey::ed25519_from_bytes(bytes).unwrap();
232        let public_key: PublicKey = PublicKey::from(&secret_key);
233
234        let genesis_account_1 = GenesisAccount::account(public_key.clone(), Motes::new(100), None);
235
236        bytesrepr::test_serialization_roundtrip(&genesis_account_1);
237
238        let genesis_account_2 =
239            GenesisAccount::account(public_key, Motes::new(100), Some(rng.gen()));
240
241        bytesrepr::test_serialization_roundtrip(&genesis_account_2);
242    }
243
244    #[test]
245    fn delegator_bytesrepr_roundtrip() {
246        let mut rng = rand::thread_rng();
247        let mut validator_bytes = [0u8; 32];
248        let mut delegator_bytes = [0u8; 32];
249        rng.fill_bytes(&mut validator_bytes[..]);
250        rng.fill_bytes(&mut delegator_bytes[..]);
251        let validator_secret_key = SecretKey::ed25519_from_bytes(validator_bytes).unwrap();
252        let delegator_secret_key = SecretKey::ed25519_from_bytes(delegator_bytes).unwrap();
253
254        let validator_public_key = PublicKey::from(&validator_secret_key);
255        let delegator_public_key = PublicKey::from(&delegator_secret_key);
256
257        let genesis_account = GenesisAccount::delegator(
258            validator_public_key,
259            delegator_public_key,
260            Motes::new(100),
261            Motes::zero(),
262        );
263
264        bytesrepr::test_serialization_roundtrip(&genesis_account);
265    }
266
267    #[test]
268    fn administrator_account_bytesrepr_roundtrip() {
269        let administrator_account = AdministratorAccount::new(
270            PublicKey::ed25519_from_bytes([123u8; 32]).unwrap(),
271            Motes::new(U512::MAX),
272        );
273        bytesrepr::test_serialization_roundtrip(&administrator_account);
274    }
275}