Module 0x1::version
Maintains the version number for the blockchain.
- Resource
Version - Resource
SetVersionCapability - Constants
- Function
initialize - Function
set_version - Function
set_for_next_epoch - Function
on_new_epoch - Function
initialize_for_test - Specification
use 0x1::chain_status;
use 0x1::config_buffer;
use 0x1::error;
use 0x1::reconfiguration;
use 0x1::signer;
use 0x1::system_addresses;
Resource Version
struct Version has drop, store, key
Fields
-
major: u64
Resource SetVersionCapability
struct SetVersionCapability has key
Fields
-
dummy_field: bool
Constants
Specified major version number must be greater than current version number.
const EINVALID_MAJOR_VERSION_NUMBER: u64 = 1;
Account is not authorized to make this change.
const ENOT_AUTHORIZED: u64 = 2;
Function initialize
Only called during genesis. Publishes the Version config.
public(friend) fun initialize(aptos_framework: &signer, initial_version: u64)
Implementation
public(friend) fun initialize(aptos_framework: &signer, initial_version: u64) {
system_addresses::assert_aptos_framework(aptos_framework);
move_to(aptos_framework, Version { major: initial_version });
// Give aptos framework account capability to call set version. This allows on chain governance to do it through
// control of the aptos framework account.
move_to(aptos_framework, SetVersionCapability {});
}
Function set_version
Deprecated by set_for_next_epoch().
WARNING: calling this while randomness is enabled will trigger a new epoch without randomness!
TODO: update all the tests that reference this function, then disable this function.
public entry fun set_version(account: &signer, major: u64)
Implementation
public entry fun set_version(account: &signer, major: u64) acquires Version {
assert!(exists<SetVersionCapability>(signer::address_of(account)), error::permission_denied(ENOT_AUTHORIZED));
chain_status::assert_genesis();
let old_major = borrow_global<Version>(@aptos_framework).major;
assert!(old_major < major, error::invalid_argument(EINVALID_MAJOR_VERSION_NUMBER));
let config = borrow_global_mut<Version>(@aptos_framework);
config.major = major;
// Need to trigger reconfiguration so validator nodes can sync on the updated version.
reconfiguration::reconfigure();
}
Function set_for_next_epoch
Used in on-chain governances to update the major version for the next epoch. Example usage:
aptos_framework::version::set_for_next_epoch(&framework_signer, new_version);aptos_framework::aptos_governance::reconfigure(&framework_signer);
public entry fun set_for_next_epoch(account: &signer, major: u64)
Implementation
public entry fun set_for_next_epoch(account: &signer, major: u64) acquires Version {
assert!(exists<SetVersionCapability>(signer::address_of(account)), error::permission_denied(ENOT_AUTHORIZED));
let old_major = borrow_global<Version>(@aptos_framework).major;
assert!(old_major < major, error::invalid_argument(EINVALID_MAJOR_VERSION_NUMBER));
config_buffer::upsert(Version {major});
}
Function on_new_epoch
Only used in reconfigurations to apply the pending Version, if there is any.
public(friend) fun on_new_epoch(framework: &signer)
Implementation
public(friend) fun on_new_epoch(framework: &signer) acquires Version {
system_addresses::assert_aptos_framework(framework);
if (config_buffer::does_exist<Version>()) {
let new_value = config_buffer::extract_v2<Version>();
if (exists<Version>(@aptos_framework)) {
*borrow_global_mut<Version>(@aptos_framework) = new_value;
} else {
move_to(framework, new_value);
}
}
}
Function initialize_for_test
Only called in tests and testnets. This allows the core resources account, which only exists in tests/testnets, to update the version.
fun initialize_for_test(core_resources: &signer)
Implementation
fun initialize_for_test(core_resources: &signer) {
system_addresses::assert_core_resource(core_resources);
move_to(core_resources, SetVersionCapability {});
}
Specification
High-level Requirements
| No. | Requirement | Criticality | Implementation | Enforcement |
|---|---|---|---|---|
| 1 | During genesis, the Version resource should be initialized with the initial version and stored along with its capability under the aptos framework account. | Medium | The initialize function ensures that the signer is the aptos framework account and stores the Version and SetVersionCapability resources in it. | Formally verified via initialize. |
| 2 | The version should be updateable after initialization, but only by the Aptos framework account and with an increasing version number. | Medium | The version number for the blockchain should be updatable whenever necessary. This functionality is provided by the set_version function which ensures that the new version is greater than the previous one. | Formally verified via set_version. |
Module-level Specification
pragma verify = true;
pragma aborts_if_is_strict;
Function initialize
public(friend) fun initialize(aptos_framework: &signer, initial_version: u64)
Abort if resource already exists in @aptos_framwork when initializing.
// This enforces high-level requirement 1:
aborts_if signer::address_of(aptos_framework) != @aptos_framework;
aborts_if exists<Version>(@aptos_framework);
aborts_if exists<SetVersionCapability>(@aptos_framework);
ensures exists<Version>(@aptos_framework);
ensures exists<SetVersionCapability>(@aptos_framework);
ensures global<Version>(@aptos_framework) == Version { major: initial_version };
ensures global<SetVersionCapability>(@aptos_framework) == SetVersionCapability {};
Function set_version
public entry fun set_version(account: &signer, major: u64)
pragma verify_duration_estimate = 120;
include staking_config::StakingRewardsConfigRequirement;
requires chain_status::is_genesis();
requires timestamp::spec_now_microseconds() >= reconfiguration::last_reconfiguration_time();
requires exists<CoinInfo<AptosCoin>>(@aptos_framework);
aborts_if !exists<SetVersionCapability>(signer::address_of(account));
aborts_if !exists<Version>(@aptos_framework);
let old_major = global<Version>(@aptos_framework).major;
// This enforces high-level requirement 2:
aborts_if !(old_major < major);
ensures global<Version>(@aptos_framework).major == major;
Function set_for_next_epoch
public entry fun set_for_next_epoch(account: &signer, major: u64)
aborts_if !exists<SetVersionCapability>(signer::address_of(account));
aborts_if !exists<Version>(@aptos_framework);
aborts_if global<Version>(@aptos_framework).major >= major;
aborts_if !exists<config_buffer::PendingConfigs>(@aptos_framework);
Function on_new_epoch
public(friend) fun on_new_epoch(framework: &signer)
requires @aptos_framework == std::signer::address_of(framework);
include config_buffer::OnNewEpochRequirement<Version>;
aborts_if false;
Function initialize_for_test
fun initialize_for_test(core_resources: &signer)
This module turns on aborts_if_is_strict, so need to add spec for test function initialize_for_test.
pragma verify = false;