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 store
Fields
-
value: u128
-
limit: u128
OptionalAggregator
Contains either an aggregator or a normal integer, both overflowing on limit.
struct OptionalAggregator has store
Fields
Functions
new_integer
Creates a new integer which overflows on exceeding a limit
.
fun new_integer(limit: u128): optional_aggregator::Integer
Implementation
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): u128
Implementation
fun limit(integer: &Integer): u128 { integer.limit}
read_integer
Returns a value stored in this integer.
fun read_integer(integer: &optional_aggregator::Integer): u128
Implementation
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::OptionalAggregator
Implementation
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): u128
Implementation
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): u128
Implementation
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): u128
Implementation
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): bool
Implementation
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::Integer
aborts_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::OptionalAggregator
aborts_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): u128
The 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): u128
The 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): u128
ensures !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));