Skip to content

gas_schedule - [mainnet]

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;

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;

Structs

GasEntry

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

Resources

GasSchedule

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

GasScheduleV2

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

Functions

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!(!vector::is_empty(&gas_schedule_blob), 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);
}

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!(!vector::is_empty(&gas_schedule_blob), 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();
}

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!(!vector::is_empty(&gas_schedule_blob), 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);
}

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!(!vector::is_empty(&new_gas_schedule_blob), 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);
}

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);
}
}
}

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();
}

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;

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);

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;

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;

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);

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;

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);

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);