Skip to content

Commit

Permalink
Add aggregator_v2::is_at_least API
Browse files Browse the repository at this point in the history
  • Loading branch information
igor-aptos committed May 28, 2024
1 parent 0ee977e commit ce876c0
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 10 deletions.
19 changes: 16 additions & 3 deletions aptos-move/aptos-aggregator/src/delayed_field_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ impl DelayedFieldData {
max_value: u128,
input: SignedU128,
resolver: &dyn DelayedFieldResolver,
) -> PartialVMResult<bool> {
self.try_add_or_check_delta(id, max_value, input, resolver, true)
}

pub fn try_add_or_check_delta(
&mut self,
id: DelayedFieldID,
max_value: u128,
input: SignedU128,
resolver: &dyn DelayedFieldResolver,
apply_delta: bool,
) -> PartialVMResult<bool> {
// No need to record or check or try, if input value exceeds the bound.
if input.abs() > max_value {
Expand All @@ -55,7 +66,7 @@ impl DelayedFieldData {
&input,
max_value,
)?;
if result {
if result && apply_delta {
entry.insert(DelayedChange::Apply(DelayedApplyChange::AggregatorDelta {
delta: DeltaWithMax::new(input, max_value),
}));
Expand All @@ -68,7 +79,9 @@ impl DelayedFieldData {
DelayedChange::Create(DelayedFieldValue::Aggregator(value)) => {
match math.unsigned_add_delta(*value, &input) {
Ok(new_value) => {
*value = new_value;
if apply_delta {
*value = new_value;
}
Ok(true)
},
Err(_) => Ok(false),
Expand All @@ -83,7 +96,7 @@ impl DelayedFieldData {
&input,
previous_delta.max_value,
)?;
if result {
if result && apply_delta {
*previous_delta = expect_ok(DeltaWithMax::create_merged_delta(
previous_delta,
&DeltaWithMax::new(input, max_value),
Expand Down
114 changes: 112 additions & 2 deletions aptos-move/framework/aptos-framework/doc/aggregator_v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ doing <code><a href="aggregator_v2.md#0x1_aggregator_v2_try_sub">try_sub</a>(X,3
dependency.
However, reading the aggregator value (i.e. calling <code><a href="aggregator_v2.md#0x1_aggregator_v2_read">read</a>(X)</code>) 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.


- [Struct `Aggregator`](#0x1_aggregator_v2_Aggregator)
Expand All @@ -21,11 +23,15 @@ operation that also reduced parallelism, and should be avoided as much as possib
- [Constants](#@Constants_0)
- [Function `max_value`](#0x1_aggregator_v2_max_value)
- [Function `create_aggregator`](#0x1_aggregator_v2_create_aggregator)
- [Function `create_aggregator_with_value`](#0x1_aggregator_v2_create_aggregator_with_value)
- [Function `create_unbounded_aggregator`](#0x1_aggregator_v2_create_unbounded_aggregator)
- [Function `create_unbounded_aggregator_with_value`](#0x1_aggregator_v2_create_unbounded_aggregator_with_value)
- [Function `try_add`](#0x1_aggregator_v2_try_add)
- [Function `add`](#0x1_aggregator_v2_add)
- [Function `try_sub`](#0x1_aggregator_v2_try_sub)
- [Function `sub`](#0x1_aggregator_v2_sub)
- [Function `is_at_least_impl`](#0x1_aggregator_v2_is_at_least_impl)
- [Function `is_at_least`](#0x1_aggregator_v2_is_at_least)
- [Function `read`](#0x1_aggregator_v2_read)
- [Function `snapshot`](#0x1_aggregator_v2_snapshot)
- [Function `create_snapshot`](#0x1_aggregator_v2_create_snapshot)
Expand All @@ -48,6 +54,7 @@ operation that also reduced parallelism, and should be avoided as much as possib


<pre><code><b>use</b> <a href="../../aptos-stdlib/../move-stdlib/doc/error.md#0x1_error">0x1::error</a>;
<b>use</b> <a href="../../aptos-stdlib/../move-stdlib/doc/features.md#0x1_features">0x1::features</a>;
<b>use</b> <a href="../../aptos-stdlib/../move-stdlib/doc/string.md#0x1_string">0x1::string</a>;
</code></pre>

Expand Down Expand Up @@ -278,6 +285,32 @@ EAGGREGATOR_ELEMENT_TYPE_NOT_SUPPORTED raised if called with a different type.



</details>

<a id="0x1_aggregator_v2_create_aggregator_with_value"></a>

## Function `create_aggregator_with_value`



<pre><code><b>public</b> <b>fun</b> <a href="aggregator_v2.md#0x1_aggregator_v2_create_aggregator_with_value">create_aggregator_with_value</a>&lt;IntElement: <b>copy</b>, drop&gt;(start_value: IntElement, max_value: IntElement): <a href="aggregator_v2.md#0x1_aggregator_v2_Aggregator">aggregator_v2::Aggregator</a>&lt;IntElement&gt;
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="aggregator_v2.md#0x1_aggregator_v2_create_aggregator_with_value">create_aggregator_with_value</a>&lt;IntElement: <b>copy</b> + drop&gt;(start_value: IntElement, max_value: IntElement): <a href="aggregator_v2.md#0x1_aggregator_v2_Aggregator">Aggregator</a>&lt;IntElement&gt; {
<b>let</b> <a href="aggregator.md#0x1_aggregator">aggregator</a> = <a href="aggregator_v2.md#0x1_aggregator_v2_create_aggregator">create_aggregator</a>(max_value);
<a href="aggregator_v2.md#0x1_aggregator_v2_add">add</a>(&<b>mut</b> <a href="aggregator.md#0x1_aggregator">aggregator</a>, start_value);
<a href="aggregator.md#0x1_aggregator">aggregator</a>
}
</code></pre>



</details>

<a id="0x1_aggregator_v2_create_unbounded_aggregator"></a>
Expand Down Expand Up @@ -305,6 +338,32 @@ EAGGREGATOR_ELEMENT_TYPE_NOT_SUPPORTED raised if called with a different type.



</details>

<a id="0x1_aggregator_v2_create_unbounded_aggregator_with_value"></a>

## Function `create_unbounded_aggregator_with_value`



<pre><code><b>public</b> <b>fun</b> <a href="aggregator_v2.md#0x1_aggregator_v2_create_unbounded_aggregator_with_value">create_unbounded_aggregator_with_value</a>&lt;IntElement: <b>copy</b>, drop&gt;(start_value: IntElement): <a href="aggregator_v2.md#0x1_aggregator_v2_Aggregator">aggregator_v2::Aggregator</a>&lt;IntElement&gt;
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="aggregator_v2.md#0x1_aggregator_v2_create_unbounded_aggregator_with_value">create_unbounded_aggregator_with_value</a>&lt;IntElement: <b>copy</b> + drop&gt;(start_value: IntElement): <a href="aggregator_v2.md#0x1_aggregator_v2_Aggregator">Aggregator</a>&lt;IntElement&gt; {
<b>let</b> <a href="aggregator.md#0x1_aggregator">aggregator</a> = <a href="aggregator_v2.md#0x1_aggregator_v2_create_unbounded_aggregator">create_unbounded_aggregator</a>();
<a href="aggregator_v2.md#0x1_aggregator_v2_add">add</a>(&<b>mut</b> <a href="aggregator.md#0x1_aggregator">aggregator</a>, start_value);
<a href="aggregator.md#0x1_aggregator">aggregator</a>
}
</code></pre>



</details>

<a id="0x1_aggregator_v2_try_add"></a>
Expand Down Expand Up @@ -401,6 +460,53 @@ If subtraction would result in a negative value, <code><b>false</b></code> is re



</details>

<a id="0x1_aggregator_v2_is_at_least_impl"></a>

## Function `is_at_least_impl`



<pre><code><b>fun</b> <a href="aggregator_v2.md#0x1_aggregator_v2_is_at_least_impl">is_at_least_impl</a>&lt;IntElement: <b>copy</b>, drop&gt;(<a href="aggregator.md#0x1_aggregator">aggregator</a>: &<a href="aggregator_v2.md#0x1_aggregator_v2_Aggregator">aggregator_v2::Aggregator</a>&lt;IntElement&gt;, min_amount: IntElement): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>native</b> <b>fun</b> <a href="aggregator_v2.md#0x1_aggregator_v2_is_at_least_impl">is_at_least_impl</a>&lt;IntElement: <b>copy</b> + drop&gt;(<a href="aggregator.md#0x1_aggregator">aggregator</a>: &<a href="aggregator_v2.md#0x1_aggregator_v2_Aggregator">Aggregator</a>&lt;IntElement&gt;, min_amount: IntElement): bool;
</code></pre>



</details>

<a id="0x1_aggregator_v2_is_at_least"></a>

## Function `is_at_least`



<pre><code><b>public</b> <b>fun</b> <a href="aggregator_v2.md#0x1_aggregator_v2_is_at_least">is_at_least</a>&lt;IntElement: <b>copy</b>, drop&gt;(<a href="aggregator.md#0x1_aggregator">aggregator</a>: &<a href="aggregator_v2.md#0x1_aggregator_v2_Aggregator">aggregator_v2::Aggregator</a>&lt;IntElement&gt;, min_amount: IntElement): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="aggregator_v2.md#0x1_aggregator_v2_is_at_least">is_at_least</a>&lt;IntElement: <b>copy</b> + drop&gt;(<a href="aggregator.md#0x1_aggregator">aggregator</a>: &<a href="aggregator_v2.md#0x1_aggregator_v2_Aggregator">Aggregator</a>&lt;IntElement&gt;, min_amount: IntElement): bool {
<b>assert</b>!(<a href="../../aptos-stdlib/../move-stdlib/doc/features.md#0x1_features_aggregator_v2_is_at_least_api_enabled">features::aggregator_v2_is_at_least_api_enabled</a>(), <a href="aggregator_v2.md#0x1_aggregator_v2_EAGGREGATOR_API_V2_NOT_ENABLED">EAGGREGATOR_API_V2_NOT_ENABLED</a>);
<a href="aggregator_v2.md#0x1_aggregator_v2_is_at_least_impl">is_at_least_impl</a>(<a href="aggregator.md#0x1_aggregator">aggregator</a>, min_amount)
}
</code></pre>



</details>

<a id="0x1_aggregator_v2_read"></a>
Expand All @@ -409,8 +515,12 @@ If subtraction would result in a negative value, <code><b>false</b></code> is re

Returns a value stored in this aggregator.
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)
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.


<pre><code><b>public</b> <b>fun</b> <a href="aggregator_v2.md#0x1_aggregator_v2_read">read</a>&lt;IntElement&gt;(<a href="aggregator.md#0x1_aggregator">aggregator</a>: &<a href="aggregator_v2.md#0x1_aggregator_v2_Aggregator">aggregator_v2::Aggregator</a>&lt;IntElement&gt;): IntElement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
/// 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.
module aptos_framework::aggregator_v2 {
use std::error;
use std::features;
use std::string::String;

/// The value of aggregator overflows. Raised by uncoditional add() call
Expand Down Expand Up @@ -66,13 +69,25 @@ module aptos_framework::aggregator_v2 {
/// EAGGREGATOR_ELEMENT_TYPE_NOT_SUPPORTED raised if called with a different type.
public native fun create_aggregator<IntElement: copy + drop>(max_value: IntElement): Aggregator<IntElement>;

public fun create_aggregator_with_value<IntElement: copy + drop>(start_value: IntElement, max_value: IntElement): Aggregator<IntElement> {
let aggregator = create_aggregator(max_value);
add(&mut aggregator, start_value);
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 native fun create_unbounded_aggregator<IntElement: copy + drop>(): Aggregator<IntElement>;

public fun create_unbounded_aggregator_with_value<IntElement: copy + drop>(start_value: IntElement): Aggregator<IntElement> {
let aggregator = create_unbounded_aggregator();
add(&mut aggregator, start_value);
aggregator
}

/// Adds `value` to aggregator.
/// If addition would exceed the max_value, `false` is returned, and aggregator value is left unchanged.
public native fun try_add<IntElement>(aggregator: &mut Aggregator<IntElement>, value: IntElement): bool;
Expand All @@ -93,10 +108,21 @@ module aptos_framework::aggregator_v2 {
assert!(try_sub(aggregator, value), error::out_of_range(EAGGREGATOR_UNDERFLOW));
}

native fun is_at_least_impl<IntElement: copy + drop>(aggregator: &Aggregator<IntElement>, min_amount: IntElement): bool;

public fun is_at_least<IntElement: copy + drop>(aggregator: &Aggregator<IntElement>, min_amount: IntElement): bool {
assert!(features::aggregator_v2_is_at_least_api_enabled(), EAGGREGATOR_API_V2_NOT_ENABLED);
is_at_least_impl(aggregator, min_amount)
}

/// Returns a value stored in this aggregator.
/// 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)
/// 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.
public native fun read<IntElement>(aggregator: &Aggregator<IntElement>): IntElement;

/// Returns a wrapper of a current value of an aggregator
Expand Down
26 changes: 26 additions & 0 deletions aptos-move/framework/move-stdlib/doc/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ return true.
- [Function `coin_to_fungible_asset_migration_feature_enabled`](#0x1_features_coin_to_fungible_asset_migration_feature_enabled)
- [Function `get_primary_apt_fungible_store_at_user_address_feature`](#0x1_features_get_primary_apt_fungible_store_at_user_address_feature)
- [Function `primary_apt_fungible_store_at_user_address_enabled`](#0x1_features_primary_apt_fungible_store_at_user_address_enabled)
- [Function `aggregator_v2_is_at_least_api_enabled`](#0x1_features_aggregator_v2_is_at_least_api_enabled)
- [Function `get_object_native_derived_address_feature`](#0x1_features_get_object_native_derived_address_feature)
- [Function `object_native_derived_address_enabled`](#0x1_features_object_native_derived_address_enabled)
- [Function `get_dispatchable_fungible_asset_feature`](#0x1_features_get_dispatchable_fungible_asset_feature)
Expand Down Expand Up @@ -2775,6 +2776,31 @@ Lifetime: transient



</details>

<a id="0x1_features_aggregator_v2_is_at_least_api_enabled"></a>

## Function `aggregator_v2_is_at_least_api_enabled`



<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_aggregator_v2_is_at_least_api_enabled">aggregator_v2_is_at_least_api_enabled</a>(): bool
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> <b>fun</b> <a href="features.md#0x1_features_aggregator_v2_is_at_least_api_enabled">aggregator_v2_is_at_least_api_enabled</a>(): bool {
<b>false</b>
// <a href="features.md#0x1_features_is_enabled">is_enabled</a>(AGGREGATOR_V2_IS_AT_LEAST_API)
}
</code></pre>



</details>

<a id="0x1_features_get_object_native_derived_address_feature"></a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,11 @@ module std::features {
is_enabled(PRIMARY_APT_FUNGIBLE_STORE_AT_USER_ADDRESS)
}

public fun aggregator_v2_is_at_least_api_enabled(): bool {
false
// is_enabled(AGGREGATOR_V2_IS_AT_LEAST_API)
}

/// Whether we use more efficient native implementation of computing object derived address
const OBJECT_NATIVE_DERIVED_ADDRESS: u64 = 62;

Expand Down
Loading

0 comments on commit ce876c0

Please sign in to comment.