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::config_buffer

This wrapper helps store an on-chain config for the next epoch.

Once reconfigure with DKG is introduced, every on-chain config C should do the following.

  • Support async update when DKG is enabled. This is typically done by 3 steps below.
  • Implement C::set_for_next_epoch() using upsert() function in this module.
  • Implement C::on_new_epoch() using extract() function in this module.
  • Update 0x1::reconfiguration_with_dkg::finish() to call C::on_new_epoch().
  • Support sychronous update when DKG is disabled. This is typically done by implementing C::set() to update the config resource directly.

NOTE: on-chain config 0x1::state::ValidatorSet implemented its own buffer.

use 0x1::any;
use 0x1::error;
use 0x1::option;
use 0x1::simple_map;
use 0x1::string;
use 0x1::system_addresses;
use 0x1::type_info;

Resource PendingConfigs

struct PendingConfigs has key
Fields
configs: simple_map::SimpleMap<string::String, any::Any>

Constants

Function is deprecated.

const EDEPRECATED: u64 = 2;

Config buffer operations failed with permission denied.

const ESTD_SIGNER_NEEDED: u64 = 1;

Function initialize

public fun initialize(aptos_framework: &signer)
Implementation
public fun initialize(aptos_framework: &signer) {
    system_addresses::assert_aptos_framework(aptos_framework);
    if (!exists<PendingConfigs>(@aptos_framework)) {
        move_to(aptos_framework, PendingConfigs {
            configs: simple_map::new(),
        })
    }
}

Function does_exist

Check whether there is a pending config payload for T.

public fun does_exist<T: store>(): bool
Implementation
public fun does_exist<T: store>(): bool acquires PendingConfigs {
    if (exists<PendingConfigs>(@aptos_framework)) {
        let config = borrow_global<PendingConfigs>(@aptos_framework);
        config.configs.contains_key(&type_info::type_name<T>())
    } else {
        false
    }
}

Function upsert

Upsert an on-chain config to the buffer for the next epoch.

Typically used in X::set_for_next_epoch() where X is an on-chain config.

public(friend) fun upsert<T: drop, store>(config: T)
Implementation
public(friend) fun upsert<T: drop + store>(config: T) acquires PendingConfigs {
    let configs = borrow_global_mut<PendingConfigs>(@aptos_framework);
    let key = type_info::type_name<T>();
    let value = any::pack(config);
    configs.configs.upsert(key, value);
}

Function extract

Use extract_v2 instead.

#[deprecated]
public fun extract<T: store>(): T
Implementation
public fun extract<T: store>(): T {
    abort(error::unavailable(EDEPRECATED))
}

Function extract_v2

Take the buffered config T out (buffer cleared). Abort if the buffer is empty. Should only be used at the end of a reconfiguration.

Typically used in X::on_new_epoch() where X is an on-chaon config.

public(friend) fun extract_v2<T: store>(): T
Implementation
public(friend) fun extract_v2<T: store>(): T acquires PendingConfigs {
    let configs = borrow_global_mut<PendingConfigs>(@aptos_framework);
    let key = type_info::type_name<T>();
    let (_, value_packed) = configs.configs.remove(&key);
    value_packed.unpack()
}

Specification

pragma verify = true;

Function does_exist

public fun does_exist<T: store>(): bool
aborts_if false;
let type_name = type_info::type_name<T>();
ensures result == spec_fun_does_exist<T>(type_name);

fun spec_fun_does_exist<T: store>(type_name: String): bool {
   if (exists<PendingConfigs>(@aptos_framework)) {
       let config = global<PendingConfigs>(@aptos_framework);
       simple_map::spec_contains_key(config.configs, type_name)
   } else {
       false
   }
}

Function upsert

public(friend) fun upsert<T: drop, store>(config: T)
aborts_if !exists<PendingConfigs>(@aptos_framework);

Function extract_v2

public(friend) fun extract_v2<T: store>(): T
aborts_if !exists<PendingConfigs>(@aptos_framework);
include ExtractAbortsIf<T>;

schema ExtractAbortsIf<T> {
    let configs = global<PendingConfigs>(@aptos_framework);
    let key = type_info::type_name<T>();
    aborts_if !simple_map::spec_contains_key(configs.configs, key);
    include any::UnpackAbortsIf<T> {
        self: simple_map::spec_get(configs.configs, key)
    };
}

schema SetForNextEpochAbortsIf {
    account: &signer;
    config: vector<u8>;
    let account_addr = std::signer::address_of(account);
    aborts_if account_addr != @aptos_framework;
    aborts_if len(config) == 0;
    aborts_if !exists<PendingConfigs>(@aptos_framework);
}

schema OnNewEpochAbortsIf<T> {
    let type_name = type_info::type_name<T>();
    let configs = global<PendingConfigs>(@aptos_framework);
    include spec_fun_does_exist<T>(type_name) ==> any::UnpackAbortsIf<T> {
        self: simple_map::spec_get(configs.configs, type_name)
    };
}

schema OnNewEpochRequirement<T> {
    let type_name = type_info::type_name<T>();
    let configs = global<PendingConfigs>(@aptos_framework);
    include spec_fun_does_exist<T>(type_name) ==> any::UnpackRequirement<T> {
        self: simple_map::spec_get(configs.configs, type_name)
    };
}