genesis - [mainnet]
use 0x1::account;use 0x1::aggregator_factory;use 0x1::aptos_account;use 0x1::aptos_coin;use 0x1::aptos_governance;use 0x1::block;use 0x1::chain_id;use 0x1::chain_status;use 0x1::coin;use 0x1::consensus_config;use 0x1::create_signer;use 0x1::error;use 0x1::execution_config;use 0x1::fixed_point32;use 0x1::gas_schedule;use 0x1::nonce_validation;use 0x1::reconfiguration;use 0x1::simple_map;use 0x1::stake;use 0x1::staking_config;use 0x1::staking_contract;use 0x1::state_storage;use 0x1::storage_gas;use 0x1::timestamp;use 0x1::transaction_fee;use 0x1::transaction_validation;use 0x1::vector;use 0x1::version;use 0x1::vesting;
Constants
const EACCOUNT_DOES_NOT_EXIST: u64 = 2;
const EDUPLICATE_ACCOUNT: u64 = 1;
Structs
AccountMap
struct AccountMap has drop
Fields
-
account_address: address
-
balance: u64
EmployeeAccountMap
struct EmployeeAccountMap has copy, drop
Fields
-
accounts: vector<address>
-
validator: genesis::ValidatorConfigurationWithCommission
-
vesting_schedule_numerator: vector<u64>
-
vesting_schedule_denominator: u64
-
beneficiary_resetter: address
ValidatorConfiguration
struct ValidatorConfiguration has copy, drop
Fields
ValidatorConfigurationWithCommission
struct ValidatorConfigurationWithCommission has copy, drop
Fields
-
validator_config: genesis::ValidatorConfiguration
-
commission_percentage: u64
-
join_during_genesis: bool
Functions
initialize
Genesis step 1: Initialize aptos framework account and core modules on chain.
fun initialize(gas_schedule: vector<u8>, chain_id: u8, initial_version: u64, consensus_config: vector<u8>, execution_config: vector<u8>, epoch_interval_microsecs: u64, minimum_stake: u64, maximum_stake: u64, recurring_lockup_duration_secs: u64, allow_validator_set_change: bool, rewards_rate: u64, rewards_rate_denominator: u64, voting_power_increase_limit: u64)
Implementation
fun initialize( gas_schedule: vector<u8>, chain_id: u8, initial_version: u64, consensus_config: vector<u8>, execution_config: vector<u8>, epoch_interval_microsecs: u64, minimum_stake: u64, maximum_stake: u64, recurring_lockup_duration_secs: u64, allow_validator_set_change: bool, rewards_rate: u64, rewards_rate_denominator: u64, voting_power_increase_limit: u64,) { // Initialize the aptos framework account. This is the account where system resources and modules will be // deployed to. This will be entirely managed by on-chain governance and no entities have the key or privileges // to use this account. let (aptos_framework_account, aptos_framework_signer_cap) = account::create_framework_reserved_account(@aptos_framework); // Initialize account configs on aptos framework account. account::initialize(&aptos_framework_account);
transaction_validation::initialize( &aptos_framework_account, b"script_prologue", b"module_prologue", b"multi_agent_script_prologue", b"epilogue", ); // Give the decentralized on-chain governance control over the core framework account. aptos_governance::store_signer_cap(&aptos_framework_account, @aptos_framework, aptos_framework_signer_cap);
// put reserved framework reserved accounts under aptos governance let framework_reserved_addresses = vector<address>[@0x2, @0x3, @0x4, @0x5, @0x6, @0x7, @0x8, @0x9, @0xa]; while (!vector::is_empty(&framework_reserved_addresses)) { let address = vector::pop_back<address>(&mut framework_reserved_addresses); let (_, framework_signer_cap) = account::create_framework_reserved_account(address); aptos_governance::store_signer_cap(&aptos_framework_account, address, framework_signer_cap); };
consensus_config::initialize(&aptos_framework_account, consensus_config); execution_config::set(&aptos_framework_account, execution_config); version::initialize(&aptos_framework_account, initial_version); stake::initialize(&aptos_framework_account); timestamp::set_time_has_started(&aptos_framework_account); staking_config::initialize( &aptos_framework_account, minimum_stake, maximum_stake, recurring_lockup_duration_secs, allow_validator_set_change, rewards_rate, rewards_rate_denominator, voting_power_increase_limit, ); storage_gas::initialize(&aptos_framework_account); gas_schedule::initialize(&aptos_framework_account, gas_schedule);
// Ensure we can create aggregators for supply, but not enable it for common use just yet. aggregator_factory::initialize_aggregator_factory(&aptos_framework_account);
chain_id::initialize(&aptos_framework_account, chain_id); reconfiguration::initialize(&aptos_framework_account); block::initialize(&aptos_framework_account, epoch_interval_microsecs); state_storage::initialize(&aptos_framework_account); nonce_validation::initialize(&aptos_framework_account);}
initialize_aptos_coin
Genesis step 2: Initialize Aptos coin.
fun initialize_aptos_coin(aptos_framework: &signer)
Implementation
fun initialize_aptos_coin(aptos_framework: &signer) { let (burn_cap, mint_cap) = aptos_coin::initialize(aptos_framework);
coin::create_coin_conversion_map(aptos_framework); coin::create_pairing<AptosCoin>(aptos_framework);
// Give stake module MintCapability<AptosCoin> so it can mint rewards. stake::store_aptos_coin_mint_cap(aptos_framework, mint_cap); // Give transaction_fee module BurnCapability<AptosCoin> so it can burn gas. transaction_fee::store_aptos_coin_burn_cap(aptos_framework, burn_cap); // Give transaction_fee module MintCapability<AptosCoin> so it can mint refunds. transaction_fee::store_aptos_coin_mint_cap(aptos_framework, mint_cap);}
initialize_core_resources_and_aptos_coin
Only called for testnets and e2e tests.
fun initialize_core_resources_and_aptos_coin(aptos_framework: &signer, core_resources_auth_key: vector<u8>)
Implementation
fun initialize_core_resources_and_aptos_coin( aptos_framework: &signer, core_resources_auth_key: vector<u8>,) { let (burn_cap, mint_cap) = aptos_coin::initialize(aptos_framework);
coin::create_coin_conversion_map(aptos_framework); coin::create_pairing<AptosCoin>(aptos_framework);
// Give stake module MintCapability<AptosCoin> so it can mint rewards. stake::store_aptos_coin_mint_cap(aptos_framework, mint_cap); // Give transaction_fee module BurnCapability<AptosCoin> so it can burn gas. transaction_fee::store_aptos_coin_burn_cap(aptos_framework, burn_cap); // Give transaction_fee module MintCapability<AptosCoin> so it can mint refunds. transaction_fee::store_aptos_coin_mint_cap(aptos_framework, mint_cap);
let core_resources = account::create_account(@core_resources); account::rotate_authentication_key_internal(&core_resources, core_resources_auth_key); aptos_account::register_apt(&core_resources); // registers APT store aptos_coin::configure_accounts_for_test(aptos_framework, &core_resources, mint_cap);}
create_accounts
fun create_accounts(aptos_framework: &signer, accounts: vector<genesis::AccountMap>)
Implementation
fun create_accounts(aptos_framework: &signer, accounts: vector<AccountMap>) { let unique_accounts = vector::empty(); vector::for_each_ref(&accounts, |account_map| { let account_map: &AccountMap = account_map; assert!( !vector::contains(&unique_accounts, &account_map.account_address), error::already_exists(EDUPLICATE_ACCOUNT), ); vector::push_back(&mut unique_accounts, account_map.account_address);
create_account( aptos_framework, account_map.account_address, account_map.balance, ); });}
create_account
This creates an funds an account if it doesn’t exist. If it exists, it just returns the signer.
fun create_account(aptos_framework: &signer, account_address: address, balance: u64): signer
Implementation
fun create_account(aptos_framework: &signer, account_address: address, balance: u64): signer { let account = if (account::exists_at(account_address)) { create_signer(account_address) } else { account::create_account(account_address) };
if (coin::balance<AptosCoin>(account_address) == 0) { coin::register<AptosCoin>(&account); aptos_coin::mint(aptos_framework, account_address, balance); }; account}
create_employee_validators
fun create_employee_validators(employee_vesting_start: u64, employee_vesting_period_duration: u64, employees: vector<genesis::EmployeeAccountMap>)
Implementation
fun create_employee_validators( employee_vesting_start: u64, employee_vesting_period_duration: u64, employees: vector<EmployeeAccountMap>,) { let unique_accounts = vector::empty();
vector::for_each_ref(&employees, |employee_group| { let j = 0; let employee_group: &EmployeeAccountMap = employee_group; let num_employees_in_group = vector::length(&employee_group.accounts);
let buy_ins = simple_map::create();
while (j < num_employees_in_group) { let account = vector::borrow(&employee_group.accounts, j); assert!( !vector::contains(&unique_accounts, account), error::already_exists(EDUPLICATE_ACCOUNT), ); vector::push_back(&mut unique_accounts, *account);
let employee = create_signer(*account); let total = coin::balance<AptosCoin>(*account); let coins = coin::withdraw<AptosCoin>(&employee, total); simple_map::add(&mut buy_ins, *account, coins);
j = j + 1; };
let j = 0; let num_vesting_events = vector::length(&employee_group.vesting_schedule_numerator); let schedule = vector::empty();
while (j < num_vesting_events) { let numerator = vector::borrow(&employee_group.vesting_schedule_numerator, j); let event = fixed_point32::create_from_rational(*numerator, employee_group.vesting_schedule_denominator); vector::push_back(&mut schedule, event);
j = j + 1; };
let vesting_schedule = vesting::create_vesting_schedule( schedule, employee_vesting_start, employee_vesting_period_duration, );
let admin = employee_group.validator.validator_config.owner_address; let admin_signer = &create_signer(admin); let contract_address = vesting::create_vesting_contract( admin_signer, &employee_group.accounts, buy_ins, vesting_schedule, admin, employee_group.validator.validator_config.operator_address, employee_group.validator.validator_config.voter_address, employee_group.validator.commission_percentage, x"", ); let pool_address = vesting::stake_pool_address(contract_address);
if (employee_group.beneficiary_resetter != @0x0) { vesting::set_beneficiary_resetter(admin_signer, contract_address, employee_group.beneficiary_resetter); };
let validator = &employee_group.validator.validator_config; // These checks ensure that validator accounts have 0x1::Account resource. // So, validator accounts can't be stateless. assert!( account::exists_at(validator.owner_address), error::not_found(EACCOUNT_DOES_NOT_EXIST), ); assert!( account::exists_at(validator.operator_address), error::not_found(EACCOUNT_DOES_NOT_EXIST), ); assert!( account::exists_at(validator.voter_address), error::not_found(EACCOUNT_DOES_NOT_EXIST), ); if (employee_group.validator.join_during_genesis) { initialize_validator(pool_address, validator); }; });}
create_initialize_validators_with_commission
fun create_initialize_validators_with_commission(aptos_framework: &signer, use_staking_contract: bool, validators: vector<genesis::ValidatorConfigurationWithCommission>)
Implementation
fun create_initialize_validators_with_commission( aptos_framework: &signer, use_staking_contract: bool, validators: vector<ValidatorConfigurationWithCommission>,) { vector::for_each_ref(&validators, |validator| { let validator: &ValidatorConfigurationWithCommission = validator; create_initialize_validator(aptos_framework, validator, use_staking_contract); });
// Destroy the aptos framework account's ability to mint coins now that we're done with setting up the initial // validators. aptos_coin::destroy_mint_cap(aptos_framework);
stake::on_new_epoch();}
create_initialize_validators
Sets up the initial validator set for the network.
The validator “owner” accounts, and their authentication
Addresses (and keys) are encoded in the owners
Each validator signs consensus messages with the private key corresponding to the Ed25519
public key in consensus_pubkeys
.
Finally, each validator must specify the network address
(see types/src/network_address/mod.rs) for itself and its full nodes.
Network address fields are a vector per account, where each entry is a vector of addresses encoded in a single BCS byte array.
fun create_initialize_validators(aptos_framework: &signer, validators: vector<genesis::ValidatorConfiguration>)
Implementation
fun create_initialize_validators(aptos_framework: &signer, validators: vector<ValidatorConfiguration>) { let validators_with_commission = vector::empty(); vector::for_each_reverse(validators, |validator| { let validator_with_commission = ValidatorConfigurationWithCommission { validator_config: validator, commission_percentage: 0, join_during_genesis: true, }; vector::push_back(&mut validators_with_commission, validator_with_commission); });
create_initialize_validators_with_commission(aptos_framework, false, validators_with_commission);}
create_initialize_validator
fun create_initialize_validator(aptos_framework: &signer, commission_config: &genesis::ValidatorConfigurationWithCommission, use_staking_contract: bool)
Implementation
fun create_initialize_validator( aptos_framework: &signer, commission_config: &ValidatorConfigurationWithCommission, use_staking_contract: bool,) { let validator = &commission_config.validator_config;
let owner = &create_account(aptos_framework, validator.owner_address, validator.stake_amount); create_account(aptos_framework, validator.operator_address, 0); create_account(aptos_framework, validator.voter_address, 0);
// Initialize the stake pool and join the validator set. let pool_address = if (use_staking_contract) { staking_contract::create_staking_contract( owner, validator.operator_address, validator.voter_address, validator.stake_amount, commission_config.commission_percentage, x"", ); staking_contract::stake_pool_address(validator.owner_address, validator.operator_address) } else { stake::initialize_stake_owner( owner, validator.stake_amount, validator.operator_address, validator.voter_address, ); validator.owner_address };
if (commission_config.join_during_genesis) { initialize_validator(pool_address, validator); };}
initialize_validator
fun initialize_validator(pool_address: address, validator: &genesis::ValidatorConfiguration)
Implementation
fun initialize_validator(pool_address: address, validator: &ValidatorConfiguration) { let operator = &create_signer(validator.operator_address);
stake::rotate_consensus_key( operator, pool_address, validator.consensus_pubkey, validator.proof_of_possession, ); stake::update_network_and_fullnode_addresses( operator, pool_address, validator.network_addresses, validator.full_node_network_addresses, ); stake::join_validator_set_internal(operator, pool_address);}
set_genesis_end
The last step of genesis.
fun set_genesis_end(aptos_framework: &signer)
Implementation
fun set_genesis_end(aptos_framework: &signer) { chain_status::set_genesis_end(aptos_framework);}
Specification
High-level Requirements
No. | Requirement | Criticality | Implementation | Enforcement |
---|---|---|---|---|
1 | All the core resources and modules should be created during genesis and owned by the Aptos framework account. | Critical | Resources created during genesis initialization: GovernanceResponsbility, ConsensusConfig, ExecutionConfig, Version, SetVersionCapability, ValidatorSet, ValidatorPerformance, StakingConfig, StorageGasConfig, StorageGas, GasScheduleV2, AggregatorFactory, SupplyConfig, ChainId, Configuration, BlockResource, StateStorageUsage, CurrentTimeMicroseconds. If some of the resources were to be owned by a malicious account, it could lead to the compromise of the chain, as these are core resources. It should be formally verified by a post condition to ensure that all the critical resources are owned by the Aptos framework. | Formally verified via initialize. |
2 | Addresses ranging from 0x0 - 0xa should be reserved for the framework and part of aptos governance. | Critical | The function genesis::initialize calls account::create_framework_reserved_account for addresses 0x0, 0x2, 0x3, 0x4, ..., 0xa which creates an account and authentication_key for them. This should be formally verified by ensuring that at the beginning of the genesis::initialize function no Account resource exists for the reserved addresses, and at the end of the function, an Account resource exists. | Formally verified via initialize. |
3 | The Aptos coin should be initialized during genesis and only the Aptos framework account should own the mint and burn capabilities for the APT token. | Critical | Both mint and burn capabilities are wrapped inside the stake::AptosCoinCapabilities and transaction_fee::AptosCoinCapabilities resources which are stored under the aptos framework account. | Formally verified via initialize_aptos_coin. |
4 | An initial set of validators should exist before the end of genesis. | Low | To ensure that there will be a set of validators available to validate the genesis block, the length of the ValidatorSet.active_validators vector should be > 0. | Formally verified via set_genesis_end. |
5 | The end of genesis should be marked on chain. | Low | The end of genesis is marked, on chain, via the chain_status::GenesisEndMarker resource. The ownership of this resource marks the operating state of the chain. | Formally verified via set_genesis_end. |
Module-level Specification
pragma verify = true;
initialize
fun initialize(gas_schedule: vector<u8>, chain_id: u8, initial_version: u64, consensus_config: vector<u8>, execution_config: vector<u8>, epoch_interval_microsecs: u64, minimum_stake: u64, maximum_stake: u64, recurring_lockup_duration_secs: u64, allow_validator_set_change: bool, rewards_rate: u64, rewards_rate_denominator: u64, voting_power_increase_limit: u64)
pragma aborts_if_is_partial;include InitalizeRequires;// This enforces high-level requirement 2:aborts_if exists<account::Account>(@0x0);aborts_if exists<account::Account>(@0x2);aborts_if exists<account::Account>(@0x3);aborts_if exists<account::Account>(@0x4);aborts_if exists<account::Account>(@0x5);aborts_if exists<account::Account>(@0x6);aborts_if exists<account::Account>(@0x7);aborts_if exists<account::Account>(@0x8);aborts_if exists<account::Account>(@0x9);aborts_if exists<account::Account>(@0xa);ensures exists<account::Account>(@0x0);ensures exists<account::Account>(@0x2);ensures exists<account::Account>(@0x3);ensures exists<account::Account>(@0x4);ensures exists<account::Account>(@0x5);ensures exists<account::Account>(@0x6);ensures exists<account::Account>(@0x7);ensures exists<account::Account>(@0x8);ensures exists<account::Account>(@0x9);ensures exists<account::Account>(@0xa);// This enforces high-level requirement 1:ensures exists<aptos_governance::GovernanceResponsbility>(@aptos_framework);ensures exists<consensus_config::ConsensusConfig>(@aptos_framework);ensures exists<execution_config::ExecutionConfig>(@aptos_framework);ensures exists<version::Version>(@aptos_framework);ensures exists<stake::ValidatorSet>(@aptos_framework);ensures exists<stake::ValidatorPerformance>(@aptos_framework);ensures exists<storage_gas::StorageGasConfig>(@aptos_framework);ensures exists<storage_gas::StorageGas>(@aptos_framework);ensures exists<gas_schedule::GasScheduleV2>(@aptos_framework);ensures exists<aggregator_factory::AggregatorFactory>(@aptos_framework);ensures exists<coin::SupplyConfig>(@aptos_framework);ensures exists<chain_id::ChainId>(@aptos_framework);ensures exists<reconfiguration::Configuration>(@aptos_framework);ensures exists<block::BlockResource>(@aptos_framework);ensures exists<state_storage::StateStorageUsage>(@aptos_framework);ensures exists<timestamp::CurrentTimeMicroseconds>(@aptos_framework);ensures exists<account::Account>(@aptos_framework);ensures exists<version::SetVersionCapability>(@aptos_framework);ensures exists<staking_config::StakingConfig>(@aptos_framework);
initialize_aptos_coin
fun initialize_aptos_coin(aptos_framework: &signer)
// This enforces high-level requirement 3:requires !exists<stake::AptosCoinCapabilities>(@aptos_framework);ensures exists<stake::AptosCoinCapabilities>(@aptos_framework);requires exists<transaction_fee::AptosCoinCapabilities>(@aptos_framework);ensures exists<transaction_fee::AptosCoinCapabilities>(@aptos_framework);
create_initialize_validators_with_commission
fun create_initialize_validators_with_commission(aptos_framework: &signer, use_staking_contract: bool, validators: vector<genesis::ValidatorConfigurationWithCommission>)
pragma verify_duration_estimate = 120;include stake::ResourceRequirement;include stake::GetReconfigStartTimeRequirement;include CompareTimeRequires;include aptos_coin::ExistsAptosCoin;
create_initialize_validators
fun create_initialize_validators(aptos_framework: &signer, validators: vector<genesis::ValidatorConfiguration>)
pragma verify_duration_estimate = 120;include stake::ResourceRequirement;include stake::GetReconfigStartTimeRequirement;include CompareTimeRequires;include aptos_coin::ExistsAptosCoin;
create_initialize_validator
fun create_initialize_validator(aptos_framework: &signer, commission_config: &genesis::ValidatorConfigurationWithCommission, use_staking_contract: bool)
pragma verify_duration_estimate = 120;include stake::ResourceRequirement;
initialize_validator
fun initialize_validator(pool_address: address, validator: &genesis::ValidatorConfiguration)
pragma verify_duration_estimate = 120;
set_genesis_end
fun set_genesis_end(aptos_framework: &signer)
pragma delegate_invariants_to_caller;// This enforces high-level requirement 4:requires len(global<stake::ValidatorSet>(@aptos_framework).active_validators) >= 1;// This enforces high-level requirement 5:let addr = std::signer::address_of(aptos_framework);aborts_if addr != @aptos_framework;aborts_if exists<chain_status::GenesisEndMarker>(@aptos_framework);ensures global<chain_status::GenesisEndMarker>(@aptos_framework) == chain_status::GenesisEndMarker {};
schema InitalizeRequires { execution_config: vector<u8>; requires !exists<account::Account>(@aptos_framework); requires chain_status::is_operating(); requires len(execution_config) > 0; requires exists<staking_config::StakingRewardsConfig>(@aptos_framework); requires exists<coin::CoinInfo<AptosCoin>>(@aptos_framework); include CompareTimeRequires;}
schema CompareTimeRequires { let staking_rewards_config = global<staking_config::StakingRewardsConfig>(@aptos_framework); requires staking_rewards_config.last_rewards_rate_period_start_in_secs <= timestamp::spec_now_seconds();}