Module 0x1::aggregator_v2
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
- Struct
Aggregator - Struct
AggregatorSnapshot - Struct
DerivedStringSnapshot - Constants
- Function
max_value - Function
create_aggregator - Function
create_aggregator_with_value - Function
create_unbounded_aggregator - Function
create_unbounded_aggregator_with_value - Function
try_add - Function
add - Function
try_sub - Function
sub - Function
is_at_least_impl - Function
is_at_least - Function
read - Function
snapshot - Function
create_snapshot - Function
read_snapshot - Function
read_derived_string - Function
create_derived_string - Function
derive_string_concat - Function
copy_snapshot - Function
string_concat - Specification
- Struct
Aggregator - Function
max_value - Function
create_aggregator - Function
create_unbounded_aggregator - Function
try_add - Function
add - Function
try_sub - Function
sub - Function
is_at_least_impl - Function
read - Function
snapshot - Function
create_snapshot - Function
read_snapshot - Function
read_derived_string - Function
create_derived_string - Function
derive_string_concat - Function
copy_snapshot - Function
string_concat
- Struct
use 0x1::error;
use 0x1::string;
Struct 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
Struct 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
Struct DerivedStringSnapshot
struct DerivedStringSnapshot has drop, store
Fields
-
value: string::String -
padding: vector<u8>
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;
Function 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
}
Function 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>;
Function 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
}
Function 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>;
Function 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
}
Function 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;
Function 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));
}
Function 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;
Function 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));
}
Function 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;
Function 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 {
self.is_at_least_impl(min_amount)
}
Function 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;
Function 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>;
Function 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>;
Function 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;
Function 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;
Function 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;
Function 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;
Function 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>;
Function 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
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
}
Struct Aggregator
struct Aggregator<IntElement> has drop, store
-
value: IntElement -
max_value: IntElement
pragma intrinsic;
Function max_value
public fun max_value<IntElement: copy, drop>(self: &aggregator_v2::Aggregator<IntElement>): IntElement
pragma intrinsic;
Function create_aggregator
public fun create_aggregator<IntElement: copy, drop>(max_value: IntElement): aggregator_v2::Aggregator<IntElement>
pragma intrinsic;
Function create_unbounded_aggregator
public fun create_unbounded_aggregator<IntElement: copy, drop>(): aggregator_v2::Aggregator<IntElement>
pragma intrinsic;
Function try_add
public fun try_add<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement): bool
pragma intrinsic;
Function add
public fun add<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement)
pragma intrinsic;
Function try_sub
public fun try_sub<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement): bool
pragma intrinsic;
Function sub
public fun sub<IntElement>(self: &mut aggregator_v2::Aggregator<IntElement>, value: IntElement)
pragma intrinsic;
Function is_at_least_impl
fun is_at_least_impl<IntElement>(self: &aggregator_v2::Aggregator<IntElement>, min_amount: IntElement): bool
pragma intrinsic;
Function read
public fun read<IntElement>(self: &aggregator_v2::Aggregator<IntElement>): IntElement
pragma intrinsic;
Function 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);
Function 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;
Function read_snapshot
public fun read_snapshot<IntElement>(self: &aggregator_v2::AggregatorSnapshot<IntElement>): IntElement
pragma opaque;
include AbortsIfIntElement<IntElement>;
ensures [abstract] result == self.value;
Function 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;
Function 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;
Function 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";
}
Function 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;
Function 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;