diff --git a/aptos-move/framework/aptos-framework/doc/aggregator.md b/aptos-move/framework/aptos-framework/doc/aggregator.md index 7bf411bebcb0a..1aad7e8d1725e 100644 --- a/aptos-move/framework/aptos-framework/doc/aggregator.md +++ b/aptos-move/framework/aptos-framework/doc/aggregator.md @@ -3,67 +3,18 @@ # Module `0x1::aggregator` -This module provides an API for aggregatable integers that allow addition, -subtraction, and reading. - -Design rationale (V1) -===================== -Aggregator can be seen as a parellizable integer that supports addition, -subtraction and reading. The first version (V1) of aggregator has the -the following specification. - -add(value: u128) -Speculatively adds a value to aggregator. This is a cheap operation -which is parallelizable. If the result of addition overflows a limit -(one of aggregator's fields), an error is produced and the execution -aborts. - -sub(value: u128) -Speculatively subtracts a value from aggregator. This is a cheap -operation which is parallelizable. If the result goes below zero, an -error is produced and the execution aborts. - -read(): u128 -Reads (materializes) the value of an aggregator. This is an expensive -operation which usually involves reading from the storage. - -destroy() -Destroys and aggregator, also cleaning up storage if necessary. - -Note that there is no constructor in Aggregator API. This is done on purpose. -For every aggregator, we need to know where its value is stored on chain. -Currently, Move does not allow fine grained access to struct fields. For -example, given a struct - -struct Foo has key { -a: A, -b: u128, -} - -there is no way of getting a value of Foo::a without hardcoding the layout -of Foo and the field offset. To mitigate this problem, one can use a table. -Every item stored in the table is uniqely identified by (handle, key) pair: -handle identifies a table instance, key identifies an item within the table. - -So how is this related to aggregator? Well, aggregator can reuse the table's -approach for fine-grained storage. However, since native functions only see a -reference to aggregator, we must ensure that both handle and key are -included as fields. Therefore, the struct looks like - -struct Aggregator { -handle: u128, -key: u128, -.. -} - -Remaining question is how to generate this (handle, key) pair. For that, we have -a dedicated struct called AggregatorFactory which is responsible for constructing -aggregators. See aggregator_factory.move for more details. - -Advice to users (V1) -==================== -Users are encouraged to use "cheap" operations (e.g. additions) to exploit the -parallelism in execution. +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.** - [Struct `Aggregator`](#0x1_aggregator_Aggregator) @@ -88,6 +39,8 @@ parallelism in execution. ## Struct `Aggregator` +Represents an integer which supports parallel additions and subtractions +across multiple transactions. See the module description for more details.
struct Aggregator has store
@@ -130,7 +83,7 @@ parallelism in execution.
 
 
 
-When the value of aggregator (actual or accumulated) overflows (raised by native code).
+The value of aggregator overflows. Raised by native code.
 
 
 
const EAGGREGATOR_OVERFLOW: u64 = 1;
@@ -140,7 +93,7 @@ When the value of aggregator (actual or accumulated) overflows (raised by native
 
 
 
-When the value of aggregator (actual or accumulated) underflows, i.e goes below zero (raised by native code).
+The value of aggregator underflows (goes below zero). Raised by native code.
 
 
 
const EAGGREGATOR_UNDERFLOW: u64 = 2;
@@ -150,7 +103,7 @@ When the value of aggregator (actual or accumulated) underflows, i.e goes below
 
 
 
-When aggregator feature is not supported (raised by native code).
+Aggregator feature is not supported. Raised by native code.
 
 
 
const ENOT_SUPPORTED: u64 = 3;
diff --git a/aptos-move/framework/aptos-framework/doc/aggregator_factory.md b/aptos-move/framework/aptos-framework/doc/aggregator_factory.md
index bd37acaed36d8..e59707d642601 100644
--- a/aptos-move/framework/aptos-framework/doc/aggregator_factory.md
+++ b/aptos-move/framework/aptos-framework/doc/aggregator_factory.md
@@ -3,34 +3,11 @@
 
 # Module `0x1::aggregator_factory`
 
-This module provides foundations to create aggregators in the system.
-
-Design rationale (V1)
-=====================
-First, we encourage the reader to see rationale of Aggregator in
-aggregator.move.
-
-Recall that the value of any aggregator can be identified in storage by
-(handle, key) pair. How this pair can be generated? Short answer: with
-AggregatorFactory!
-
-AggregatorFactory is a struct that can be stored as a resource on some
-account and which contains a phantom_table field. When the factory is
-initialized, we initialize this table. Importantly, table initialization
-only generates a uniue table handle - something we can reuse.
-
-When the user wants to create a new aggregator, he/she calls a constructor
-provided by the factory (create_aggregator(..)). This constructor generates
-a unique key, which with the handle is used to initialize Aggregator struct.
-
-Use cases
-=========
-We limit the usage of AggregatorFactory by only storing it on the core
-account.
-
-When something whants to use an aggregator, the factory is queried and an
-aggregator instance is created. Once aggregator is no longer in use, it
-should be destroyed by the user.
+This module provides foundations to create aggregators. Currently only
+Aptos Framework (0x1) can create them, so this module helps to wrap
+the constructor of Aggregator struct so that only a system account
+can initialize one. In the future, this might change and aggregators
+can be enabled for the public.
 
 
 -  [Resource `AggregatorFactory`](#0x1_aggregator_factory_AggregatorFactory)
@@ -55,7 +32,9 @@ should be destroyed by the user.
 
 ## Resource `AggregatorFactory`
 
-Struct that creates aggregators.
+Creates new aggregators. Used to control the numbers of aggregators in the
+system and who can create them. At the moment, only Aptos Framework (0x1)
+account can.
 
 
 
struct AggregatorFactory has key
@@ -86,7 +65,7 @@ Struct that creates aggregators.
 
 
 
-When aggregator factory is not published yet.
+Aggregator factory is not published yet.
 
 
 
const EAGGREGATOR_FACTORY_NOT_FOUND: u64 = 1;
@@ -98,8 +77,7 @@ When aggregator factory is not published yet.
 
 ## Function `initialize_aggregator_factory`
 
-Can only be called during genesis.
-Creates a new factory for aggregators.
+Creates a new factory for aggregators. Can only be called during genesis.
 
 
 
public(friend) fun initialize_aggregator_factory(aptos_framework: &signer)
@@ -187,6 +165,7 @@ to allow any signer to call.
 
 ## Function `new_aggregator`
 
+Returns a new aggregator.
 
 
 
fun new_aggregator(aggregator_factory: &mut aggregator_factory::AggregatorFactory, limit: u128): aggregator::Aggregator
diff --git a/aptos-move/framework/aptos-framework/doc/optional_aggregator.md b/aptos-move/framework/aptos-framework/doc/optional_aggregator.md
index 1051002e18dfe..c59bd32b79ef7 100644
--- a/aptos-move/framework/aptos-framework/doc/optional_aggregator.md
+++ b/aptos-move/framework/aptos-framework/doc/optional_aggregator.md
@@ -43,9 +43,7 @@ aggregator (parallelizable) or via normal integers.
 
 ## Struct `Integer`
 
-Wrapper around integer to have a custom overflow limit. Note that
-Move has no traits (and trait bounds), so integer value must be u128.
-Integer provides API to add/subtract and read, just like Aggregator.
+Wrapper around integer with a custom overflow limit. Supports add, subtract and read just like Aggregator.
 
 
 
struct Integer has store
@@ -79,8 +77,7 @@ Move has no traits (and trait bounds), so integer value must be u128.
 
 ## Struct `OptionalAggregator`
 
-Struct that contains either an aggregator or a normal integer, both
-overflowing on limit.
+Contains either an aggregator or a normal integer, both overflowing on limit.
 
 
 
struct OptionalAggregator has store
@@ -117,6 +114,7 @@ overflowing on limit.
 
 
 
+The value of aggregator underflows (goes below zero). Raised by native code.
 
 
 
const EAGGREGATOR_OVERFLOW: u64 = 1;
@@ -126,6 +124,7 @@ overflowing on limit.
 
 
 
+Aggregator feature is not supported. Raised by native code.
 
 
 
const EAGGREGATOR_UNDERFLOW: u64 = 2;
@@ -137,6 +136,7 @@ overflowing on limit.
 
 ## Function `new_integer`
 
+Creates a new integer which overflows on exceeding a limit.
 
 
 
fun new_integer(limit: u128): optional_aggregator::Integer
@@ -164,6 +164,7 @@ overflowing on limit.
 
 ## Function `add_integer`
 
+Adds value to integer. Aborts on overflowing the limit.
 
 
 
fun add_integer(integer: &mut optional_aggregator::Integer, value: u128)
@@ -192,6 +193,7 @@ overflowing on limit.
 
 ## Function `sub_integer`
 
+Subtracts value from integer. Aborts on going below zero.
 
 
 
fun sub_integer(integer: &mut optional_aggregator::Integer, value: u128)
@@ -217,6 +219,7 @@ overflowing on limit.
 
 ## Function `limit`
 
+Returns an overflow limit of integer.
 
 
 
fun limit(integer: &optional_aggregator::Integer): u128
@@ -241,6 +244,7 @@ overflowing on limit.
 
 ## Function `read_integer`
 
+Returns a value stored in this integer.
 
 
 
fun read_integer(integer: &optional_aggregator::Integer): u128
@@ -265,6 +269,7 @@ overflowing on limit.
 
 ## Function `destroy_integer`
 
+Destroys an integer.
 
 
 
fun destroy_integer(integer: optional_aggregator::Integer)
@@ -289,7 +294,7 @@ overflowing on limit.
 
 ## Function `new`
 
-Creates a new optional aggregator instance.
+Creates a new optional aggregator.
 
 
 
public(friend) fun new(limit: u128, parallelizable: bool): optional_aggregator::OptionalAggregator
@@ -534,7 +539,7 @@ Destroys non-parallelizable optional aggregator and returns its limit.
 
 ## Function `add`
 
-Adds to optional aggregator, aborting on exceeding the limit.
+Adds value to optional aggregator, aborting on exceeding the limit.
 
 
 
public fun add(optional_aggregator: &mut optional_aggregator::OptionalAggregator, value: u128)
@@ -565,7 +570,7 @@ Adds to optional aggregator, aborting on exceeding the limit.
 
 ## Function `sub`
 
-Subtracts from optional aggregator, aborting on going below zero.
+Subtracts value from optional aggregator, aborting on going below zero.
 
 
 
public fun sub(optional_aggregator: &mut optional_aggregator::OptionalAggregator, value: u128)
@@ -627,7 +632,7 @@ Returns the value stored in optional aggregator.
 
 ## Function `is_parallelizable`
 
-Returns true is optional aggregator uses parallelizable implementation.
+Returns true if optional aggregator uses parallelizable implementation.
 
 
 
public fun is_parallelizable(optional_aggregator: &optional_aggregator::OptionalAggregator): bool
diff --git a/aptos-move/framework/aptos-framework/sources/aggregator/README.md b/aptos-move/framework/aptos-framework/sources/aggregator/README.md
new file mode 100644
index 0000000000000..9c57db04440b5
--- /dev/null
+++ b/aptos-move/framework/aptos-framework/sources/aggregator/README.md
@@ -0,0 +1,47 @@
+# Design Rationale
+
+## Aggregators
+
+Aggregator is a parellizable integer that supports addition and subtraction.
+Unlike integer, aggregator has a user-defined `limit` which specifies when
+the value of aggregator overflows. Similarly to unsigned integers, the value
+of an aggregator underflows when going below zero.
+
+Both additions and subtractions are executed speculatively, and thus can be
+easily parallelized. On underflow or overflow, these operations are guaranteed
+to abort. Using these operations is encouraged.
+
+Reading an aggregator's value "materializes" the speculative value, and it
+can involve reading from the storage or checking for underflow or overflow.
+In general, using this operation is discouraged, or at least it should be used
+as rarely as possible.
+
+## Aggregator factory
+
+Unfortunately, aggregators cannot be part of a resource. At the moment, Move
+does not allow fine-grained access to resource fields, which ruins perfromance
+benefits aggregators can provide. In addition, getting the value of the field of
+a resource from storage is not possible without hardcoding the struct layout.
+For example, given a struct
+
+```move
+struct Foo has key {
+    a: A,
+    b: u128,
+}
+```
+
+there is no clean way of getting the value of `Foo::a` without knowing that the
+offset is 0.
+
+To mitigate the problem, we store aggregators as table items. Recall that every
+item stored in the table is uniquely identified by `(handle, key)` pair: `handle` 
+identifies a table instance, and `key` identifies an item within the table. Now,
+if aggregator is a table item, it can be easily queried from storage and has a
+fine-grained access.
+
+To create an aggregator, one can use an `AggregatorFactory`. It is a resource
+which contains a single `phantom_table` field. When the factory is initialized,
+this field is used to generate a unique table `handle` which is passed to all
+new aggregators. When a new aggregator instance is created, it has a unique
+`key` which together with the `handle` is stored in `Aggregator` struct.
diff --git a/aptos-move/framework/aptos-framework/sources/aggregator/aggregator.move b/aptos-move/framework/aptos-framework/sources/aggregator/aggregator.move
index 549b795370b01..9a0baaff12916 100644
--- a/aptos-move/framework/aptos-framework/sources/aggregator/aggregator.move
+++ b/aptos-move/framework/aptos-framework/sources/aggregator/aggregator.move
@@ -1,75 +1,28 @@
-/// This module provides an API for aggregatable integers that allow addition,
-/// subtraction, and reading.
-///
-/// Design rationale (V1)
-/// =====================
-/// Aggregator can be seen as a parellizable integer that supports addition,
-/// subtraction and reading. The first version (V1) of aggregator has the
-/// the following specification.
-///
-/// add(value: u128)
-///   Speculatively adds a `value` to aggregator. This is a cheap operation
-///   which is parallelizable. If the result of addition overflows a `limit`
-///   (one of aggregator's fields), an error is produced and the execution
-///   aborts.
-///
-/// sub(value: u128)
-///   Speculatively subtracts a `value` from aggregator. This is a cheap
-///   operation which is parallelizable. If the result goes below zero, an
-///   error is produced and the execution aborts.
-///
-/// read(): u128
-///   Reads (materializes) the value of an aggregator. This is an expensive
-///   operation which usually involves reading from the storage.
-///
-/// destroy()
-///   Destroys and aggregator, also cleaning up storage if necessary.
-///
-/// Note that there is no constructor in `Aggregator` API. This is done on purpose.
-/// For every aggregator, we need to know where its value is stored on chain.
-/// Currently, Move does not allow fine grained access to struct fields. For
-/// example, given a struct
-///
-///   struct Foo has key {
-///       a: A,
-///       b: u128,
-///   }
-///
-/// there is no way of getting a value of `Foo::a` without hardcoding the layout
-/// of `Foo` and the field offset. To mitigate this problem, one can use a table.
-/// Every item stored in the table is uniqely identified by (handle, key) pair:
-/// `handle` identifies a table instance, `key` identifies an item within the table.
-///
-/// So how is this related to aggregator? Well, aggregator can reuse the table's
-/// approach for fine-grained storage. However, since native functions only see a
-/// reference to aggregator, we must ensure that both `handle` and `key` are
-/// included as fields. Therefore, the struct looks like
-///
-///  struct Aggregator {
-///      handle: u128,
-///      key: u128,
-///      ..
-///  }
-///
-/// Remaining question is how to generate this (handle, key) pair. For that, we have
-/// a dedicated struct called `AggregatorFactory` which is responsible for constructing
-/// aggregators. See `aggregator_factory.move` for more details.
-///
-/// Advice to users (V1)
-/// ====================
-/// Users are encouraged to use "cheap" operations (e.g. additions) to exploit the
-/// parallelism in execution.
+/// 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.**
 module aptos_framework::aggregator {
 
-    /// When the value of aggregator (actual or accumulated) overflows (raised by native code).
+    /// The value of aggregator overflows. Raised by native code.
     const EAGGREGATOR_OVERFLOW: u64 = 1;
 
-    /// When the value of aggregator (actual or accumulated) underflows, i.e goes below zero (raised by native code).
+    /// The value of aggregator underflows (goes below zero). Raised by native code.
     const EAGGREGATOR_UNDERFLOW: u64 = 2;
 
-    /// When aggregator feature is not supported (raised by native code).
+    /// Aggregator feature is not supported. Raised by native code.
     const ENOT_SUPPORTED: u64 = 3;
 
+    /// Represents an integer which supports parallel additions and subtractions
+    /// across multiple transactions. See the module description for more details.
     struct Aggregator has store {
         handle: address,
         key: address,
diff --git a/aptos-move/framework/aptos-framework/sources/aggregator/aggregator_factory.move b/aptos-move/framework/aptos-framework/sources/aggregator/aggregator_factory.move
index 312e6c550b71b..cfdc79f30c4a4 100644
--- a/aptos-move/framework/aptos-framework/sources/aggregator/aggregator_factory.move
+++ b/aptos-move/framework/aptos-framework/sources/aggregator/aggregator_factory.move
@@ -1,31 +1,8 @@
-/// This module provides foundations to create aggregators in the system.
-///
-/// Design rationale (V1)
-/// =====================
-/// First, we encourage the reader to see rationale of `Aggregator` in
-/// `aggregator.move`.
-///
-/// Recall that the value of any aggregator can be identified in storage by
-/// (handle, key) pair. How this pair can be generated? Short answer: with
-/// `AggregatorFactory`!
-///
-/// `AggregatorFactory` is a struct that can be stored as a resource on some
-/// account and which contains a `phantom_table` field. When the factory is
-/// initialized, we initialize this table. Importantly, table initialization
-/// only generates a uniue table `handle` - something we can reuse.
-///
-/// When the user wants to create a new aggregator, he/she calls a constructor
-/// provided by the factory (`create_aggregator(..)`). This constructor generates
-/// a unique key, which with the handle is used to initialize `Aggregator` struct.
-///
-/// Use cases
-/// =========
-/// We limit the usage of `AggregatorFactory` by only storing it on the core
-/// account.
-///
-/// When something whants to use an aggregator, the factory is queried and an
-/// aggregator instance is created. Once aggregator is no longer in use, it
-/// should be destroyed by the user.
+/// This module provides foundations to create aggregators. Currently only
+/// Aptos Framework (0x1) can create them, so this module helps to wrap
+/// the constructor of `Aggregator` struct so that only a system account
+/// can initialize one. In the future, this might change and aggregators
+/// can be enabled for the public.
 module aptos_framework::aggregator_factory {
     use std::error;
 
@@ -36,16 +13,17 @@ module aptos_framework::aggregator_factory {
     friend aptos_framework::genesis;
     friend aptos_framework::optional_aggregator;
 
-    /// When aggregator factory is not published yet.
+    /// Aggregator factory is not published yet.
     const EAGGREGATOR_FACTORY_NOT_FOUND: u64 = 1;
 
-    /// Struct that creates aggregators.
+    /// Creates new aggregators. Used to control the numbers of aggregators in the
+    /// system and who can create them. At the moment, only Aptos Framework (0x1)
+    /// account can.
     struct AggregatorFactory has key {
         phantom_table: Table,
     }
 
-    /// Can only be called during genesis.
-    /// Creates a new factory for aggregators.
+    /// Creates a new factory for aggregators. Can only be called during genesis.
     public(friend) fun initialize_aggregator_factory(aptos_framework: &signer) {
         system_addresses::assert_aptos_framework(aptos_framework);
         let aggregator_factory = AggregatorFactory {
@@ -73,6 +51,7 @@ module aptos_framework::aggregator_factory {
         create_aggregator_internal(limit)
     }
 
+    /// Returns a new aggregator.
     native fun new_aggregator(aggregator_factory: &mut AggregatorFactory, limit: u128): Aggregator;
 
     #[test_only]
diff --git a/aptos-move/framework/aptos-framework/sources/aggregator/optional_aggregator.move b/aptos-move/framework/aptos-framework/sources/aggregator/optional_aggregator.move
index 83fd45a39749a..216750442dbd9 100644
--- a/aptos-move/framework/aptos-framework/sources/aggregator/optional_aggregator.move
+++ b/aptos-move/framework/aptos-framework/sources/aggregator/optional_aggregator.move
@@ -9,19 +9,19 @@ module aptos_framework::optional_aggregator {
 
     friend aptos_framework::coin;
 
-    // These error codes are produced by `Aggregator` and used by `Integer` for
-    // consistency.
+    /// 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;
 
-    /// Wrapper around integer to have a custom overflow limit. Note that
-    /// Move has no traits (and trait bounds), so integer value must be u128.
-    /// `Integer` provides API to add/subtract and read, just like `Aggregator`.
+    /// Wrapper around integer with a custom overflow limit. Supports add, subtract and read just like `Aggregator`.
     struct Integer has store {
         value: u128,
         limit: u128,
     }
 
+    /// Creates a new integer which overflows on exceeding a `limit`.
     fun new_integer(limit: u128): Integer {
         Integer {
             value: 0,
@@ -29,6 +29,7 @@ module aptos_framework::optional_aggregator {
         }
     }
 
+    /// Adds `value` to integer. Aborts on overflowing the limit.
     fun add_integer(integer: &mut Integer, value: u128) {
         assert!(
             value <= (integer.limit - integer.value),
@@ -37,25 +38,28 @@ module aptos_framework::optional_aggregator {
         integer.value = integer.value + value;
     }
 
+    /// Subtracts `value` from integer. Aborts on going below zero.
     fun sub_integer(integer: &mut Integer, value: u128) {
         assert!(value <= integer.value, error::out_of_range(EAGGREGATOR_UNDERFLOW));
         integer.value = integer.value - value;
     }
 
+    /// Returns an overflow limit of integer.
     fun limit(integer: &Integer): u128 {
         integer.limit
     }
 
+    /// Returns a value stored in this integer.
     fun read_integer(integer: &Integer): u128 {
         integer.value
     }
 
+    /// Destroys an integer.
     fun destroy_integer(integer: Integer) {
         let Integer { value: _, limit: _ } = integer;
     }
 
-    /// Struct that contains either an aggregator or a normal integer, both
-    /// overflowing on limit.
+    /// Contains either an aggregator or a normal integer, both overflowing on limit.
     struct OptionalAggregator has store {
         // Parallelizable.
         aggregator: Option,
@@ -63,7 +67,7 @@ module aptos_framework::optional_aggregator {
         integer: Option,
     }
 
-    /// Creates a new optional aggregator instance.
+    /// Creates a new optional aggregator.
     public(friend) fun new(limit: u128, parallelizable: bool): OptionalAggregator {
         if (parallelizable) {
             OptionalAggregator {
@@ -148,7 +152,7 @@ module aptos_framework::optional_aggregator {
         limit
     }
 
-    /// Adds to optional aggregator, aborting on exceeding the `limit`.
+    /// Adds `value` to optional aggregator, aborting on exceeding the `limit`.
     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);
@@ -159,7 +163,7 @@ module aptos_framework::optional_aggregator {
         }
     }
 
-    /// Subtracts from optional aggregator, aborting on going below zero.
+    /// Subtracts `value` from optional aggregator, aborting on going below zero.
     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);
@@ -181,7 +185,7 @@ module aptos_framework::optional_aggregator {
         }
     }
 
-    /// Returns true is optional aggregator uses parallelizable implementation.
+    /// Returns true if optional aggregator uses parallelizable implementation.
     public fun is_parallelizable(optional_aggregator: &OptionalAggregator): bool {
         option::is_some(&optional_aggregator.aggregator)
     }