aggregator_v2 - [mainnet]
This module provides an interface for aggregators (version 2). 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 try_add(X, 1)
for aggregator X
, and the second is
doing try_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 a resource-intensive
operation that also reduced parallelism, and should be avoided as much as possible.
If you need to capture the value, without revealing it, use snapshot function instead,
which has no parallelism impact.
From parallelism considerations, there are three different levels of effects:
- enable full parallelism (cannot create conflicts): max_value, create_*, snapshot, derive_string_concat
- enable speculative parallelism (generally parallel via branch prediction) try_add, add, try_sub, sub, is_at_least
- create read/write conflicts, as if you were using a regular field read, read_snapshot, read_derived_string
use 0x1::error;use 0x1::features;use 0x1::string;
Constants
The value of aggregator overflows. Raised by uncoditional add() call
const EAGGREGATOR_OVERFLOW: u64 = 1;
The value of aggregator underflows (goes below zero). Raised by uncoditional sub() call
const EAGGREGATOR_UNDERFLOW: u64 = 2;
The aggregator api v2 feature flag is not enabled.
const EAGGREGATOR_API_V2_NOT_ENABLED: u64 = 6;
The native aggregator function, that is in the move file, is not yet supported. and any calls will raise this error.
const EAGGREGATOR_FUNCTION_NOT_YET_SUPPORTED: u64 = 9;
Arguments passed to concat exceed max limit of 1024 bytes (for prefix and suffix together).
const ECONCAT_STRING_LENGTH_TOO_LARGE: u64 = 8;
The generic type supplied to the aggregator snapshot is not supported.
const EUNSUPPORTED_AGGREGATOR_SNAPSHOT_TYPE: u64 = 5;
The generic type supplied to the aggregator is not supported.
const EUNSUPPORTED_AGGREGATOR_TYPE: u64 = 7;
Structs
Aggregator
Represents an integer which supports parallel additions and subtractions across multiple transactions. See the module description for more details.
Currently supported types for IntElement are u64 and u128.
struct Aggregator<IntElement> has drop, store
Fields
-
value: IntElement
-
max_value: IntElement
AggregatorSnapshot
Represents a constant value, that was derived from an aggregator at given instant in time. Unlike read() and storing the value directly, this enables parallel execution of transactions, while storing snapshot of aggregator state elsewhere.
struct AggregatorSnapshot<IntElement> has drop, store
Fields
-
value: IntElement
DerivedStringSnapshot
struct DerivedStringSnapshot has drop, store
Fields
-
value: string::String
-
padding: vector<u8>
Functions
max_value
Returns max_value
exceeding which aggregator overflows.
public fun max_value<IntElement: copy, drop>(self: &aggregator_v2::Aggregator<IntElement>): IntElement
Implementation
public fun max_value<IntElement: copy + drop>(self: &Aggregator<IntElement>): IntElement { self.max_value}
create_aggregator
Creates new aggregator, with given ‘max_value’.
Currently supported types for IntElement are u64 and u128. EAGGREGATOR_ELEMENT_TYPE_NOT_SUPPORTED raised if called with a different type.
public fun create_aggregator<IntElement: copy, drop>(max_value: IntElement): aggregator_v2::Aggregator<IntElement>
Implementation
public native fun create_aggregator<IntElement: copy + drop>(max_value: IntElement): Aggregator<IntElement>;
create_aggregator_with_value
public fun create_aggregator_with_value<IntElement: copy, drop>(start_value: IntElement, max_value: IntElement): aggregator_v2::Aggregator<IntElement>
Implementation
public fun create_aggregator_with_value<IntElement: copy + drop>(start_value: IntElement, max_value: IntElement): Aggregator<IntElement> { let aggregator = create_aggregator(max_value); aggregator.add(start_value); aggregator}
create_unbounded_aggregator
Creates new aggregator, without any ‘max_value’ on top of the implicit bound restriction due to the width of the type (i.e. MAX_U64 for u64, MAX_U128 for u128).
Currently supported types for IntElement are u64 and u128. EAGGREGATOR_ELEMENT_TYPE_NOT_SUPPORTED raised if called with a different type.
public fun create_unbounded_aggregator<IntElement: copy, drop>(): aggregator_v2::Aggregator<IntElement>
Implementation
public native fun create_unbounded_aggregator<IntElement: copy + drop>(): Aggregator<IntElement>;
create_unbounded_aggregator_with_value
public fun create_unbounded_aggregator_with_value<IntElement: copy, drop>(start_value: IntElement): aggregator_v2::Aggregator<IntElement>
Implementation
public fun create_unbounded_aggregator_with_value<IntElement: copy + drop>(start_value: IntElement): Aggregator<IntElement> { let aggregator = create_unbounded_aggregator(); aggregator.add(start_value); aggregator}
try_add
Adds value
to aggregator.
If addition would exceed the max_value, false
is returned, and aggregator value is left unchanged.
Parallelism info: This operation enables speculative parallelism.
public fun try_add<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement): bool
Implementation
public native fun try_add<IntElement>(self: &mut Aggregator<IntElement>, value: IntElement): bool;
add
Adds value
to aggregator, unconditionally.
If addition would exceed the max_value, EAGGREGATOR_OVERFLOW exception will be thrown.
Parallelism info: This operation enables speculative parallelism.
public fun add<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement)
Implementation
public fun add<IntElement>(self: &mut Aggregator<IntElement>, value: IntElement) { assert!(self.try_add(value), error::out_of_range(EAGGREGATOR_OVERFLOW));}
try_sub
Subtracts value
from aggregator.
If subtraction would result in a negative value, false
is returned, and aggregator value is left unchanged.
Parallelism info: This operation enables speculative parallelism.
public fun try_sub<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement): bool
Implementation
public native fun try_sub<IntElement>(self: &mut Aggregator<IntElement>, value: IntElement): bool;
sub
Parallelism info: This operation enables speculative parallelism.
public fun sub<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement)
Implementation
public fun sub<IntElement>(self: &mut Aggregator<IntElement>, value: IntElement) { assert!(self.try_sub(value), error::out_of_range(EAGGREGATOR_UNDERFLOW));}
is_at_least_impl
fun is_at_least_impl<IntElement>(self: &aggregator_v2::Aggregator<IntElement>, min_amount: IntElement): bool
Implementation
native fun is_at_least_impl<IntElement>(self: &Aggregator<IntElement>, min_amount: IntElement): bool;
is_at_least
Returns true if aggregator value is larger than or equal to the given min_amount
, false otherwise.
This operation is more efficient and much more parallelization friendly than calling read(agg) > min_amount
.
Until traits are deployed, is_at_most
/is_equal
utility methods can be derived from this one (assuming +1 doesn’t overflow):
- for
is_at_most(agg, max_amount)
, you can do!is_at_least(max_amount + 1)
- for
is_equal(agg, value)
, you can dois_at_least(value) && !is_at_least(value + 1)
Parallelism info: This operation enables speculative parallelism.
public fun is_at_least<IntElement>(self: &aggregator_v2::Aggregator<IntElement>, min_amount: IntElement): bool
Implementation
public fun is_at_least<IntElement>(self: &Aggregator<IntElement>, min_amount: IntElement): bool { assert!(features::aggregator_v2_is_at_least_api_enabled(), EAGGREGATOR_API_V2_NOT_ENABLED); self.is_at_least_impl(min_amount)}
read
Returns a value stored in this aggregator. Note: This operation is resource-intensive, and reduces parallelism. If you need to capture the value, without revealing it, use snapshot function instead, which has no parallelism impact. If called in a transaction that also modifies the aggregator, or has other read/write conflicts, it will sequentialize that transaction. (i.e. up to concurrency_level times slower) If called in a separate transaction (i.e. after transaction that modifies aggregator), it might be up to two times slower.
Parallelism info: This operation prevents speculative parallelism.
public fun read<IntElement>(self: &aggregator_v2::Aggregator<IntElement>): IntElement
Implementation
public native fun read<IntElement>(self: &Aggregator<IntElement>): IntElement;
snapshot
Returns a wrapper of a current value of an aggregator Unlike read(), it is fast and avoids sequential dependencies.
Parallelism info: This operation enables parallelism.
public fun snapshot<IntElement>(self: &aggregator_v2::Aggregator<IntElement>): aggregator_v2::AggregatorSnapshot<IntElement>
Implementation
public native fun snapshot<IntElement>(self: &Aggregator<IntElement>): AggregatorSnapshot<IntElement>;
create_snapshot
Creates a snapshot of a given value. Useful for when object is sometimes created via snapshot() or string_concat(), and sometimes directly.
public fun create_snapshot<IntElement: copy, drop>(value: IntElement): aggregator_v2::AggregatorSnapshot<IntElement>
Implementation
public native fun create_snapshot<IntElement: copy + drop>(value: IntElement): AggregatorSnapshot<IntElement>;
read_snapshot
Returns a value stored in this snapshot. Note: This operation is resource-intensive, and reduces parallelism. (Especially if called in a transaction that also modifies the aggregator, or has other read/write conflicts)
Parallelism info: This operation prevents speculative parallelism.
public fun read_snapshot<IntElement>(self: &aggregator_v2::AggregatorSnapshot<IntElement>): IntElement
Implementation
public native fun read_snapshot<IntElement>(self: &AggregatorSnapshot<IntElement>): IntElement;
read_derived_string
Returns a value stored in this DerivedStringSnapshot. Note: This operation is resource-intensive, and reduces parallelism. (Especially if called in a transaction that also modifies the aggregator, or has other read/write conflicts)
Parallelism info: This operation prevents speculative parallelism.
public fun read_derived_string(self: &aggregator_v2::DerivedStringSnapshot): string::String
Implementation
public native fun read_derived_string(self: &DerivedStringSnapshot): String;
create_derived_string
Creates a DerivedStringSnapshot of a given value. Useful for when object is sometimes created via string_concat(), and sometimes directly.
public fun create_derived_string(value: string::String): aggregator_v2::DerivedStringSnapshot
Implementation
public native fun create_derived_string(value: String): DerivedStringSnapshot;
derive_string_concat
Concatenates before
, snapshot
and after
into a single string.
snapshot passed needs to have integer type - currently supported types are u64 and u128.
Raises EUNSUPPORTED_AGGREGATOR_SNAPSHOT_TYPE if called with another type.
If length of prefix and suffix together exceeds 1024 bytes, ECONCAT_STRING_LENGTH_TOO_LARGE is raised.
Parallelism info: This operation enables parallelism.
public fun derive_string_concat<IntElement>(before: string::String, snapshot: &aggregator_v2::AggregatorSnapshot<IntElement>, after: string::String): aggregator_v2::DerivedStringSnapshot
Implementation
public native fun derive_string_concat<IntElement>(before: String, snapshot: &AggregatorSnapshot<IntElement>, after: String): DerivedStringSnapshot;
copy_snapshot
NOT YET IMPLEMENTED, always raises EAGGREGATOR_FUNCTION_NOT_YET_SUPPORTED.
#[deprecated]public fun copy_snapshot<IntElement: copy, drop>(snapshot: &aggregator_v2::AggregatorSnapshot<IntElement>): aggregator_v2::AggregatorSnapshot<IntElement>
Implementation
public native fun copy_snapshot<IntElement: copy + drop>(snapshot: &AggregatorSnapshot<IntElement>): AggregatorSnapshot<IntElement>;
string_concat
DEPRECATED, use derive_string_concat() instead. always raises EAGGREGATOR_FUNCTION_NOT_YET_SUPPORTED.
#[deprecated]public fun string_concat<IntElement>(before: string::String, snapshot: &aggregator_v2::AggregatorSnapshot<IntElement>, after: string::String): aggregator_v2::AggregatorSnapshot<string::String>
Implementation
public native fun string_concat<IntElement>(before: String, snapshot: &AggregatorSnapshot<IntElement>, after: String): AggregatorSnapshot<String>;
Specification
Aggregator
struct Aggregator<IntElement> has drop, store
-
value: IntElement
-
max_value: IntElement
pragma intrinsic;
max_value
public fun max_value<IntElement: copy, drop>(self: &aggregator_v2::Aggregator<IntElement>): IntElement
pragma intrinsic;
create_aggregator
public fun create_aggregator<IntElement: copy, drop>(max_value: IntElement): aggregator_v2::Aggregator<IntElement>
pragma intrinsic;
create_unbounded_aggregator
public fun create_unbounded_aggregator<IntElement: copy, drop>(): aggregator_v2::Aggregator<IntElement>
pragma intrinsic;
try_add
public fun try_add<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement): bool
pragma intrinsic;
add
public fun add<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement)
pragma intrinsic;
try_sub
public fun try_sub<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement): bool
pragma intrinsic;
sub
public fun sub<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement)
pragma intrinsic;
is_at_least_impl
fun is_at_least_impl<IntElement>(self: &aggregator_v2::Aggregator<IntElement>, min_amount: IntElement): bool
pragma intrinsic;
read
public fun read<IntElement>(self: &aggregator_v2::Aggregator<IntElement>): IntElement
pragma intrinsic;
snapshot
public fun snapshot<IntElement>(self: &aggregator_v2::Aggregator<IntElement>): aggregator_v2::AggregatorSnapshot<IntElement>
pragma opaque;include AbortsIfIntElement<IntElement>;ensures [abstract] result.value == spec_get_value(self);
create_snapshot
public fun create_snapshot<IntElement: copy, drop>(value: IntElement): aggregator_v2::AggregatorSnapshot<IntElement>
pragma opaque;include AbortsIfIntElement<IntElement>;ensures [abstract] result.value == value;
read_snapshot
public fun read_snapshot<IntElement>(self: &aggregator_v2::AggregatorSnapshot<IntElement>): IntElement
pragma opaque;include AbortsIfIntElement<IntElement>;ensures [abstract] result == self.value;
read_derived_string
public fun read_derived_string(self: &aggregator_v2::DerivedStringSnapshot): string::String
pragma opaque;aborts_if [abstract] false;ensures [abstract] result == self.value;
create_derived_string
public fun create_derived_string(value: string::String): aggregator_v2::DerivedStringSnapshot
pragma opaque;aborts_if [abstract] len(value.bytes) > 1024;ensures [abstract] result.value == value;
derive_string_concat
public fun derive_string_concat<IntElement>(before: string::String, snapshot: &aggregator_v2::AggregatorSnapshot<IntElement>, after: string::String): aggregator_v2::DerivedStringSnapshot
pragma opaque;include AbortsIfIntElement<IntElement>;ensures [abstract] result.value.bytes == concat(before.bytes, concat(spec_get_string_value(snapshot).bytes, after.bytes));aborts_if [abstract] len(before.bytes) + len(after.bytes) > 1024;
schema AbortsIfIntElement<IntElement> { aborts_if [abstract] type_info::type_name<IntElement>().bytes != b"u64" && type_info::type_name<IntElement>().bytes != b"u128";}
copy_snapshot
#[deprecated]public fun copy_snapshot<IntElement: copy, drop>(snapshot: &aggregator_v2::AggregatorSnapshot<IntElement>): aggregator_v2::AggregatorSnapshot<IntElement>
pragma opaque;aborts_if [abstract] true;
string_concat
#[deprecated]public fun string_concat<IntElement>(before: string::String, snapshot: &aggregator_v2::AggregatorSnapshot<IntElement>, after: string::String): aggregator_v2::AggregatorSnapshot<string::String>
pragma opaque;aborts_if [abstract] true;
native fun spec_get_value<IntElement>(aggregator: Aggregator<IntElement>): IntElement;
native fun spec_get_max_value<IntElement>(aggregator: Aggregator<IntElement>): IntElement;
fun spec_get_string_value<IntElement>(aggregator: AggregatorSnapshot<IntElement>): String;
fun spec_read_snapshot<IntElement>(snapshot: AggregatorSnapshot<IntElement>): IntElement { snapshot.value}
fun spec_read_derived_string(snapshot: DerivedStringSnapshot): String { snapshot.value}