Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Module 0x1::gas_schedule

This module defines structs and methods to initialize the gas schedule, which dictates how much it costs to execute Move on the network.

use 0x1::aptos_hash;
use 0x1::bcs;
use 0x1::chain_status;
use 0x1::config_buffer;
use 0x1::error;
use 0x1::reconfiguration;
use 0x1::storage_gas;
use 0x1::string;
use 0x1::system_addresses;
use 0x1::util;
use 0x1::vector;

Struct GasEntry

struct GasEntry has copy, drop, store
Fields
key: string::String
val: u64

Resource GasSchedule

struct GasSchedule has copy, drop, key
Fields
entries: vector<gas_schedule::GasEntry>

Resource GasScheduleV2

struct GasScheduleV2 has copy, drop, store, key
Fields
feature_version: u64
entries: vector<gas_schedule::GasEntry>

Constants

const EINVALID_GAS_FEATURE_VERSION: u64 = 2;

The provided gas schedule bytes are empty or invalid

const EINVALID_GAS_SCHEDULE: u64 = 1;

const EINVALID_GAS_SCHEDULE_HASH: u64 = 3;

Function initialize

Only called during genesis.

public(friend) fun initialize(aptos_framework: &signer, gas_schedule_blob: vector<u8>)
Implementation
public(friend) fun initialize(aptos_framework: &signer, gas_schedule_blob: vector<u8>) {
    system_addresses::assert_aptos_framework(aptos_framework);
    assert!(!gas_schedule_blob.is_empty(), error::invalid_argument(EINVALID_GAS_SCHEDULE));

    // TODO(Gas): check if gas schedule is consistent
    let gas_schedule: GasScheduleV2 = from_bytes(gas_schedule_blob);
    move_to<GasScheduleV2>(aptos_framework, gas_schedule);
}

Function set_gas_schedule

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 fun set_gas_schedule(aptos_framework: &signer, gas_schedule_blob: vector<u8>)
Implementation
public fun set_gas_schedule(aptos_framework: &signer, gas_schedule_blob: vector<u8>) acquires GasSchedule, GasScheduleV2 {
    system_addresses::assert_aptos_framework(aptos_framework);
    assert!(!gas_schedule_blob.is_empty(), error::invalid_argument(EINVALID_GAS_SCHEDULE));
    chain_status::assert_genesis();

    if (exists<GasScheduleV2>(@aptos_framework)) {
        let gas_schedule = borrow_global_mut<GasScheduleV2>(@aptos_framework);
        let new_gas_schedule: GasScheduleV2 = from_bytes(gas_schedule_blob);
        assert!(new_gas_schedule.feature_version >= gas_schedule.feature_version,
            error::invalid_argument(EINVALID_GAS_FEATURE_VERSION));
        // TODO(Gas): check if gas schedule is consistent
        *gas_schedule = new_gas_schedule;
    }
    else {
        if (exists<GasSchedule>(@aptos_framework)) {
            _ = move_from<GasSchedule>(@aptos_framework);
        };
        let new_gas_schedule: GasScheduleV2 = from_bytes(gas_schedule_blob);
        // TODO(Gas): check if gas schedule is consistent
        move_to<GasScheduleV2>(aptos_framework, new_gas_schedule);
    };

    // Need to trigger reconfiguration so validator nodes can sync on the updated gas schedule.
    reconfiguration::reconfigure();
}

Function set_for_next_epoch

Set the gas schedule for the next epoch, typically called by on-chain governance. Abort if the version of the given schedule is lower than the current version.

Example usage:

aptos_framework::gas_schedule::set_for_next_epoch(&framework_signer, some_gas_schedule_blob);
aptos_framework::aptos_governance::reconfigure(&framework_signer);
public fun set_for_next_epoch(aptos_framework: &signer, gas_schedule_blob: vector<u8>)
Implementation
public fun set_for_next_epoch(aptos_framework: &signer, gas_schedule_blob: vector<u8>) acquires GasScheduleV2 {
    system_addresses::assert_aptos_framework(aptos_framework);
    assert!(!gas_schedule_blob.is_empty(), error::invalid_argument(EINVALID_GAS_SCHEDULE));
    let new_gas_schedule: GasScheduleV2 = from_bytes(gas_schedule_blob);
    if (exists<GasScheduleV2>(@aptos_framework)) {
        let cur_gas_schedule = borrow_global<GasScheduleV2>(@aptos_framework);
        assert!(
            new_gas_schedule.feature_version >= cur_gas_schedule.feature_version,
            error::invalid_argument(EINVALID_GAS_FEATURE_VERSION)
        );
    };
    config_buffer::upsert(new_gas_schedule);
}

Function set_for_next_epoch_check_hash

Set the gas schedule for the next epoch, typically called by on-chain governance. Abort if the version of the given schedule is lower than the current version. Require a hash of the old gas schedule to be provided and will abort if the hashes mismatch.

public fun set_for_next_epoch_check_hash(aptos_framework: &signer, old_gas_schedule_hash: vector<u8>, new_gas_schedule_blob: vector<u8>)
Implementation
public fun set_for_next_epoch_check_hash(
    aptos_framework: &signer,
    old_gas_schedule_hash: vector<u8>,
    new_gas_schedule_blob: vector<u8>
) acquires GasScheduleV2 {
    system_addresses::assert_aptos_framework(aptos_framework);
    assert!(!new_gas_schedule_blob.is_empty(), error::invalid_argument(EINVALID_GAS_SCHEDULE));

    let new_gas_schedule: GasScheduleV2 = from_bytes(new_gas_schedule_blob);
    if (exists<GasScheduleV2>(@aptos_framework)) {
        let cur_gas_schedule = borrow_global<GasScheduleV2>(@aptos_framework);
        assert!(
            new_gas_schedule.feature_version >= cur_gas_schedule.feature_version,
            error::invalid_argument(EINVALID_GAS_FEATURE_VERSION)
        );
        let cur_gas_schedule_bytes = bcs::to_bytes(cur_gas_schedule);
        let cur_gas_schedule_hash = aptos_hash::sha3_512(cur_gas_schedule_bytes);
        assert!(
            cur_gas_schedule_hash == old_gas_schedule_hash,
            error::invalid_argument(EINVALID_GAS_SCHEDULE_HASH)
        );
    };

    config_buffer::upsert(new_gas_schedule);
}

Function on_new_epoch

Only used in reconfigurations to apply the pending GasScheduleV2, if there is any.

public(friend) fun on_new_epoch(framework: &signer)
Implementation
public(friend) fun on_new_epoch(framework: &signer) acquires GasScheduleV2 {
    system_addresses::assert_aptos_framework(framework);
    if (config_buffer::does_exist<GasScheduleV2>()) {
        let new_gas_schedule = config_buffer::extract_v2<GasScheduleV2>();
        if (exists<GasScheduleV2>(@aptos_framework)) {
            *borrow_global_mut<GasScheduleV2>(@aptos_framework) = new_gas_schedule;
        } else {
            move_to(framework, new_gas_schedule);
        }
    }
}

Function set_storage_gas_config

public fun set_storage_gas_config(aptos_framework: &signer, config: storage_gas::StorageGasConfig)
Implementation
public fun set_storage_gas_config(aptos_framework: &signer, config: StorageGasConfig) {
    storage_gas::set_config(aptos_framework, config);
    // Need to trigger reconfiguration so the VM is guaranteed to load the new gas fee starting from the next
    // transaction.
    reconfiguration::reconfigure();
}

Function set_storage_gas_config_for_next_epoch

public fun set_storage_gas_config_for_next_epoch(aptos_framework: &signer, config: storage_gas::StorageGasConfig)
Implementation
public fun set_storage_gas_config_for_next_epoch(aptos_framework: &signer, config: StorageGasConfig) {
    storage_gas::set_config(aptos_framework, config);
}

Specification

High-level Requirements

No.RequirementCriticalityImplementationEnforcement
1 During genesis, the Aptos framework account should be assigned the gas schedule resource. Medium The gas_schedule::initialize function calls the assert_aptos_framework function to ensure that the signer is the aptos_framework and then assigns the GasScheduleV2 resource to it. Formally verified via initialize.
2 Only the Aptos framework account should be allowed to update the gas schedule resource. Critical The gas_schedule::set_gas_schedule function calls the assert_aptos_framework function to ensure that the signer is the aptos framework account. Formally verified via set_gas_schedule.
3 Only valid gas schedule should be allowed for initialization and update. Medium The initialize and set_gas_schedule functions ensures that the gas_schedule_blob is not empty. Formally verified via initialize and set_gas_schedule.
4 Only a gas schedule with the feature version greater or equal than the current feature version is allowed to be provided when performing an update operation. Medium The set_gas_schedule function validates the feature_version of the new_gas_schedule by ensuring that it is greater or equal than the current gas_schedule.feature_version. Formally verified via set_gas_schedule.

Module-level Specification

pragma verify = true;
pragma aborts_if_is_strict;

Function initialize

public(friend) fun initialize(aptos_framework: &signer, gas_schedule_blob: vector<u8>)
let addr = signer::address_of(aptos_framework);
// This enforces high-level requirement 1:
include system_addresses::AbortsIfNotAptosFramework{ account: aptos_framework };
// This enforces high-level requirement 3:
aborts_if len(gas_schedule_blob) == 0;
aborts_if exists<GasScheduleV2>(addr);
ensures exists<GasScheduleV2>(addr);

Function set_gas_schedule

public fun set_gas_schedule(aptos_framework: &signer, gas_schedule_blob: vector<u8>)
pragma verify_duration_estimate = 600;
requires exists<CoinInfo<AptosCoin>>(@aptos_framework);
requires chain_status::is_genesis();
include staking_config::StakingRewardsConfigRequirement;
// This enforces high-level requirement 2:
include system_addresses::AbortsIfNotAptosFramework{ account: aptos_framework };
// This enforces high-level requirement 3:
aborts_if len(gas_schedule_blob) == 0;
let new_gas_schedule = util::spec_from_bytes<GasScheduleV2>(gas_schedule_blob);
let gas_schedule = global<GasScheduleV2>(@aptos_framework);
// This enforces high-level requirement 4:
aborts_if exists<GasScheduleV2>(@aptos_framework) && new_gas_schedule.feature_version < gas_schedule.feature_version;
ensures exists<GasScheduleV2>(signer::address_of(aptos_framework));
ensures global<GasScheduleV2>(@aptos_framework) == new_gas_schedule;

Function set_for_next_epoch

public fun set_for_next_epoch(aptos_framework: &signer, gas_schedule_blob: vector<u8>)
include system_addresses::AbortsIfNotAptosFramework{ account: aptos_framework };
include config_buffer::SetForNextEpochAbortsIf {
    account: aptos_framework,
    config: gas_schedule_blob
};
let new_gas_schedule = util::spec_from_bytes<GasScheduleV2>(gas_schedule_blob);
let cur_gas_schedule = global<GasScheduleV2>(@aptos_framework);
aborts_if exists<GasScheduleV2>(@aptos_framework) && new_gas_schedule.feature_version < cur_gas_schedule.feature_version;

Function set_for_next_epoch_check_hash

public fun set_for_next_epoch_check_hash(aptos_framework: &signer, old_gas_schedule_hash: vector<u8>, new_gas_schedule_blob: vector<u8>)
include system_addresses::AbortsIfNotAptosFramework{ account: aptos_framework };
include config_buffer::SetForNextEpochAbortsIf {
    account: aptos_framework,
    config: new_gas_schedule_blob
};
let new_gas_schedule = util::spec_from_bytes<GasScheduleV2>(new_gas_schedule_blob);
let cur_gas_schedule = global<GasScheduleV2>(@aptos_framework);
aborts_if exists<GasScheduleV2>(@aptos_framework) && new_gas_schedule.feature_version < cur_gas_schedule.feature_version;
aborts_if exists<GasScheduleV2>(@aptos_framework) && (!features::spec_sha_512_and_ripemd_160_enabled() || aptos_hash::spec_sha3_512_internal(bcs::serialize(cur_gas_schedule)) != old_gas_schedule_hash);

Function on_new_epoch

public(friend) fun on_new_epoch(framework: &signer)
requires @aptos_framework == std::signer::address_of(framework);
include config_buffer::OnNewEpochRequirement<GasScheduleV2>;
aborts_if false;

Function set_storage_gas_config

public fun set_storage_gas_config(aptos_framework: &signer, config: storage_gas::StorageGasConfig)
pragma verify_duration_estimate = 600;
requires exists<CoinInfo<AptosCoin>>(@aptos_framework);
include system_addresses::AbortsIfNotAptosFramework{ account: aptos_framework };
include staking_config::StakingRewardsConfigRequirement;
aborts_if !exists<StorageGasConfig>(@aptos_framework);
ensures global<StorageGasConfig>(@aptos_framework) == config;
include system_addresses::AbortsIfNotAptosFramework{ account: aptos_framework };
aborts_if !exists<storage_gas::StorageGasConfig>(@aptos_framework);

Function set_storage_gas_config_for_next_epoch

public fun set_storage_gas_config_for_next_epoch(aptos_framework: &signer, config: storage_gas::StorageGasConfig)
include system_addresses::AbortsIfNotAptosFramework{ account: aptos_framework };
aborts_if !exists<storage_gas::StorageGasConfig>(@aptos_framework);