Skip to content

aggregator - [mainnet]

This module provides an interface for aggregators. Aggregators are similar to unsigned integers and support addition and subtraction (aborting on underflow or on overflowing a custom upper limit). The difference from integers is that aggregators allow to perform both additions and subtractions in parallel across multiple transactions, enabling parallel execution. For example, if the first transaction is doing add(X, 1) for aggregator resource X, and the second is doing sub(X,3), they can be executed in parallel avoiding a read-modify-write dependency. However, reading the aggregator value (i.e. calling read(X)) is an expensive operation and should be avoided as much as possible because it reduces the parallelism. Moreover, aggregators can only be created by Aptos Framework (0x1) at the moment.

Constants

The value of aggregator overflows. Raised by native code.

const EAGGREGATOR_OVERFLOW: u64 = 1;

The value of aggregator underflows (goes below zero). Raised by native code.

const EAGGREGATOR_UNDERFLOW: u64 = 2;

Aggregator feature is not supported. Raised by native code.

const ENOT_SUPPORTED: u64 = 3;

Structs

Aggregator

Represents an integer which supports parallel additions and subtractions across multiple transactions. See the module description for more details.

struct Aggregator has store
Fields
handle: address
key: address
limit: u128

Functions

limit

Returns limit exceeding which aggregator overflows.

public fun limit(aggregator: &aggregator::Aggregator): u128
Implementation
public fun limit(aggregator: &Aggregator): u128 {
aggregator.limit
}

add

Adds value to aggregator. Aborts on overflowing the limit.

public fun add(aggregator: &mut aggregator::Aggregator, value: u128)
Implementation
public native fun add(aggregator: &mut Aggregator, value: u128);

sub

Subtracts value from aggregator. Aborts on going below zero.

public fun sub(aggregator: &mut aggregator::Aggregator, value: u128)
Implementation
public native fun sub(aggregator: &mut Aggregator, value: u128);

read

Returns a value stored in this aggregator.

public fun read(aggregator: &aggregator::Aggregator): u128
Implementation
public native fun read(aggregator: &Aggregator): u128;

destroy

Destroys an aggregator and removes it from its AggregatorFactory.

public fun destroy(aggregator: aggregator::Aggregator)
Implementation
public native fun destroy(aggregator: Aggregator);

Specification

Aggregator

struct Aggregator has store
handle: address
key: address
limit: u128

High-level Requirements

No.RequirementCriticalityImplementationEnforcement
1 For a given aggregator, it should always be possible to: Return the limit value of the aggregator. Return the current value stored in the aggregator. Destroy an aggregator, removing it from its AggregatorFactory. Low The following functions should not abort if EventHandle exists: limit(), read(), destroy(). Formally verified via read, destroy, and limit.
2 If the value during addition exceeds the limit, an overflow occurs. High The native add() function checks the value of the addition to ensure it does not pass the defined limit and results in aggregator overflow. Formally verified via add.
3 Operations over aggregators should be correct. High The implementation of the add, sub, read and destroy functions is correct. The native implementation of the add, sub, read and destroy functions have been manually audited.

Module-level Specification

pragma intrinsic;

limit

public fun limit(aggregator: &aggregator::Aggregator): u128
pragma intrinsic;
// This enforces high-level requirement 1:
aborts_if [abstract] false;
native fun spec_read(aggregator: Aggregator): u128;
native fun spec_get_limit(a: Aggregator): u128;
native fun spec_get_handle(a: Aggregator): u128;
native fun spec_get_key(a: Aggregator): u128;
native fun spec_aggregator_set_val(a: Aggregator, v: u128): Aggregator;
native fun spec_aggregator_get_val(a: Aggregator): u128;

add

public fun add(aggregator: &mut aggregator::Aggregator, value: u128)
pragma opaque;
aborts_if spec_aggregator_get_val(aggregator) + value > spec_get_limit(aggregator);
// This enforces high-level requirement 2:
aborts_if spec_aggregator_get_val(aggregator) + value > MAX_U128;
ensures spec_get_limit(aggregator) == spec_get_limit(old(aggregator));
ensures aggregator == spec_aggregator_set_val(old(aggregator),
spec_aggregator_get_val(old(aggregator)) + value);

sub

public fun sub(aggregator: &mut aggregator::Aggregator, value: u128)
pragma opaque;
aborts_if spec_aggregator_get_val(aggregator) < value;
ensures spec_get_limit(aggregator) == spec_get_limit(old(aggregator));
ensures aggregator == spec_aggregator_set_val(old(aggregator),
spec_aggregator_get_val(old(aggregator)) - value);

read

public fun read(aggregator: &aggregator::Aggregator): u128
pragma opaque;
// This enforces high-level requirement 1:
aborts_if false;
ensures result == spec_read(aggregator);
ensures result <= spec_get_limit(aggregator);

destroy

public fun destroy(aggregator: aggregator::Aggregator)
pragma opaque;
// This enforces high-level requirement 1:
aborts_if false;