optional_aggregator - [mainnet]
This module provides an interface to aggregate integers either via aggregator (parallelizable) or via normal integers.
use 0x1::aggregator;use 0x1::aggregator_factory;use 0x1::error;use 0x1::option;Constants
const MAX_U128: u128 = 340282366920938463463374607431768211455;The value of aggregator underflows (goes below zero). Raised by native code.
const EAGGREGATOR_OVERFLOW: u64 = 1;Aggregator feature is not supported. Raised by native code.
const EAGGREGATOR_UNDERFLOW: u64 = 2;OptionalAggregator (Agg V1) switch not supported any more.
const ESWITCH_DEPRECATED: u64 = 3;Structs
Integer
Wrapper around integer with a custom overflow limit. Supports add, subtract and read just like Aggregator.
struct Integer has storeFields
-
value: u128 -
limit: u128
OptionalAggregator
Contains either an aggregator or a normal integer, both overflowing on limit.
struct OptionalAggregator has storeFields
Functions
new_integer
Creates a new integer which overflows on exceeding a limit.
fun new_integer(limit: u128): optional_aggregator::IntegerImplementation
fun new_integer(limit: u128): Integer { Integer { value: 0, limit, }}add_integer
Adds value to integer. Aborts on overflowing the limit.
fun add_integer(integer: &mut optional_aggregator::Integer, value: u128)Implementation
fun add_integer(integer: &mut Integer, value: u128) { assert!( value <= (integer.limit - integer.value), error::out_of_range(EAGGREGATOR_OVERFLOW) ); integer.value = integer.value + value;}sub_integer
Subtracts value from integer. Aborts on going below zero.
fun sub_integer(integer: &mut optional_aggregator::Integer, value: u128)Implementation
fun sub_integer(integer: &mut Integer, value: u128) { assert!(value <= integer.value, error::out_of_range(EAGGREGATOR_UNDERFLOW)); integer.value = integer.value - value;}limit
Returns an overflow limit of integer.
fun limit(integer: &optional_aggregator::Integer): u128Implementation
fun limit(integer: &Integer): u128 { integer.limit}read_integer
Returns a value stored in this integer.
fun read_integer(integer: &optional_aggregator::Integer): u128Implementation
fun read_integer(integer: &Integer): u128 { integer.value}destroy_integer
Destroys an integer.
fun destroy_integer(integer: optional_aggregator::Integer)Implementation
fun destroy_integer(integer: Integer) { let Integer { value: _, limit: _ } = integer;}new
Creates a new optional aggregator.
public(friend) fun new(parallelizable: bool): optional_aggregator::OptionalAggregatorImplementation
public(friend) fun new(parallelizable: bool): OptionalAggregator { if (parallelizable) { OptionalAggregator { aggregator: option::some(aggregator_factory::create_aggregator_internal()), integer: option::none(), } } else { OptionalAggregator { aggregator: option::none(), integer: option::some(new_integer(MAX_U128)), } }}switch
Switches between parallelizable and non-parallelizable implementations.
public fun switch(_optional_aggregator: &mut optional_aggregator::OptionalAggregator)Implementation
public fun switch(_optional_aggregator: &mut OptionalAggregator) { abort error::invalid_state(ESWITCH_DEPRECATED)}destroy
Destroys optional aggregator.
public fun destroy(optional_aggregator: optional_aggregator::OptionalAggregator)Implementation
public fun destroy(optional_aggregator: OptionalAggregator) { if (is_parallelizable(&optional_aggregator)) { destroy_optional_aggregator(optional_aggregator); } else { destroy_optional_integer(optional_aggregator); }}destroy_optional_aggregator
Destroys parallelizable optional aggregator and returns its limit.
fun destroy_optional_aggregator(optional_aggregator: optional_aggregator::OptionalAggregator): u128Implementation
fun destroy_optional_aggregator(optional_aggregator: OptionalAggregator): u128 { let OptionalAggregator { aggregator, integer } = optional_aggregator; let limit = aggregator::limit(option::borrow(&aggregator)); aggregator::destroy(option::destroy_some(aggregator)); option::destroy_none(integer); limit}destroy_optional_integer
Destroys non-parallelizable optional aggregator and returns its limit.
fun destroy_optional_integer(optional_aggregator: optional_aggregator::OptionalAggregator): u128Implementation
fun destroy_optional_integer(optional_aggregator: OptionalAggregator): u128 { let OptionalAggregator { aggregator, integer } = optional_aggregator; let limit = limit(option::borrow(&integer)); destroy_integer(option::destroy_some(integer)); option::destroy_none(aggregator); limit}add
Adds value to optional aggregator, aborting on exceeding the limit.
public fun add(optional_aggregator: &mut optional_aggregator::OptionalAggregator, value: u128)Implementation
public fun add(optional_aggregator: &mut OptionalAggregator, value: u128) { if (option::is_some(&optional_aggregator.aggregator)) { let aggregator = option::borrow_mut(&mut optional_aggregator.aggregator); aggregator::add(aggregator, value); } else { let integer = option::borrow_mut(&mut optional_aggregator.integer); add_integer(integer, value); }}sub
Subtracts value from optional aggregator, aborting on going below zero.
public fun sub(optional_aggregator: &mut optional_aggregator::OptionalAggregator, value: u128)Implementation
public fun sub(optional_aggregator: &mut OptionalAggregator, value: u128) { if (option::is_some(&optional_aggregator.aggregator)) { let aggregator = option::borrow_mut(&mut optional_aggregator.aggregator); aggregator::sub(aggregator, value); } else { let integer = option::borrow_mut(&mut optional_aggregator.integer); sub_integer(integer, value); }}read
Returns the value stored in optional aggregator.
public fun read(optional_aggregator: &optional_aggregator::OptionalAggregator): u128Implementation
public fun read(optional_aggregator: &OptionalAggregator): u128 { if (option::is_some(&optional_aggregator.aggregator)) { let aggregator = option::borrow(&optional_aggregator.aggregator); aggregator::read(aggregator) } else { let integer = option::borrow(&optional_aggregator.integer); read_integer(integer) }}is_parallelizable
Returns true if optional aggregator uses parallelizable implementation.
public fun is_parallelizable(optional_aggregator: &optional_aggregator::OptionalAggregator): boolImplementation
public fun is_parallelizable(optional_aggregator: &OptionalAggregator): bool { option::is_some(&optional_aggregator.aggregator)}Specification
High-level Requirements
| No. | Requirement | Criticality | Implementation | Enforcement |
|---|---|---|---|---|
| 1 | When creating a new integer instance, it guarantees that the limit assigned is a value passed into the function as an argument, and the value field becomes zero. | High | The new_integer function sets the limit field to the argument passed in, and the value field is set to zero. | Formally verified via new_integer. |
| 2 | For a given integer instance it should always be possible to: (1) return the limit value of the integer resource, (2) return the current value stored in that particular instance, and (3) destroy the integer instance. | Low | The following functions should not abort if the Integer instance exists: limit(), read_integer(), destroy_integer(). | Formally verified via: read_integer, limit, and destroy_integer. |
| 3 | Every successful switch must end with the aggregator type changed from non-parallelizable to parallelizable or vice versa. | High | The switch function run, if successful, should always change the aggregator type. | Formally verified via switch_and_zero_out. |
Module-level Specification
pragma verify = true;pragma aborts_if_is_strict;OptionalAggregator
struct OptionalAggregator has store-
aggregator: option::Option<aggregator::Aggregator> -
integer: option::Option<optional_aggregator::Integer>
invariant option::is_some(aggregator) <==> option::is_none(integer);invariant option::is_some(integer) <==> option::is_none(aggregator);invariant option::is_some(integer) ==> option::borrow(integer).value <= option::borrow(integer).limit;invariant option::is_some(aggregator) ==> aggregator::spec_aggregator_get_val(option::borrow(aggregator)) <= aggregator::spec_get_limit(option::borrow(aggregator));new_integer
fun new_integer(limit: u128): optional_aggregator::Integeraborts_if false;ensures result.limit == limit;// This enforces high-level requirement 1:ensures result.value == 0;add_integer
fun add_integer(integer: &mut optional_aggregator::Integer, value: u128)Check for overflow.
aborts_if value > (integer.limit - integer.value);aborts_if integer.value + value > MAX_U128;ensures integer.value <= integer.limit;ensures integer.value == old(integer.value) + value;sub_integer
fun sub_integer(integer: &mut optional_aggregator::Integer, value: u128)aborts_if value > integer.value;ensures integer.value == old(integer.value) - value;limit
fun limit(integer: &optional_aggregator::Integer): u128// This enforces high-level requirement 2:aborts_if false;read_integer
fun read_integer(integer: &optional_aggregator::Integer): u128// This enforces high-level requirement 2:aborts_if false;destroy_integer
fun destroy_integer(integer: optional_aggregator::Integer)// This enforces high-level requirement 2:aborts_if false;new
public(friend) fun new(parallelizable: bool): optional_aggregator::OptionalAggregatoraborts_if parallelizable && !exists<aggregator_factory::AggregatorFactory>(@aptos_framework);ensures parallelizable ==> is_parallelizable(result);ensures !parallelizable ==> !is_parallelizable(result);ensures optional_aggregator_value(result) == 0;ensures optional_aggregator_value(result) <= optional_aggregator_limit(result);switch
public fun switch(_optional_aggregator: &mut optional_aggregator::OptionalAggregator)aborts_if true;destroy
public fun destroy(optional_aggregator: optional_aggregator::OptionalAggregator)aborts_if is_parallelizable(optional_aggregator) && len(optional_aggregator.integer.vec) != 0;aborts_if !is_parallelizable(optional_aggregator) && len(optional_aggregator.integer.vec) == 0;destroy_optional_aggregator
fun destroy_optional_aggregator(optional_aggregator: optional_aggregator::OptionalAggregator): u128The aggregator exists and the integer does not exist when destroy the aggregator.
aborts_if len(optional_aggregator.aggregator.vec) == 0;aborts_if len(optional_aggregator.integer.vec) != 0;ensures result == aggregator::spec_get_limit(option::borrow(optional_aggregator.aggregator));destroy_optional_integer
fun destroy_optional_integer(optional_aggregator: optional_aggregator::OptionalAggregator): u128The integer exists and the aggregator does not exist when destroy the integer.
aborts_if len(optional_aggregator.integer.vec) == 0;aborts_if len(optional_aggregator.aggregator.vec) != 0;ensures result == option::borrow(optional_aggregator.integer).limit;fun optional_aggregator_value(optional_aggregator: OptionalAggregator): u128 { if (is_parallelizable(optional_aggregator)) { aggregator::spec_aggregator_get_val(option::borrow(optional_aggregator.aggregator)) } else { option::borrow(optional_aggregator.integer).value }}fun optional_aggregator_limit(optional_aggregator: OptionalAggregator): u128 { if (is_parallelizable(optional_aggregator)) { aggregator::spec_get_limit(option::borrow(optional_aggregator.aggregator)) } else { option::borrow(optional_aggregator.integer).limit }}add
public fun add(optional_aggregator: &mut optional_aggregator::OptionalAggregator, value: u128)include AddAbortsIf;ensures ((optional_aggregator_value(optional_aggregator) == optional_aggregator_value(old(optional_aggregator)) + value));schema AddAbortsIf { optional_aggregator: OptionalAggregator; value: u128; aborts_if is_parallelizable(optional_aggregator) && (aggregator::spec_aggregator_get_val(option::borrow(optional_aggregator.aggregator)) + value > aggregator::spec_get_limit(option::borrow(optional_aggregator.aggregator))); aborts_if is_parallelizable(optional_aggregator) && (aggregator::spec_aggregator_get_val(option::borrow(optional_aggregator.aggregator)) + value > MAX_U128); aborts_if !is_parallelizable(optional_aggregator) && (option::borrow(optional_aggregator.integer).value + value > MAX_U128); aborts_if !is_parallelizable(optional_aggregator) && (value > (option::borrow(optional_aggregator.integer).limit - option::borrow(optional_aggregator.integer).value));}sub
public fun sub(optional_aggregator: &mut optional_aggregator::OptionalAggregator, value: u128)include SubAbortsIf;ensures ((optional_aggregator_value(optional_aggregator) == optional_aggregator_value(old(optional_aggregator)) - value));schema SubAbortsIf { optional_aggregator: OptionalAggregator; value: u128; aborts_if is_parallelizable(optional_aggregator) && (aggregator::spec_aggregator_get_val(option::borrow(optional_aggregator.aggregator)) < value); aborts_if !is_parallelizable(optional_aggregator) && (option::borrow(optional_aggregator.integer).value < value);}read
public fun read(optional_aggregator: &optional_aggregator::OptionalAggregator): u128ensures !is_parallelizable(optional_aggregator) ==> result == option::borrow(optional_aggregator.integer).value;ensures is_parallelizable(optional_aggregator) ==> result == aggregator::spec_read(option::borrow(optional_aggregator.aggregator));