From 3cb1f1b3fa4a24baa16e4d065e06a055c534c43a Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Wed, 19 Jun 2024 14:06:40 +0300 Subject: [PATCH 01/35] feat(iota-types): staking params were changed according new requirements --- crates/iota-types/src/governance.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/iota-types/src/governance.rs b/crates/iota-types/src/governance.rs index ba54c7d797a..db3b8b7f880 100644 --- a/crates/iota-types/src/governance.rs +++ b/crates/iota-types/src/governance.rs @@ -22,22 +22,22 @@ pub const MAX_VALIDATOR_COUNT: u64 = 150; /// Lower-bound on the amount of stake required to become a validator. /// -/// 30 million IOTA -pub const MIN_VALIDATOR_JOINING_STAKE_MICROS: u64 = 30_000_000 * MICROS_PER_IOTA; +/// 2 million IOTA +pub const MIN_VALIDATOR_JOINING_STAKE_MICROS: u64 = 2_000_000 * MICROS_PER_IOTA; /// Validators with stake amount below `validator_low_stake_threshold` are /// considered to have low stake and will be escorted out of the validator set /// after being below this threshold for more than /// `validator_low_stake_grace_period` number of epochs. /// -/// 20 million IOTA -pub const VALIDATOR_LOW_STAKE_THRESHOLD_MICROS: u64 = 20_000_000 * MICROS_PER_IOTA; +/// 1.5 million IOTA +pub const VALIDATOR_LOW_STAKE_THRESHOLD_MICROS: u64 = 1_500_000 * MICROS_PER_IOTA; /// Validators with stake below `validator_very_low_stake_threshold` will be /// removed immediately at epoch change, no grace period. /// -/// 15 million IOTA -pub const VALIDATOR_VERY_LOW_STAKE_THRESHOLD_MICROS: u64 = 15_000_000 * MICROS_PER_IOTA; +/// 1 million IOTA +pub const VALIDATOR_VERY_LOW_STAKE_THRESHOLD_MICROS: u64 = 1_000_000 * MICROS_PER_IOTA; /// A validator can have stake below `validator_low_stake_threshold` /// for this many epochs before being kicked out. From 9f2b264bcb38956826bdf8fb95ce9df4e480693d Mon Sep 17 00:00:00 2001 From: Valerii Reutov Date: Wed, 19 Jun 2024 16:18:36 +0300 Subject: [PATCH 02/35] feat: store IOTA's TreasutyCap in SystemObject --- .../docs/iota-framework/iota.md | 43 ++++++++++++++++--- .../docs/iota-system/genesis.md | 4 +- .../docs/iota-system/iota_system.md | 4 +- .../iota-system/iota_system_state_inner.md | 18 +++++++- .../packages/iota-framework/sources/iota.move | 23 +++++++--- .../packages/iota-system/sources/genesis.move | 3 ++ .../iota-system/sources/iota_system.move | 4 +- .../sources/iota_system_state_inner.move | 10 ++++- .../tests/governance_test_utils.move | 1 + crates/iota-genesis-builder/src/lib.rs | 41 +++++++++++++----- 10 files changed, 121 insertions(+), 30 deletions(-) diff --git a/crates/iota-framework/docs/iota-framework/iota.md b/crates/iota-framework/docs/iota-framework/iota.md index 7c76bcebee9..0ce9f549757 100644 --- a/crates/iota-framework/docs/iota-framework/iota.md +++ b/crates/iota-framework/docs/iota-framework/iota.md @@ -9,6 +9,7 @@ It has 9 decimals, and the smallest unit (10^-9) is called "micros". - [Struct `IOTA`](#0x2_iota_IOTA) - [Constants](#@Constants_0) - [Function `new`](#0x2_iota_new) +- [Function `increase_supply`](#0x2_iota_increase_supply) - [Function `transfer`](#0x2_iota_transfer) @@ -109,11 +110,11 @@ The total supply of Iota denominated in Micros (10 Billion * 10^9) ## Function `new` -Register the IOTA Coin to acquire its Supply. +Register the IOTA Coin to acquire its TreasuryCap. This should be called only once during genesis creation. -
fun new(ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
fun new(ctx: &mut tx_context::TxContext): coin::TreasuryCap<iota::IOTA>
 
@@ -122,7 +123,7 @@ This should be called only once during genesis creation. Implementation -
fun new(ctx: &mut TxContext): Balance<IOTA> {
+
fun new(ctx: &mut TxContext): TreasuryCap<IOTA> {
     assert!(ctx.sender() == @0x0, ENotSystemAddress);
     assert!(ctx.epoch() == 0, EAlreadyMinted);
 
@@ -136,11 +137,39 @@ This should be called only once during genesis creation.
         option::none(),
         ctx
     );
+
     transfer::public_freeze_object(metadata);
-    let mut supply = treasury.treasury_into_supply();
-    let total_iota = supply.increase_supply(TOTAL_SUPPLY_MICROS);
-    supply.destroy_supply();
-    total_iota
+
+    treasury
+}
+
+ + + + + + + +## Function `increase_supply` + +Increase the IOTA supply. +This should be called only once during genesis creation. + + +
fun increase_supply(cap: &mut coin::TreasuryCap<iota::IOTA>, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
+
+ + + +
+Implementation + + +
fun increase_supply(cap: &mut TreasuryCap<IOTA>, ctx: &TxContext): Balance<IOTA> {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+    assert!(ctx.epoch() == 0, EAlreadyMinted);
+
+    cap.supply_mut().increase_supply(TOTAL_SUPPLY_MICROS)
 }
 
diff --git a/crates/iota-framework/docs/iota-system/genesis.md b/crates/iota-framework/docs/iota-system/genesis.md index 6596d57ac48..15afdec723b 100644 --- a/crates/iota-framework/docs/iota-system/genesis.md +++ b/crates/iota-framework/docs/iota-system/genesis.md @@ -340,7 +340,7 @@ It will create a singleton IotaSystemState object, which contains all the information we need in the system. -
fun create(iota_system_state_id: object::UID, iota_supply: balance::Balance<iota::IOTA>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, ctx: &mut tx_context::TxContext)
+
fun create(iota_system_state_id: object::UID, iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, iota_supply: balance::Balance<iota::IOTA>, genesis_chain_parameters: genesis::GenesisChainParameters, genesis_validators: vector<genesis::GenesisValidatorMetadata>, token_distribution_schedule: genesis::TokenDistributionSchedule, ctx: &mut tx_context::TxContext)
 
@@ -351,6 +351,7 @@ all the information we need in the system.
fun create(
     iota_system_state_id: UID,
+    iota_treasury_cap: TreasuryCap<IOTA>,
     mut iota_supply: Balance<IOTA>,
     genesis_chain_parameters: GenesisChainParameters,
     genesis_validators: vector<GenesisValidatorMetadata>,
@@ -456,6 +457,7 @@ all the information we need in the system.
 
     iota_system::create(
         iota_system_state_id,
+        iota_treasury_cap,
         validators,
         storage_fund,
         genesis_chain_parameters.protocol_version,
diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md
index cf6ab5c3c8a..0d030e5f8a8 100644
--- a/crates/iota-framework/docs/iota-system/iota_system.md
+++ b/crates/iota-framework/docs/iota-system/iota_system.md
@@ -167,7 +167,7 @@ Create a new IotaSystemState object and make it shared.
 This function will be called only once in genesis.
 
 
-
public(friend) fun create(id: object::UID, validators: vector<validator::Validator>, storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext)
+
public(friend) fun create(id: object::UID, iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext)
 
@@ -178,6 +178,7 @@ This function will be called only once in genesis.
public(package) fun create(
     id: UID,
+    iota_treasury_cap: TreasuryCap<IOTA>,
     validators: vector<Validator>,
     storage_fund: Balance<IOTA>,
     protocol_version: u64,
@@ -187,6 +188,7 @@ This function will be called only once in genesis.
     ctx: &mut TxContext,
 ) {
     let system_state = iota_system_state_inner::create(
+        iota_treasury_cap,
         validators,
         storage_fund,
         protocol_version,
diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index 457f001f402..d9229cd6374 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -281,6 +281,12 @@ The top-level object containing all information of the Iota system.
  we know what version it is by inspecting IotaSystemStateInner as well.
 
 
+iota_treasury_cap: coin::TreasuryCap<iota::IOTA> +
+
+ The IOTA's TreasuryCap. +
+
validators: validator_set::ValidatorSet
@@ -413,6 +419,12 @@ Uses SystemParametersV2 as the parameters. we know what version it is by inspecting IotaSystemStateInner as well.
+iota_treasury_cap: coin::TreasuryCap<iota::IOTA> +
+
+ The IOTA's TreasuryCap. +
+
validators: validator_set::ValidatorSet
@@ -741,7 +753,7 @@ Create a new IotaSystemState object and make it shared. This function will be called only once in genesis. -
public(friend) fun create(validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
+
public(friend) fun create(iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
 
@@ -751,6 +763,7 @@ This function will be called only once in genesis.
public(package) fun create(
+    iota_treasury_cap: TreasuryCap<IOTA>,
     validators: vector<Validator>,
     initial_storage_fund: Balance<IOTA>,
     protocol_version: u64,
@@ -766,6 +779,7 @@ This function will be called only once in genesis.
         epoch: 0,
         protocol_version,
         system_state_version: genesis_system_state_version(),
+        iota_treasury_cap,
         validators,
         storage_fund: storage_fund::new(initial_storage_fund),
         parameters,
@@ -852,6 +866,7 @@ This function will be called only once in genesis.
         epoch,
         protocol_version,
         system_state_version: _,
+        iota_treasury_cap,
         validators,
         storage_fund,
         parameters,
@@ -880,6 +895,7 @@ This function will be called only once in genesis.
         epoch,
         protocol_version,
         system_state_version: 2,
+        iota_treasury_cap,
         validators,
         storage_fund,
         parameters: SystemParametersV2 {
diff --git a/crates/iota-framework/packages/iota-framework/sources/iota.move b/crates/iota-framework/packages/iota-framework/sources/iota.move
index e2ceb1fe3fc..96ff58c7c2a 100644
--- a/crates/iota-framework/packages/iota-framework/sources/iota.move
+++ b/crates/iota-framework/packages/iota-framework/sources/iota.move
@@ -6,7 +6,7 @@
 /// It has 9 decimals, and the smallest unit (10^-9) is called "micros".
 module iota::iota {
     use iota::balance::Balance;
-    use iota::coin;
+    use iota::coin::{Self, TreasuryCap};
 
     const EAlreadyMinted: u64 = 0;
     /// Sender is not @0x0 the system address.
@@ -28,9 +28,9 @@ module iota::iota {
     public struct IOTA has drop {}
 
     #[allow(unused_function)]
-    /// Register the `IOTA` Coin to acquire its `Supply`.
+    /// Register the `IOTA` Coin to acquire its `TreasuryCap`.
     /// This should be called only once during genesis creation.
-    fun new(ctx: &mut TxContext): Balance {
+    fun new(ctx: &mut TxContext): TreasuryCap {
         assert!(ctx.sender() == @0x0, ENotSystemAddress);
         assert!(ctx.epoch() == 0, EAlreadyMinted);
 
@@ -44,11 +44,20 @@ module iota::iota {
             option::none(),
             ctx
         );
+
         transfer::public_freeze_object(metadata);
-        let mut supply = treasury.treasury_into_supply();
-        let total_iota = supply.increase_supply(TOTAL_SUPPLY_MICROS);
-        supply.destroy_supply();
-        total_iota
+
+        treasury
+    }
+
+    #[allow(unused_function)]
+    /// Increase the IOTA supply.
+    /// This should be called only once during genesis creation.
+    fun increase_supply(cap: &mut TreasuryCap, ctx: &TxContext): Balance {
+        assert!(ctx.sender() == @0x0, ENotSystemAddress);
+        assert!(ctx.epoch() == 0, EAlreadyMinted);
+
+        cap.supply_mut().increase_supply(TOTAL_SUPPLY_MICROS)
     }
 
     public entry fun transfer(c: coin::Coin, recipient: address) {
diff --git a/crates/iota-framework/packages/iota-system/sources/genesis.move b/crates/iota-framework/packages/iota-system/sources/genesis.move
index 68133f283a7..b669b58398c 100644
--- a/crates/iota-framework/packages/iota-system/sources/genesis.move
+++ b/crates/iota-framework/packages/iota-system/sources/genesis.move
@@ -5,6 +5,7 @@
 module iota_system::genesis {
 
     use iota::balance::{Self, Balance};
+    use iota::coin::TreasuryCap;
     use iota::iota::{Self, IOTA};
     use iota_system::iota_system;
     use iota_system::validator::{Self, Validator};
@@ -79,6 +80,7 @@ module iota_system::genesis {
     /// all the information we need in the system.
     fun create(
         iota_system_state_id: UID,
+        iota_treasury_cap: TreasuryCap,
         mut iota_supply: Balance,
         genesis_chain_parameters: GenesisChainParameters,
         genesis_validators: vector,
@@ -184,6 +186,7 @@ module iota_system::genesis {
 
         iota_system::create(
             iota_system_state_id,
+            iota_treasury_cap,
             validators,
             storage_fund,
             genesis_chain_parameters.protocol_version,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move
index 9906271b539..4f01e7cf08f 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move
@@ -42,7 +42,7 @@
 module iota_system::iota_system {
     use iota::balance::Balance;
 
-    use iota::coin::Coin;
+    use iota::coin::{Coin, TreasuryCap};
     use iota_system::staking_pool::StakedIota;
     use iota::iota::IOTA;
     use iota::table::Table;
@@ -78,6 +78,7 @@ module iota_system::iota_system {
     /// This function will be called only once in genesis.
     public(package) fun create(
         id: UID,
+        iota_treasury_cap: TreasuryCap,
         validators: vector,
         storage_fund: Balance,
         protocol_version: u64,
@@ -87,6 +88,7 @@ module iota_system::iota_system {
         ctx: &mut TxContext,
     ) {
         let system_state = iota_system_state_inner::create(
+            iota_treasury_cap,
             validators,
             storage_fund,
             protocol_version,
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index f4270501b06..ceaf0a25532 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -4,7 +4,7 @@
 
 module iota_system::iota_system_state_inner {
     use iota::balance::{Self, Balance};
-    use iota::coin::Coin;
+    use iota::coin::{Coin, TreasuryCap};
     use iota_system::staking_pool::{stake_activation_epoch, StakedIota};
     use iota::iota::IOTA;
     use iota_system::validator::{Self, Validator};
@@ -110,6 +110,8 @@ module iota_system::iota_system_state_inner {
         /// This is always the same as IotaSystemState.version. Keeping a copy here so that
         /// we know what version it is by inspecting IotaSystemStateInner as well.
         system_state_version: u64,
+        /// The IOTA's TreasuryCap.
+        iota_treasury_cap: TreasuryCap,
         /// Contains all information about the validators.
         validators: ValidatorSet,
         /// The storage fund.
@@ -158,6 +160,8 @@ module iota_system::iota_system_state_inner {
         /// This is always the same as IotaSystemState.version. Keeping a copy here so that
         /// we know what version it is by inspecting IotaSystemStateInner as well.
         system_state_version: u64,
+        /// The IOTA's TreasuryCap.
+        iota_treasury_cap: TreasuryCap,
         /// Contains all information about the validators.
         validators: ValidatorSet,
         /// The storage fund.
@@ -232,6 +236,7 @@ module iota_system::iota_system_state_inner {
     /// Create a new IotaSystemState object and make it shared.
     /// This function will be called only once in genesis.
     public(package) fun create(
+        iota_treasury_cap: TreasuryCap,
         validators: vector,
         initial_storage_fund: Balance,
         protocol_version: u64,
@@ -247,6 +252,7 @@ module iota_system::iota_system_state_inner {
             epoch: 0,
             protocol_version,
             system_state_version: genesis_system_state_version(),
+            iota_treasury_cap,
             validators,
             storage_fund: storage_fund::new(initial_storage_fund),
             parameters,
@@ -293,6 +299,7 @@ module iota_system::iota_system_state_inner {
             epoch,
             protocol_version,
             system_state_version: _,
+            iota_treasury_cap,
             validators,
             storage_fund,
             parameters,
@@ -321,6 +328,7 @@ module iota_system::iota_system_state_inner {
             epoch,
             protocol_version,
             system_state_version: 2,
+            iota_treasury_cap,
             validators,
             storage_fund,
             parameters: SystemParametersV2 {
diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
index 327418973ac..004f7eaec8d 100644
--- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
+++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move
@@ -83,6 +83,7 @@ module iota_system::governance_test_utils {
 
         iota_system::create(
             object::new(ctx), // it doesn't matter what ID iota system state has in tests
+            coin::create_treasury_cap_for_testing(ctx),
             validators,
             balance::create_for_testing(storage_fund_amount * MICROS_PER_IOTA), // storage_fund
             1,   // protocol version
diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs
index adec4c5f7c2..36613b7de5a 100644
--- a/crates/iota-genesis-builder/src/lib.rs
+++ b/crates/iota-genesis-builder/src/lib.rs
@@ -46,7 +46,7 @@ use iota_types::{
     transaction::{
         CallArg, CheckedInputObjects, Command, InputObjectKind, ObjectReadResult, Transaction,
     },
-    IOTA_FRAMEWORK_ADDRESS, IOTA_SYSTEM_ADDRESS,
+    IOTA_FRAMEWORK_PACKAGE_ID, IOTA_SYSTEM_ADDRESS,
 };
 use move_binary_format::CompiledModule;
 use move_core_types::ident_str;
@@ -1060,7 +1060,7 @@ pub fn generate_genesis_system_object(
         let mut builder = ProgrammableTransactionBuilder::new();
         // Step 1: Create the IotaSystemState UID
         let iota_system_state_uid = builder.programmable_move_call(
-            IOTA_FRAMEWORK_ADDRESS.into(),
+            IOTA_FRAMEWORK_PACKAGE_ID,
             ident_str!("object").to_owned(),
             ident_str!("iota_system_state").to_owned(),
             vec![],
@@ -1069,7 +1069,7 @@ pub fn generate_genesis_system_object(
 
         // Step 2: Create and share the Clock.
         builder.move_call(
-            IOTA_FRAMEWORK_ADDRESS.into(),
+            IOTA_FRAMEWORK_PACKAGE_ID,
             ident_str!("clock").to_owned(),
             ident_str!("create").to_owned(),
             vec![],
@@ -1080,7 +1080,7 @@ pub fn generate_genesis_system_object(
         // (which only happens in tests).
         if protocol_config.create_authenticator_state_in_genesis() {
             builder.move_call(
-                IOTA_FRAMEWORK_ADDRESS.into(),
+                IOTA_FRAMEWORK_PACKAGE_ID,
                 ident_str!("authenticator_state").to_owned(),
                 ident_str!("create").to_owned(),
                 vec![],
@@ -1089,7 +1089,7 @@ pub fn generate_genesis_system_object(
         }
         if protocol_config.random_beacon() {
             builder.move_call(
-                IOTA_FRAMEWORK_ADDRESS.into(),
+                IOTA_FRAMEWORK_PACKAGE_ID,
                 ident_str!("random").to_owned(),
                 ident_str!("create").to_owned(),
                 vec![],
@@ -1098,7 +1098,7 @@ pub fn generate_genesis_system_object(
         }
         if protocol_config.enable_coin_deny_list() {
             builder.move_call(
-                IOTA_FRAMEWORK_ADDRESS.into(),
+                IOTA_FRAMEWORK_PACKAGE_ID,
                 DENY_LIST_MODULE.to_owned(),
                 DENY_LIST_CREATE_FUNC.to_owned(),
                 vec![],
@@ -1106,19 +1106,38 @@ pub fn generate_genesis_system_object(
             )?;
         }
 
-        // Step 4: Mint the supply of IOTA.
-        let iota_supply = builder.programmable_move_call(
-            IOTA_FRAMEWORK_ADDRESS.into(),
+        // Step 4: Create the IOTA Coin.
+        let iota_treasury_cap = builder.programmable_move_call(
+            IOTA_FRAMEWORK_PACKAGE_ID,
             ident_str!("iota").to_owned(),
             ident_str!("new").to_owned(),
             vec![],
             vec![],
         );
+        let total_iota = builder.programmable_move_call(
+            IOTA_FRAMEWORK_PACKAGE_ID,
+            ident_str!("iota").to_owned(),
+            ident_str!("increase_supply").to_owned(),
+            vec![],
+            vec![iota_treasury_cap],
+        );
+        // TODO:
+        // IOTA supply that already distributed to the users needs to be burned here
+        // or inside the `genesis::new` function.
+        // Rename the `destroy_storage_rebates` function or create a specific one.
+
+        // builder.programmable_move_call(
+        //     IOTA_FRAMEWORK_PACKAGE_ID,
+        //     BALANCE_MODULE_NAME.to_owned(),
+        //     BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(),
+        //     vec![GAS::type_tag()],
+        //     vec![total_iota],
+        // );
 
         // Step 5: Run genesis.
         // The first argument is the system state uid we got from step 1 and the second
-        // one is the IOTA supply we got from step 3.
-        let mut arguments = vec![iota_system_state_uid, iota_supply];
+        // one is the IOTA `TreasuryCap` we got from step 4.
+        let mut arguments = vec![iota_system_state_uid, iota_treasury_cap, total_iota];
         let mut call_arg_arguments = vec![
             CallArg::Pure(bcs::to_bytes(&genesis_chain_parameters).unwrap()),
             CallArg::Pure(bcs::to_bytes(&genesis_validators).unwrap()),

From d336e71b3c1ffe1e2c2d8cad62eef3f168b7488b Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Thu, 20 Jun 2024 12:47:26 +0300
Subject: [PATCH 03/35] fix(iota-framework): fixed lock files

---
 .../iota-framework/packages/iota-system/Move.lock  | 12 ++++++------
 crates/iota-framework/packages/timelock/Move.lock  | 14 +++++++-------
 2 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/crates/iota-framework/packages/iota-system/Move.lock b/crates/iota-framework/packages/iota-system/Move.lock
index 9128d14190f..f01fb34d06f 100644
--- a/crates/iota-framework/packages/iota-system/Move.lock
+++ b/crates/iota-framework/packages/iota-system/Move.lock
@@ -2,18 +2,14 @@
 
 [move]
 version = 1
-manifest_digest = "68AEB9354EE1D616F6D2293EC721FE3D7E810FEC4FE34197676ECFA3DA72CAE3"
+manifest_digest = "4B3F098CD3A1E550ED834159EF4E2978435F6159F321C7143AD27440B6A74BDC"
 deps_digest = "3C4103934B1E040BB6B23F1D610B4EF9F2F1166A50A104EADCF77467C004C600"
 
 dependencies = [
-  { name = "MoveStdlib" },
   { name = "Iota" },
+  { name = "MoveStdlib" },
 ]
 
-[[move.package]]
-name = "MoveStdlib"
-source = { local = "../move-stdlib" }
-
 [[move.package]]
 name = "Iota"
 source = { local = "../iota-framework" }
@@ -22,6 +18,10 @@ dependencies = [
   { name = "MoveStdlib" },
 ]
 
+[[move.package]]
+name = "MoveStdlib"
+source = { local = "../move-stdlib" }
+
 [move.toolchain-version]
 compiler-version = "1.22.0"
 edition = "legacy"
diff --git a/crates/iota-framework/packages/timelock/Move.lock b/crates/iota-framework/packages/timelock/Move.lock
index 8b1cce8f075..55ca30934e4 100644
--- a/crates/iota-framework/packages/timelock/Move.lock
+++ b/crates/iota-framework/packages/timelock/Move.lock
@@ -2,18 +2,14 @@
 
 [move]
 version = 1
-manifest_digest = "F7B0657885F7F095E7ED4AC0F6A8772A191E3257D870D1C8A0DD84BFD1BE32E8"
+manifest_digest = "B70A186772DD522A8D8DC380E7217B09F79FE8D34CB09A27CD39E5FFA487CA30"
 deps_digest = "060AD7E57DFB13104F21BE5F5C3759D03F0553FC3229247D9A7A6B45F50D03A3"
 dependencies = [
-  { name = "MoveStdlib" },
   { name = "Iota" },
   { name = "IotaSystem" },
+  { name = "MoveStdlib" },
 ]
 
-[[move.package]]
-name = "MoveStdlib"
-source = { local = "../move-stdlib" }
-
 [[move.package]]
 name = "Iota"
 source = { local = "../iota-framework" }
@@ -27,10 +23,14 @@ name = "IotaSystem"
 source = { local = "../iota-system" }
 
 dependencies = [
-  { name = "MoveStdlib" },
   { name = "Iota" },
+  { name = "MoveStdlib" },
 ]
 
+[[move.package]]
+name = "MoveStdlib"
+source = { local = "../move-stdlib" }
+
 [move.toolchain-version]
 compiler-version = "1.22.0"
 edition = "legacy"

From 792afc1a229403b2ff44f44620fa0ccc62a4e8e7 Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Thu, 20 Jun 2024 14:14:51 +0300
Subject: [PATCH 04/35] feat(iota-config): turn off stake subsidy by changing
 default params

---
 crates/iota-config/src/genesis.rs | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/crates/iota-config/src/genesis.rs b/crates/iota-config/src/genesis.rs
index 25fcd846d99..369830fc80f 100644
--- a/crates/iota-config/src/genesis.rs
+++ b/crates/iota-config/src/genesis.rs
@@ -434,18 +434,20 @@ impl GenesisCeremonyParameters {
     }
 
     fn default_initial_stake_subsidy_distribution_amount() -> u64 {
-        // 1M Iota
-        1_000_000 * iota_types::gas_coin::MICROS_PER_IOTA
+        // 0 IOTA in micros
+        0
     }
 
     fn default_stake_subsidy_period_length() -> u64 {
+        // TODO: can this param be set to u64::MAX?
+
         // 10 distributions or epochs
         10
     }
 
     fn default_stake_subsidy_decrease_rate() -> u16 {
-        // 10% in basis points
-        1000
+        // 0% in basis points. for example, should be equal to 1000 to represent 10%.
+        0
     }
 
     pub fn to_genesis_chain_parameters(&self) -> GenesisChainParameters {
@@ -476,6 +478,8 @@ impl Default for GenesisCeremonyParameters {
     }
 }
 
+// TODO: TOTAL_SUPPLY_MICROS should not be used for allocation and validation
+// directly.
 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 #[serde(rename_all = "kebab-case")]
 pub struct TokenDistributionSchedule {

From 55cd94c69c8caf601a644b37bbfa5b901c13c169 Mon Sep 17 00:00:00 2001
From: Valerii Reutov 
Date: Fri, 21 Jun 2024 11:31:36 +0300
Subject: [PATCH 05/35] feat(iota-framework): added IOTA burn/mint functions

---
 .../iota-system/iota_system_state_inner.md    | 56 +++++++++++++++++++
 .../sources/iota_system_state_inner.move      | 20 ++++++-
 2 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index d9229cd6374..e3bdedc8f91 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -62,6 +62,8 @@ title: Module `0x3::iota_system_state_inner`
 -  [Function `pool_exchange_rates`](#0x3_iota_system_state_inner_pool_exchange_rates)
 -  [Function `active_validator_addresses`](#0x3_iota_system_state_inner_active_validator_addresses)
 -  [Function `extract_coin_balance`](#0x3_iota_system_state_inner_extract_coin_balance)
+-  [Function `mint_iota`](#0x3_iota_system_state_inner_mint_iota)
+-  [Function `burn_iota`](#0x3_iota_system_state_inner_burn_iota)
 
 
 
use 0x1::option;
@@ -2610,4 +2612,58 @@ Extract required Balance from vector of Coin, transfer the remainder back
 
 
 
+
+ + + +## Function `mint_iota` + +Mint some amount of IOTA as a Balance. + + +
fun mint_iota(cap: &mut coin::TreasuryCap<iota::IOTA>, value: u64, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
+
+ + + +
+Implementation + + +
fun mint_iota(cap: &mut TreasuryCap<IOTA>, value: u64, ctx: &TxContext): Balance<IOTA> {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    coin::mint_balance(cap, value)
+}
+
+ + + +
+ + + +## Function `burn_iota` + +Destroy the balance balance and decrease the total supply of IOTA. + + +
fun burn_iota(cap: &mut coin::TreasuryCap<iota::IOTA>, balance: balance::Balance<iota::IOTA>, ctx: &tx_context::TxContext): u64
+
+ + + +
+Implementation + + +
fun burn_iota(cap: &mut TreasuryCap<IOTA>, balance: Balance<IOTA>, ctx: &TxContext): u64 {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+
+    cap.supply_mut().decrease_supply(balance)
+}
+
+ + +
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index ceaf0a25532..7bb7cec2af6 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -4,7 +4,7 @@ module iota_system::iota_system_state_inner { use iota::balance::{Self, Balance}; - use iota::coin::{Coin, TreasuryCap}; + use iota::coin::{Self, Coin, TreasuryCap}; use iota_system::staking_pool::{stake_activation_epoch, StakedIota}; use iota::iota::IOTA; use iota_system::validator::{Self, Validator}; @@ -1160,4 +1160,22 @@ module iota_system::iota_system_state_inner { self.validators.request_add_validator_candidate(validator, ctx); } + // TODO: Can be considered an option to wrap IOTA's `TreasuryCap` to + // make it impossible to mint/burn IOTAs through the standard functions. + + #[allow(unused_function)] + /// Mint some amount of IOTA as a `Balance`. + fun mint_iota(cap: &mut TreasuryCap, value: u64, ctx: &TxContext): Balance { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + coin::mint_balance(cap, value) + } + + #[allow(unused_function)] + /// Destroy the balance `balance` and decrease the total supply of IOTA. + fun burn_iota(cap: &mut TreasuryCap, balance: Balance, ctx: &TxContext): u64 { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + + cap.supply_mut().decrease_supply(balance) + } } From 33297be2b5d6d2e48495b50c5b342d1fc735c50f Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 25 Jun 2024 15:44:04 +0200 Subject: [PATCH 06/35] feat: Remove parts of stake subsidy fund --- .../sources/iota_system_state_inner.move | 4 +-- .../iota-system/tests/iota_system_tests.move | 30 ------------------- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index 7bb7cec2af6..267a2aba5ea 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -837,7 +837,6 @@ module iota_system::iota_system_state_inner { epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, ) : Balance { - let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms; self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64; @@ -951,7 +950,8 @@ module iota_system::iota_system_state_inner { storage_fund_reinvestment: storage_fund_reinvestment_amount as u64, storage_rebate: storage_rebate_amount, storage_fund_balance: self.storage_fund.total_balance(), - stake_subsidy_amount, + // TODO: Remove + stake_subsidy_amount: 0, total_gas_fees: computation_charge, total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed, leftover_storage_fund_inflow, diff --git a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move index 0761eab8301..4a7ecd08f90 100644 --- a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move @@ -973,34 +973,4 @@ module iota_system::iota_system_tests { test_scenario::return_shared(system_state); scenario_val.end(); } - - #[test] - fun test_skip_stake_subsidy() { - let mut scenario_val = test_scenario::begin(@0x0); - let scenario = &mut scenario_val; - // Epoch duration is set to be 42 here. - set_up_iota_system_state(vector[@0x1, @0x2]); - - // If the epoch length is less than 42 then the stake subsidy distribution counter should not be incremented. Otherwise it should. - advance_epoch_and_check_distribution_counter(scenario, 42, true); - advance_epoch_and_check_distribution_counter(scenario, 32, false); - advance_epoch_and_check_distribution_counter(scenario, 52, true); - scenario_val.end(); - } - - fun advance_epoch_and_check_distribution_counter(scenario: &mut Scenario, epoch_length: u64, should_increment_counter: bool) { - scenario.next_tx(@0x0); - let new_epoch = scenario.ctx().epoch() + 1; - let mut system_state = scenario.take_shared(); - let prev_epoch_time = system_state.epoch_start_timestamp_ms(); - let prev_counter = system_state.get_stake_subsidy_distribution_counter(); - - let rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, 0, 0, 0, 0, 0, 0, prev_epoch_time + epoch_length, scenario.ctx() - ); - destroy(rebate); - assert_eq(system_state.get_stake_subsidy_distribution_counter(), prev_counter + (if (should_increment_counter) 1 else 0)); - test_scenario::return_shared(system_state); - scenario.next_epoch(@0x0); - } } From 68b87c17068c556b8d3db96cc32a5fc797749e1c Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 25 Jun 2024 15:49:27 +0200 Subject: [PATCH 07/35] feat: Implement increase/decrease supply based on target reward --- .../docs/iota-system/iota_system.md | 4 ++- .../iota-system/iota_system_state_inner.md | 34 +++++++++---------- .../iota-system/sources/iota_system.move | 4 +++ .../sources/iota_system_state_inner.move | 28 +++++++-------- .../tests/governance_test_utils.move | 5 +-- .../iota-system/tests/iota_system_tests.move | 2 +- 6 files changed, 42 insertions(+), 35 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md index 0d030e5f8a8..e4d8ae69993 100644 --- a/crates/iota-framework/docs/iota-system/iota_system.md +++ b/crates/iota-framework/docs/iota-system/iota_system.md @@ -1362,7 +1362,7 @@ gas coins. 4. Update all validators. -
fun advance_epoch(storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
fun advance_epoch(validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -1372,6 +1372,7 @@ gas coins.
fun advance_epoch(
+    validator_target_reward: u64,
     storage_reward: Balance<IOTA>,
     computation_reward: Balance<IOTA>,
     wrapper: &mut IotaSystemState,
@@ -1391,6 +1392,7 @@ gas coins.
     let storage_rebate = self.advance_epoch(
         new_epoch,
         next_protocol_version,
+        validator_target_reward,
         storage_reward,
         computation_reward,
         storage_rebate,
diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
index e3bdedc8f91..5c3832e6efd 100644
--- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
+++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md
@@ -2078,7 +2078,7 @@ gas coins.
 4. Update all validators.
 
 
-
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -2091,6 +2091,7 @@ gas coins. self: &mut IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, + validator_target_reward: u64, mut storage_reward: Balance<IOTA>, mut computation_reward: Balance<IOTA>, mut storage_rebate_amount: u64, @@ -2101,7 +2102,6 @@ gas coins. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, ) : Balance<IOTA> { - let prev_epoch_start_timestamp = self.epoch_start_timestamp_ms; self.epoch_start_timestamp_ms = epoch_start_timestamp_ms; let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64; @@ -2134,20 +2134,19 @@ gas coins. let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); - // Include stake subsidy in the rewards given out to validators and stakers. - // Delay distributing any stake subsidies until after `stake_subsidy_start_epoch`. - // And if this epoch is shorter than the regular epoch duration, don't distribute any stake subsidy. - let stake_subsidy = - if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch && - epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms) - { - self.stake_subsidy.advance_epoch() - } else { - balance::zero() - }; - - let stake_subsidy_amount = stake_subsidy.value(); - computation_reward.join(stake_subsidy); + let mut computation_reward = if (computation_reward.value() < validator_target_reward) { + let tokens_to_mint = validator_target_reward - computation_reward.value(); + let new_tokens = self.iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint); + computation_reward.join(new_tokens); + computation_reward + } else if (computation_reward.value() > validator_target_reward) { + let tokens_to_burn = computation_reward.value() - validator_target_reward; + let rewards_to_burn = computation_reward.split(tokens_to_burn); + self.iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn); + computation_reward + } else { + computation_reward + }; let total_stake_u128 = total_stake as u128; let computation_charge_u128 = computation_charge as u128; @@ -2215,7 +2214,8 @@ gas coins. storage_fund_reinvestment: storage_fund_reinvestment_amount as u64, storage_rebate: storage_rebate_amount, storage_fund_balance: self.storage_fund.total_balance(), - stake_subsidy_amount, + // TODO: Remove + stake_subsidy_amount: 0, total_gas_fees: computation_charge, total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed, leftover_storage_fund_inflow, diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move index 4f01e7cf08f..471a3b877bb 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move @@ -538,6 +538,7 @@ module iota_system::iota_system { /// 3. Distribute computation charge to validator stake. /// 4. Update all validators. fun advance_epoch( + validator_target_reward: u64, storage_reward: Balance, computation_reward: Balance, wrapper: &mut IotaSystemState, @@ -557,6 +558,7 @@ module iota_system::iota_system { let storage_rebate = self.advance_epoch( new_epoch, next_protocol_version, + validator_target_reward, storage_reward, computation_reward, storage_rebate, @@ -746,6 +748,7 @@ module iota_system::iota_system { wrapper: &mut IotaSystemState, new_epoch: u64, next_protocol_version: u64, + validator_target_reward: u64, storage_charge: u64, computation_charge: u64, storage_rebate: u64, @@ -758,6 +761,7 @@ module iota_system::iota_system { let storage_reward = balance::create_for_testing(storage_charge); let computation_reward = balance::create_for_testing(computation_charge); let storage_rebate = advance_epoch( + validator_target_reward, storage_reward, computation_reward, wrapper, diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index 267a2aba5ea..7c5df343bb4 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -827,6 +827,7 @@ module iota_system::iota_system_state_inner { self: &mut IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, + validator_target_reward: u64, mut storage_reward: Balance, mut computation_reward: Balance, mut storage_rebate_amount: u64, @@ -869,20 +870,19 @@ module iota_system::iota_system_state_inner { let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); - // Include stake subsidy in the rewards given out to validators and stakers. - // Delay distributing any stake subsidies until after `stake_subsidy_start_epoch`. - // And if this epoch is shorter than the regular epoch duration, don't distribute any stake subsidy. - let stake_subsidy = - if (ctx.epoch() >= self.parameters.stake_subsidy_start_epoch && - epoch_start_timestamp_ms >= prev_epoch_start_timestamp + self.parameters.epoch_duration_ms) - { - self.stake_subsidy.advance_epoch() - } else { - balance::zero() - }; - - let stake_subsidy_amount = stake_subsidy.value(); - computation_reward.join(stake_subsidy); + let mut computation_reward = if (computation_reward.value() < validator_target_reward) { + let tokens_to_mint = validator_target_reward - computation_reward.value(); + let new_tokens = self.iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint); + computation_reward.join(new_tokens); + computation_reward + } else if (computation_reward.value() > validator_target_reward) { + let tokens_to_burn = computation_reward.value() - validator_target_reward; + let rewards_to_burn = computation_reward.split(tokens_to_burn); + self.iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn); + computation_reward + } else { + computation_reward + }; let total_stake_u128 = total_stake as u128; let computation_charge_u128 = computation_charge as u128; diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move index 004f7eaec8d..1c7742efb73 100644 --- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move +++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move @@ -123,7 +123,7 @@ module iota_system::governance_test_utils { let ctx = scenario.ctx(); let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx, + new_epoch, 1, computation_charge, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx, ); test_scenario::return_shared(system_state); scenario.next_epoch(@0x0); @@ -149,8 +149,9 @@ module iota_system::governance_test_utils { let ctx = scenario.ctx(); + let validator_target_reward = computation_charge * MICROS_PER_IOTA; let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, 0, reward_slashing_rate, 0, ctx + new_epoch, 1, validator_target_reward, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, 0, reward_slashing_rate, 0, ctx ); test_utils::destroy(storage_rebate); test_scenario::return_shared(system_state); diff --git a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move index 4a7ecd08f90..384f551d2b9 100644 --- a/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move @@ -17,7 +17,7 @@ module iota_system::iota_system_tests { use iota_system::validator_set; use iota_system::validator_cap::UnverifiedValidatorOperationCap; use iota::balance; - use iota::test_utils::{assert_eq, destroy}; + use iota::test_utils::assert_eq; use iota::url; #[test] From e67f56fbbe92bab0fc5f1429d85afa08f79b370e Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 25 Jun 2024 16:20:08 +0200 Subject: [PATCH 08/35] feat: Add validator_target_reward and pass to advance_epoch --- crates/iota-protocol-config/src/lib.rs | 6 ++++++ crates/iota-types/src/iota_system_state/mod.rs | 1 + .../latest/iota-adapter/src/execution_engine.rs | 9 ++++++++- iota-execution/v0/iota-adapter/src/execution_engine.rs | 1 + iota-execution/v1/iota-adapter/src/execution_engine.rs | 1 + iota-execution/v2/iota-adapter/src/execution_engine.rs | 1 + 6 files changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/iota-protocol-config/src/lib.rs b/crates/iota-protocol-config/src/lib.rs index c5da2630520..d0fc4cd4741 100644 --- a/crates/iota-protocol-config/src/lib.rs +++ b/crates/iota-protocol-config/src/lib.rs @@ -659,6 +659,10 @@ pub struct ProtocolConfig { /// Unit gas price, Micros per internal gas unit. storage_gas_price: Option, + /// The number of tokens that validators should receive per epoch when + /// performing optimally. + validator_target_reward: Option, + /// === Core Protocol === /// Max number of transactions per checkpoint. @@ -1362,6 +1366,8 @@ impl ProtocolConfig { // Change reward slashing rate to 100%. reward_slashing_rate: Some(10000), storage_gas_price: Some(76), + // 767k IOTAs. + validator_target_reward: Some(767_000 * 1_000_000_000), max_transactions_per_checkpoint: Some(10_000), max_checkpoint_size_bytes: Some(30 * 1024 * 1024), diff --git a/crates/iota-types/src/iota_system_state/mod.rs b/crates/iota-types/src/iota_system_state/mod.rs index df1fb87e8b5..aa220da3ea1 100644 --- a/crates/iota-types/src/iota_system_state/mod.rs +++ b/crates/iota-types/src/iota_system_state/mod.rs @@ -441,6 +441,7 @@ pub struct AdvanceEpochParams { pub epoch: u64, pub next_protocol_version: ProtocolVersion, pub storage_charge: u64, + pub validator_target_reward: u64, pub computation_charge: u64, pub storage_rebate: u64, pub non_refundable_storage_fee: u64, diff --git a/iota-execution/latest/iota-adapter/src/execution_engine.rs b/iota-execution/latest/iota-adapter/src/execution_engine.rs index 124863e97ac..fb39c72e47a 100644 --- a/iota-execution/latest/iota-adapter/src/execution_engine.rs +++ b/iota-execution/latest/iota-adapter/src/execution_engine.rs @@ -716,7 +716,13 @@ mod checked { let (storage_rewards, computation_rewards) = mint_epoch_rewards_in_pt(&mut builder, params); // Step 2: Advance the epoch. - let mut arguments = vec![storage_rewards, computation_rewards]; + let mut arguments = vec![ + builder + .input(CallArg::Pure(bcs::to_bytes(¶ms.validator_target_reward).unwrap())) + .expect("builder input on pure call arg should not fail"), + storage_rewards, + computation_rewards, + ]; let call_arg_arguments = vec![ CallArg::IOTA_SYSTEM_MUT, CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()), @@ -822,6 +828,7 @@ mod checked { let params = AdvanceEpochParams { epoch: change_epoch.epoch, next_protocol_version: change_epoch.protocol_version, + validator_target_reward: protocol_config.validator_target_reward(), storage_charge: change_epoch.storage_charge, computation_charge: change_epoch.computation_charge, storage_rebate: change_epoch.storage_rebate, diff --git a/iota-execution/v0/iota-adapter/src/execution_engine.rs b/iota-execution/v0/iota-adapter/src/execution_engine.rs index daf4c09674a..c51587d5d47 100644 --- a/iota-execution/v0/iota-adapter/src/execution_engine.rs +++ b/iota-execution/v0/iota-adapter/src/execution_engine.rs @@ -629,6 +629,7 @@ mod checked { let params = AdvanceEpochParams { epoch: change_epoch.epoch, next_protocol_version: change_epoch.protocol_version, + validator_target_reward: 0, storage_charge: change_epoch.storage_charge, computation_charge: change_epoch.computation_charge, storage_rebate: change_epoch.storage_rebate, diff --git a/iota-execution/v1/iota-adapter/src/execution_engine.rs b/iota-execution/v1/iota-adapter/src/execution_engine.rs index 7aaa23f9266..8c8661016f7 100644 --- a/iota-execution/v1/iota-adapter/src/execution_engine.rs +++ b/iota-execution/v1/iota-adapter/src/execution_engine.rs @@ -797,6 +797,7 @@ mod checked { let params = AdvanceEpochParams { epoch: change_epoch.epoch, next_protocol_version: change_epoch.protocol_version, + validator_target_reward: 0, storage_charge: change_epoch.storage_charge, computation_charge: change_epoch.computation_charge, storage_rebate: change_epoch.storage_rebate, diff --git a/iota-execution/v2/iota-adapter/src/execution_engine.rs b/iota-execution/v2/iota-adapter/src/execution_engine.rs index 124863e97ac..951e406bf0b 100644 --- a/iota-execution/v2/iota-adapter/src/execution_engine.rs +++ b/iota-execution/v2/iota-adapter/src/execution_engine.rs @@ -822,6 +822,7 @@ mod checked { let params = AdvanceEpochParams { epoch: change_epoch.epoch, next_protocol_version: change_epoch.protocol_version, + validator_target_reward: 0, storage_charge: change_epoch.storage_charge, computation_charge: change_epoch.computation_charge, storage_rebate: change_epoch.storage_rebate, From c1f310f9a4a729c66bc1117068644e64ac3e561d Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 26 Jun 2024 14:10:31 +0200 Subject: [PATCH 09/35] feat: Test supply change --- .../iota-system/sources/iota_system.move | 6 ++ .../sources/iota_system_state_inner.move | 5 + .../iota-system/tests/delegation_tests.move | 20 ++-- .../tests/governance_test_utils.move | 26 ++++-- .../tests/rewards_distribution_tests.move | 92 +++++++++++++++---- 5 files changed, 114 insertions(+), 35 deletions(-) diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move index 471a3b877bb..ef310fcfc04 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move @@ -700,6 +700,12 @@ module iota_system::iota_system { self.get_stake_subsidy_distribution_counter() } + #[test_only] + public fun get_iota_supply(wrapper: &mut IotaSystemState): u64 { + let self = load_system_state(wrapper); + self.get_total_iota_supply() + } + // CAUTION: THIS CODE IS ONLY FOR TESTING AND THIS MACRO MUST NEVER EVER BE REMOVED. Creates a // candidate validator - bypassing the proof of possession check and other metadata validation // in the process. diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index 7c5df343bb4..44ed1bfbc85 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -1095,6 +1095,11 @@ module iota_system::iota_system_state_inner { self.stake_subsidy.get_distribution_counter() } + #[test_only] + public(package) fun get_total_iota_supply(self: &IotaSystemStateInnerV2): u64 { + self.iota_treasury_cap.total_supply() + } + #[test_only] public(package) fun set_epoch_for_testing(self: &mut IotaSystemStateInnerV2, epoch_num: u64) { self.epoch = epoch_num diff --git a/crates/iota-framework/packages/iota-system/tests/delegation_tests.move b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move index 5cd1118b95f..e98e4bc32eb 100644 --- a/crates/iota-framework/packages/iota-system/tests/delegation_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move @@ -233,7 +233,7 @@ module iota_system::stake_tests { if (should_distribute_rewards) { // Each validator pool gets 30 MICROS and each validator gets an additional 10 MICROS. - advance_epoch_with_reward_amounts(0, 80, scenario); + advance_epoch_with_reward_amounts(80, 0, 80, scenario); } else { advance_epoch(scenario); }; @@ -292,7 +292,7 @@ module iota_system::stake_tests { // Add some rewards after the validator requests to leave. Since the validator is still active // this epoch, they should get the rewards from this epoch. - advance_epoch_with_reward_amounts(0, 80, scenario); + advance_epoch_with_reward_amounts(80, 0, 80, scenario); // Each validator pool gets 30 MICROS and validators shares the 20 MICROS from the storage fund // so validator gets another 10 MICROS. @@ -374,8 +374,8 @@ module iota_system::stake_tests { stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); // Advance epoch twice with some rewards - advance_epoch_with_reward_amounts(0, 400, scenario); - advance_epoch_with_reward_amounts(0, 900, scenario); + advance_epoch_with_reward_amounts(400, 0, 400, scenario); + advance_epoch_with_reward_amounts(900, 0, 900, scenario); // Unstake from the preactive validator. There should be no rewards earned. unstake(STAKER_ADDR_1, 0, scenario); @@ -412,7 +412,7 @@ module iota_system::stake_tests { // Delegate 100 IOTA to the preactive validator stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); - advance_epoch_with_reward_amounts(0, 300, scenario); + advance_epoch_with_reward_amounts(300, 0, 300, scenario); // At this point we got the following distribution of stake: // V1: 250, V2: 250, storage fund: 100 @@ -426,7 +426,7 @@ module iota_system::stake_tests { // At this point we got the following distribution of stake: // V1: 250, V2: 250, V3: 250, storage fund: 100 - advance_epoch_with_reward_amounts(0, 85, scenario); + advance_epoch_with_reward_amounts(85, 0, 85, scenario); // staker 1 and 3 unstake from the validator and earns about 2/5 * (85 - 10) * 1/3 = 10 IOTA each. // Although they stake in different epochs, they earn the same rewards as long as they unstake @@ -437,7 +437,7 @@ module iota_system::stake_tests { unstake(STAKER_ADDR_3, 0, scenario); assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 110002000000); - advance_epoch_with_reward_amounts(0, 85, scenario); + advance_epoch_with_reward_amounts(85, 0, 85, scenario); unstake(STAKER_ADDR_2, 0, scenario); // staker 2 earns about 5 IOTA from the previous epoch and 24-ish from this one // so in total she has about 50 + 5 + 24 = 79 IOTA. @@ -463,7 +463,7 @@ module iota_system::stake_tests { // staker 1 earns a bit greater than 30 IOTA here. A bit greater because the new validator's voting power // is slightly greater than 1/3 of the total voting power. - advance_epoch_with_reward_amounts(0, 90, scenario); + advance_epoch_with_reward_amounts(90, 0, 90, scenario); // And now the validator leaves the validator set. remove_validator(NEW_VALIDATOR_ADDR, scenario); @@ -488,7 +488,7 @@ module iota_system::stake_tests { stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); // Advance epoch and give out some rewards. The candidate should get nothing, of course. - advance_epoch_with_reward_amounts(0, 800, scenario); + advance_epoch_with_reward_amounts(800, 0, 800, scenario); // Now the candidate leaves. remove_validator_candidate(NEW_VALIDATOR_ADDR, scenario); @@ -517,7 +517,7 @@ module iota_system::stake_tests { test_scenario::return_to_address(@0x42, staked_iota); advance_epoch(scenario); // advances epoch to effectuate the stake // Each staking pool gets 10 IOTA of rewards. - advance_epoch_with_reward_amounts(0, 20, scenario); + advance_epoch_with_reward_amounts(20, 0, 20, scenario); let mut system_state = scenario.take_shared(); let rates = system_state.pool_exchange_rates(&pool_id); assert_eq(rates.length(), 3); diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move index 1c7742efb73..028e612c7da 100644 --- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move +++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move @@ -81,9 +81,15 @@ module iota_system::governance_test_utils { ctx, ); + // We initialize the total supply to the given test value but we destroy the + // supply balance since we will recreate balances for testing out of thin air. + let mut iota_treasury_cap = coin::create_treasury_cap_for_testing(ctx); + let supply = iota_treasury_cap.supply_mut().increase_supply(iota_supply_amount * MICROS_PER_IOTA); + balance::destroy_for_testing(supply); + iota_system::create( object::new(ctx), // it doesn't matter what ID iota system state has in tests - coin::create_treasury_cap_for_testing(ctx), + iota_treasury_cap, validators, balance::create_for_testing(storage_fund_amount * MICROS_PER_IOTA), // storage_fund 1, // protocol version @@ -110,11 +116,11 @@ module iota_system::governance_test_utils { } public fun advance_epoch(scenario: &mut Scenario) { - advance_epoch_with_reward_amounts(0, 0, scenario); + advance_epoch_with_reward_amounts(0, 0, 0, scenario); } public fun advance_epoch_with_reward_amounts_return_rebate( - storage_charge: u64, computation_charge: u64, stoarge_rebate: u64, non_refundable_storage_rebate: u64, scenario: &mut Scenario, + validator_target_reward: u64, storage_charge: u64, computation_charge: u64, stoarge_rebate: u64, non_refundable_storage_rebate: u64, scenario: &mut Scenario, ): Balance { scenario.next_tx(@0x0); let new_epoch = scenario.ctx().epoch() + 1; @@ -123,7 +129,7 @@ module iota_system::governance_test_utils { let ctx = scenario.ctx(); let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, computation_charge, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx, + new_epoch, 1, validator_target_reward, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx, ); test_scenario::return_shared(system_state); scenario.next_epoch(@0x0); @@ -131,9 +137,9 @@ module iota_system::governance_test_utils { } public fun advance_epoch_with_reward_amounts( - storage_charge: u64, computation_charge: u64, scenario: &mut Scenario + validator_target_reward: u64, storage_charge: u64, computation_charge: u64, scenario: &mut Scenario ) { - let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, scenario); + let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(validator_target_reward * MICROS_PER_IOTA, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, scenario); test_utils::destroy(storage_rebate) } @@ -342,4 +348,12 @@ module iota_system::governance_test_utils { }; sum } + + /// Returns the total IOTA supply in the system state. + public fun total_supply(scenario: &mut Scenario): u64 { + let mut system_state = scenario.take_shared(); + let total_supply = system_state.get_iota_supply(); + test_scenario::return_shared(system_state); + total_supply + } } diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move index 11c6fa0d8c1..801ca269bb2 100644 --- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move @@ -17,7 +17,8 @@ module iota_system::rewards_distribution_tests { create_validator_for_testing, create_iota_system_state_for_testing, stake_with, - total_iota_balance, unstake + total_iota_balance, unstake, + total_supply, }; use iota::test_utils::assert_eq; use iota::address; @@ -43,7 +44,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(0, 100, scenario); + advance_epoch_with_reward_amounts(100, 0, 100, scenario); assert_validator_total_stake_amounts( validator_addrs(), vector[125 * MICROS_PER_IOTA, 225 * MICROS_PER_IOTA, 325 * MICROS_PER_IOTA, 425 * MICROS_PER_IOTA], @@ -53,7 +54,7 @@ module iota_system::rewards_distribution_tests { stake_with(VALIDATOR_ADDR_2, VALIDATOR_ADDR_2, 720, scenario); advance_epoch(scenario); - advance_epoch_with_reward_amounts(0, 100, scenario); + advance_epoch_with_reward_amounts(100, 0, 100, scenario); // Even though validator 2 has a lot more stake now, it should not get more rewards because // the voting power is capped at 10%. assert_validator_total_stake_amounts( @@ -73,11 +74,64 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(0, 100, scenario); + advance_epoch_with_reward_amounts(100, 0, 100, scenario); assert_validator_total_stake_amounts(validator_addrs(), vector[100_000_025 * MICROS_PER_IOTA, 200_000_025 * MICROS_PER_IOTA, 300_000_025 * MICROS_PER_IOTA, 400_000_025 * MICROS_PER_IOTA], scenario); scenario_val.end(); } + #[test] + fun test_validator_target_reward_no_supply_change() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + let prev_supply = total_supply(scenario); + + // need to advance epoch so validator's staking starts counting + advance_epoch(scenario); + advance_epoch_with_reward_amounts(100, 0, 100, scenario); + + let new_supply = total_supply(scenario); + assert!(prev_supply == new_supply, 0); + + scenario_val.end(); + } + + #[test] + fun test_validator_target_reward_deflation() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + let prev_supply = total_supply(scenario); + + // need to advance epoch so validator's staking starts counting + advance_epoch(scenario); + advance_epoch_with_reward_amounts(60, 0, 100, scenario); + + let new_supply = total_supply(scenario); + // 40 tokens should have been burned. + assert!(prev_supply - 40 * MICROS_PER_IOTA == new_supply, 0); + + scenario_val.end(); + } + + #[test] + fun test_validator_target_reward_inflation() { + set_up_iota_system_state(); + let mut scenario_val = test_scenario::begin(VALIDATOR_ADDR_1); + let scenario = &mut scenario_val; + let prev_supply = total_supply(scenario); + + // need to advance epoch so validator's staking starts counting + advance_epoch(scenario); + advance_epoch_with_reward_amounts(100, 0, 60, scenario); + + let new_supply = total_supply(scenario); + // 40 tokens should have been minted. + assert!(prev_supply + 40 * MICROS_PER_IOTA == new_supply, 0); + + scenario_val.end(); + } + #[test] fun test_stake_rewards() { set_up_iota_system_state(); @@ -92,19 +146,19 @@ module iota_system::rewards_distribution_tests { assert_validator_self_stake_amounts(validator_addrs(), vector[100 * MICROS_PER_IOTA, 200 * MICROS_PER_IOTA, 300 * MICROS_PER_IOTA, 400 * MICROS_PER_IOTA], scenario); // Each pool gets 30 IOTA. - advance_epoch_with_reward_amounts(0, 120, scenario); + advance_epoch_with_reward_amounts(120, 0, 120, scenario); assert_validator_self_stake_amounts(validator_addrs(), vector[110 * MICROS_PER_IOTA, 220 * MICROS_PER_IOTA, 330 * MICROS_PER_IOTA, 430 * MICROS_PER_IOTA], scenario); unstake(STAKER_ADDR_1, 0, scenario); stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 600, scenario); // Each pool gets 30 IOTA. - advance_epoch_with_reward_amounts(0, 120, scenario); + advance_epoch_with_reward_amounts(120, 0, 120, scenario); // staker 1 receives only 20 IOTA of rewards, not 40 since we are using pre-epoch exchange rate. assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 220 * MICROS_PER_IOTA); assert_validator_self_stake_amounts(validator_addrs(), vector[140 * MICROS_PER_IOTA, 240 * MICROS_PER_IOTA, 360 * MICROS_PER_IOTA, 460 * MICROS_PER_IOTA], scenario); unstake(STAKER_ADDR_2, 0, scenario); assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 120 * MICROS_PER_IOTA); // 20 IOTA of rewards received - advance_epoch_with_reward_amounts(0, 40, scenario); + advance_epoch_with_reward_amounts(40, 0, 40, scenario); unstake(STAKER_ADDR_2, 0, scenario); // unstake 600 principal IOTA // additional 600 IOTA of principal and 46 IOTA of rewards withdrawn to Coin @@ -128,17 +182,17 @@ module iota_system::rewards_distribution_tests { advance_epoch(scenario); - advance_epoch_with_reward_amounts(0, 150000, scenario); + advance_epoch_with_reward_amounts(150000, 0, 150000, scenario); // stake a small amount stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 10, scenario); - advance_epoch_with_reward_amounts(0, 130, scenario); + advance_epoch_with_reward_amounts(130, 0, 130, scenario); // unstake the stakes unstake(STAKER_ADDR_1, 1, scenario); // and advance epoch should succeed - advance_epoch_with_reward_amounts(0, 150, scenario); + advance_epoch_with_reward_amounts(150, 0, 150, scenario); scenario_val.end(); } @@ -154,7 +208,7 @@ module iota_system::rewards_distribution_tests { // V1: 200, V2: 300, V3: 300, V4: 400 set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_2, 2000, scenario); // 50% commission - advance_epoch_with_reward_amounts(0, 120, scenario); + advance_epoch_with_reward_amounts(120, 0, 120, scenario); // V1: 230, V2: 330, V3: 330, V4: 430 // 2 IOTA, or 20 % of staker_2's rewards, goes to validator_2 assert_validator_non_self_stake_amounts(validator_addrs(), vector[115 * MICROS_PER_IOTA, 108 * MICROS_PER_IOTA, 0, 0], scenario); @@ -162,7 +216,7 @@ module iota_system::rewards_distribution_tests { set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_1, 1000, scenario); // 10% commission - advance_epoch_with_reward_amounts(0, 240, scenario); + advance_epoch_with_reward_amounts(240, 0, 240, scenario); assert_validator_total_stake_amounts(validator_addrs(), vector[290 * MICROS_PER_IOTA, 390 * MICROS_PER_IOTA, 390 * MICROS_PER_IOTA, 490 * MICROS_PER_IOTA], scenario); // Staker 1 rewards in the recent distribution is 0.9 x 30 = 27 IOTA @@ -268,7 +322,7 @@ module iota_system::rewards_distribution_tests { let scenario = &mut scenario_val; // Put 300 IOTA into the storage fund. - advance_epoch_with_reward_amounts(300, 0, scenario); + advance_epoch_with_reward_amounts(0, 300, 0, scenario); // Add a few stakes. stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_3, 100, scenario); @@ -353,23 +407,23 @@ module iota_system::rewards_distribution_tests { stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 220, scenario); - advance_epoch_with_reward_amounts(0, 40, scenario); + advance_epoch_with_reward_amounts(40, 0, 40, scenario); stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 480, scenario); // Staker 1 gets 2/3 * 1/4 * 120 = 20 IOTA here. - advance_epoch_with_reward_amounts(0, 120, scenario); + advance_epoch_with_reward_amounts(120, 0, 120, scenario); stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 130, scenario); stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 390, scenario); // Staker 1 gets 20 IOTA here and staker 2 gets 40 IOTA here. - advance_epoch_with_reward_amounts(0, 280, scenario); + advance_epoch_with_reward_amounts(280, 0, 280, scenario); stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 280, scenario); stake_with(STAKER_ADDR_4, VALIDATOR_ADDR_1, 1400, scenario); // Staker 1 gets 30 IOTA, staker 2 gets 40 IOTA and staker 3 gets 30 IOTA. - advance_epoch_with_reward_amounts(0, 440, scenario); + advance_epoch_with_reward_amounts(440, 0, 440, scenario); scenario.next_tx(@0x0); let mut system_state = scenario.take_shared(); @@ -396,7 +450,7 @@ module iota_system::rewards_distribution_tests { // staker 4 joined and left in an epoch where no rewards were earned so she got no rewards. assert_eq(total_iota_balance(STAKER_ADDR_4, scenario), 1400 * MICROS_PER_IOTA); - advance_epoch_with_reward_amounts(0, 0, scenario); + advance_epoch_with_reward_amounts(0, 0, 0, scenario); scenario.next_tx(@0x0); let mut system_state = scenario.take_shared(); @@ -426,7 +480,7 @@ module iota_system::rewards_distribution_tests { create_iota_system_state_for_testing(validators, 0, 0, ctx); // Each validator's stake gets doubled. - advance_epoch_with_reward_amounts(0, 10000, scenario); + advance_epoch_with_reward_amounts(10000, 0, 10000, scenario); let mut i = 0; scenario.next_tx(@0x0); From 4c6461bed5c5923fea5aaf3b20d4279b3bd6db3d Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 26 Jun 2024 16:41:15 +0200 Subject: [PATCH 10/35] fix: Set IOTA supply in Rust to correct value --- crates/iota-types/src/gas_coin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/iota-types/src/gas_coin.rs b/crates/iota-types/src/gas_coin.rs index a3a103822b2..52540d2ef14 100644 --- a/crates/iota-types/src/gas_coin.rs +++ b/crates/iota-types/src/gas_coin.rs @@ -29,7 +29,7 @@ use crate::{ pub const MICROS_PER_IOTA: u64 = 1_000_000_000; /// Total supply denominated in Iota -pub const TOTAL_SUPPLY_IOTA: u64 = 10_000_000_000; +pub const TOTAL_SUPPLY_IOTA: u64 = 4_600_000_000; // Note: cannot use checked arithmetic here since `const unwrap` is still // unstable. From b594f407b00ddc9671e676968b7e628e6e06bd63 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Wed, 26 Jun 2024 16:41:56 +0200 Subject: [PATCH 11/35] fix: Add `TreasuryCap` to the system state rust struct --- .../src/iota_system_state/iota_system_state_inner_v2.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs index b81872a5128..d6b0dca9481 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs @@ -15,6 +15,7 @@ use super::{ use crate::{ balance::Balance, base_types::IotaAddress, + coin::TreasuryCap, collection_types::{Bag, Table, TableVec, VecMap, VecSet}, committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, error::IotaError, @@ -69,6 +70,7 @@ pub struct IotaSystemStateInnerV2 { pub epoch: u64, pub protocol_version: u64, pub system_state_version: u64, + pub iota_treasury_cap: TreasuryCap, pub validators: ValidatorSetV1, pub storage_fund: StorageFundV1, pub parameters: SystemParametersV2, @@ -201,6 +203,8 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { epoch, protocol_version, system_state_version, + // TODO: Add this to the system state summary. + iota_treasury_cap: _, validators: ValidatorSetV1 { total_stake, From fbbccd91e72d7dd4bdfa73fdfebf32b5f4563c5d Mon Sep 17 00:00:00 2001 From: Dkwcs Date: Wed, 26 Jun 2024 20:54:38 +0300 Subject: [PATCH 12/35] fix: Add TreasuryCap to the system state rust struct v1 --- .../iota_system_state_inner_v1.rs | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs index 614b6773adb..3b1c076ac70 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs @@ -16,16 +16,7 @@ use super::{ AdvanceEpochParams, IotaSystemStateTrait, }; use crate::{ - balance::Balance, - base_types::{IotaAddress, ObjectID}, - collection_types::{Bag, Table, TableVec, VecMap, VecSet}, - committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, - crypto::{verify_proof_of_possession, AuthorityPublicKeyBytes}, - error::IotaError, - id::ID, - iota_system_state::epoch_start_iota_system_state::EpochStartSystemState, - multiaddr::Multiaddr, - storage::ObjectStore, + balance::Balance, base_types::{IotaAddress, ObjectID}, coin::TreasuryCap, collection_types::{Bag, Table, TableVec, VecMap, VecSet}, committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, crypto::{verify_proof_of_possession, AuthorityPublicKeyBytes}, error::IotaError, id::ID, iota_system_state::epoch_start_iota_system_state::EpochStartSystemState, multiaddr::Multiaddr, storage::ObjectStore }; const E_METADATA_INVALID_POP: u64 = 0; @@ -471,6 +462,7 @@ pub struct IotaSystemStateInnerV1 { pub epoch: u64, pub protocol_version: u64, pub system_state_version: u64, + pub iota_treasury_cap: TreasuryCap, pub validators: ValidatorSetV1, pub storage_fund: StorageFundV1, pub parameters: SystemParametersV1, @@ -626,6 +618,8 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { epoch, protocol_version, system_state_version, + // TODO: Add this to the system state summary. + iota_treasury_cap: _, validators: ValidatorSetV1 { total_stake, From eca5fc5b184c22b69c06d6a10b804e1f955c7268 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 27 Jun 2024 10:04:25 +0200 Subject: [PATCH 13/35] feat: Remove stake subsidy fund on move side --- .../packages/iota-system/sources/genesis.move | 22 +---- .../iota-system/sources/iota_system.move | 9 -- .../sources/iota_system_state_inner.move | 29 ------ .../iota-system/sources/stake_subsidy.move | 99 ------------------- .../tests/governance_test_utils.move | 11 --- 5 files changed, 1 insertion(+), 169 deletions(-) delete mode 100644 crates/iota-framework/packages/iota-system/sources/stake_subsidy.move diff --git a/crates/iota-framework/packages/iota-system/sources/genesis.move b/crates/iota-framework/packages/iota-system/sources/genesis.move index b669b58398c..49b5ee7a7e9 100644 --- a/crates/iota-framework/packages/iota-system/sources/genesis.move +++ b/crates/iota-framework/packages/iota-system/sources/genesis.move @@ -11,7 +11,6 @@ module iota_system::genesis { use iota_system::validator::{Self, Validator}; use iota_system::validator_set; use iota_system::iota_system_state_inner; - use iota_system::stake_subsidy; public struct GenesisValidatorMetadata has drop, copy { name: vector, @@ -41,12 +40,6 @@ module iota_system::genesis { chain_start_timestamp_ms: u64, epoch_duration_ms: u64, - // Stake Subsidy parameters - stake_subsidy_start_epoch: u64, - stake_subsidy_initial_distribution_amount: u64, - stake_subsidy_period_length: u64, - stake_subsidy_decrease_rate: u16, - // Validator committee parameters max_validator_count: u64, min_validator_joining_stake: u64, @@ -56,7 +49,6 @@ module iota_system::genesis { } public struct TokenDistributionSchedule { - stake_subsidy_fund_micros: u64, allocations: vector, } @@ -81,7 +73,7 @@ module iota_system::genesis { fun create( iota_system_state_id: UID, iota_treasury_cap: TreasuryCap, - mut iota_supply: Balance, + iota_supply: Balance, genesis_chain_parameters: GenesisChainParameters, genesis_validators: vector, token_distribution_schedule: TokenDistributionSchedule, @@ -91,11 +83,9 @@ module iota_system::genesis { assert!(ctx.epoch() == 0, ENotCalledAtGenesis); let TokenDistributionSchedule { - stake_subsidy_fund_micros, allocations, } = token_distribution_schedule; - let subsidy_fund = iota_supply.split(stake_subsidy_fund_micros); let storage_fund = balance::zero(); // Create all the `Validator` structs @@ -164,7 +154,6 @@ module iota_system::genesis { let system_parameters = iota_system_state_inner::create_system_parameters( genesis_chain_parameters.epoch_duration_ms, - genesis_chain_parameters.stake_subsidy_start_epoch, // Validator committee parameters genesis_chain_parameters.max_validator_count, @@ -176,14 +165,6 @@ module iota_system::genesis { ctx, ); - let stake_subsidy = stake_subsidy::create( - subsidy_fund, - genesis_chain_parameters.stake_subsidy_initial_distribution_amount, - genesis_chain_parameters.stake_subsidy_period_length, - genesis_chain_parameters.stake_subsidy_decrease_rate, - ctx, - ); - iota_system::create( iota_system_state_id, iota_treasury_cap, @@ -192,7 +173,6 @@ module iota_system::genesis { genesis_chain_parameters.protocol_version, genesis_chain_parameters.chain_start_timestamp_ms, system_parameters, - stake_subsidy, ctx, ); } diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move index ef310fcfc04..21974e9436a 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move @@ -49,7 +49,6 @@ module iota_system::iota_system { use iota_system::validator::Validator; use iota_system::validator_cap::UnverifiedValidatorOperationCap; use iota_system::iota_system_state_inner::{Self, SystemParameters, IotaSystemStateInner, IotaSystemStateInnerV2}; - use iota_system::stake_subsidy::StakeSubsidy; use iota_system::staking_pool::PoolTokenExchangeRate; use iota::dynamic_field; @@ -84,7 +83,6 @@ module iota_system::iota_system { protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: SystemParameters, - stake_subsidy: StakeSubsidy, ctx: &mut TxContext, ) { let system_state = iota_system_state_inner::create( @@ -94,7 +92,6 @@ module iota_system::iota_system { protocol_version, epoch_start_timestamp_ms, parameters, - stake_subsidy, ctx, ); let version = iota_system_state_inner::genesis_system_state_version(); @@ -694,12 +691,6 @@ module iota_system::iota_system { self.get_storage_fund_object_rebates() } - #[test_only] - public fun get_stake_subsidy_distribution_counter(wrapper: &mut IotaSystemState): u64 { - let self = load_system_state(wrapper); - self.get_stake_subsidy_distribution_counter() - } - #[test_only] public fun get_iota_supply(wrapper: &mut IotaSystemState): u64 { let self = load_system_state(wrapper); diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index 44ed1bfbc85..118e84e75a0 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -10,7 +10,6 @@ module iota_system::iota_system_state_inner { use iota_system::validator::{Self, Validator}; use iota_system::validator_set::{Self, ValidatorSet}; use iota_system::validator_cap::{UnverifiedValidatorOperationCap, ValidatorOperationCap}; - use iota_system::stake_subsidy::StakeSubsidy; use iota_system::storage_fund::{Self, StorageFund}; use iota_system::staking_pool::PoolTokenExchangeRate; use iota::vec_map::{Self, VecMap}; @@ -38,9 +37,6 @@ module iota_system::iota_system_state_inner { /// The duration of an epoch, in milliseconds. epoch_duration_ms: u64, - /// The starting epoch in which stake subsidies start being paid out - stake_subsidy_start_epoch: u64, - /// Maximum number of active validators at any moment. /// We do not allow the number of validators in any epoch to go above this. max_validator_count: u64, @@ -70,9 +66,6 @@ module iota_system::iota_system_state_inner { /// The duration of an epoch, in milliseconds. epoch_duration_ms: u64, - /// The starting epoch in which stake subsidies start being paid out - stake_subsidy_start_epoch: u64, - /// Minimum number of active validators at any moment. min_validator_count: u64, @@ -129,8 +122,6 @@ module iota_system::iota_system_state_inner { /// Note that in case we want to support validator address change in future, /// the reports should be based on validator ids validator_report_records: VecMap>, - /// Schedule of stake subsidies given out each epoch. - stake_subsidy: StakeSubsidy, /// Whether the system is running in a downgraded safe mode due to a non-recoverable bug. /// This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. @@ -179,8 +170,6 @@ module iota_system::iota_system_state_inner { /// Note that in case we want to support validator address change in future, /// the reports should be based on validator ids validator_report_records: VecMap>, - /// Schedule of stake subsidies given out each epoch. - stake_subsidy: StakeSubsidy, /// Whether the system is running in a downgraded safe mode due to a non-recoverable bug. /// This is set whenever we failed to execute advance_epoch, and ended up executing advance_epoch_safe_mode. @@ -242,7 +231,6 @@ module iota_system::iota_system_state_inner { protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: SystemParameters, - stake_subsidy: StakeSubsidy, ctx: &mut TxContext, ): IotaSystemStateInner { let validators = validator_set::new(validators, ctx); @@ -258,7 +246,6 @@ module iota_system::iota_system_state_inner { parameters, reference_gas_price, validator_report_records: vec_map::empty(), - stake_subsidy, safe_mode: false, safe_mode_storage_rewards: balance::zero(), safe_mode_computation_rewards: balance::zero(), @@ -272,7 +259,6 @@ module iota_system::iota_system_state_inner { public(package) fun create_system_parameters( epoch_duration_ms: u64, - stake_subsidy_start_epoch: u64, // Validator committee parameters max_validator_count: u64, @@ -284,7 +270,6 @@ module iota_system::iota_system_state_inner { ): SystemParameters { SystemParameters { epoch_duration_ms, - stake_subsidy_start_epoch, max_validator_count, min_validator_joining_stake, validator_low_stake_threshold, @@ -305,7 +290,6 @@ module iota_system::iota_system_state_inner { parameters, reference_gas_price, validator_report_records, - stake_subsidy, safe_mode, safe_mode_storage_rewards, safe_mode_computation_rewards, @@ -316,7 +300,6 @@ module iota_system::iota_system_state_inner { } = self; let SystemParameters { epoch_duration_ms, - stake_subsidy_start_epoch, max_validator_count, min_validator_joining_stake, validator_low_stake_threshold, @@ -333,7 +316,6 @@ module iota_system::iota_system_state_inner { storage_fund, parameters: SystemParametersV2 { epoch_duration_ms, - stake_subsidy_start_epoch, min_validator_count: 4, max_validator_count, min_validator_joining_stake, @@ -344,7 +326,6 @@ module iota_system::iota_system_state_inner { }, reference_gas_price, validator_report_records, - stake_subsidy, safe_mode, safe_mode_storage_rewards, safe_mode_computation_rewards, @@ -848,11 +829,6 @@ module iota_system::iota_system_state_inner { EBpsTooLarge, ); - // TODO: remove this in later upgrade. - if (self.parameters.stake_subsidy_start_epoch > 0) { - self.parameters.stake_subsidy_start_epoch = 20; - }; - // Accumulate the gas summary during safe_mode before processing any rewards: let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all(); storage_reward.join(safe_mode_storage_rewards); @@ -1090,11 +1066,6 @@ module iota_system::iota_system_state_inner { validators(self).get_candidate_validator_ref(validator_address) } - #[test_only] - public(package) fun get_stake_subsidy_distribution_counter(self: &IotaSystemStateInnerV2): u64 { - self.stake_subsidy.get_distribution_counter() - } - #[test_only] public(package) fun get_total_iota_supply(self: &IotaSystemStateInnerV2): u64 { self.iota_treasury_cap.total_supply() diff --git a/crates/iota-framework/packages/iota-system/sources/stake_subsidy.move b/crates/iota-framework/packages/iota-system/sources/stake_subsidy.move deleted file mode 100644 index 411503f899e..00000000000 --- a/crates/iota-framework/packages/iota-system/sources/stake_subsidy.move +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// Modifications Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -module iota_system::stake_subsidy { - use iota::balance::Balance; - use iota::math; - use iota::iota::IOTA; - use iota::bag::Bag; - use iota::bag; - - /* friend iota_system::genesis; */ - /* friend iota_system::iota_system_state_inner; */ - - /* #[test_only] */ - /* friend iota_system::governance_test_utils; */ - - public struct StakeSubsidy has store { - /// Balance of IOTA set aside for stake subsidies that will be drawn down over time. - balance: Balance, - - /// Count of the number of times stake subsidies have been distributed. - distribution_counter: u64, - - /// The amount of stake subsidy to be drawn down per distribution. - /// This amount decays and decreases over time. - current_distribution_amount: u64, - - /// Number of distributions to occur before the distribution amount decays. - stake_subsidy_period_length: u64, - - /// The rate at which the distribution amount decays at the end of each - /// period. Expressed in basis points. - stake_subsidy_decrease_rate: u16, - - /// Any extra fields that's not defined statically. - extra_fields: Bag, - } - - const BASIS_POINT_DENOMINATOR: u128 = 10000; - - const ESubsidyDecreaseRateTooLarge: u64 = 0; - - public(package) fun create( - balance: Balance, - initial_distribution_amount: u64, - stake_subsidy_period_length: u64, - stake_subsidy_decrease_rate: u16, - ctx: &mut TxContext, - ): StakeSubsidy { - // Rate can't be higher than 100%. - assert!( - stake_subsidy_decrease_rate <= BASIS_POINT_DENOMINATOR as u16, - ESubsidyDecreaseRateTooLarge, - ); - - StakeSubsidy { - balance, - distribution_counter: 0, - current_distribution_amount: initial_distribution_amount, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, - extra_fields: bag::new(ctx), - } - } - - /// Advance the epoch counter and draw down the subsidy for the epoch. - public(package) fun advance_epoch(self: &mut StakeSubsidy): Balance { - // Take the minimum of the reward amount and the remaining balance in - // order to ensure we don't overdraft the remaining stake subsidy - // balance - let to_withdraw = math::min(self.current_distribution_amount, self.balance.value()); - - // Drawn down the subsidy for this epoch. - let stake_subsidy = self.balance.split(to_withdraw); - - self.distribution_counter = self.distribution_counter + 1; - - // Decrease the subsidy amount only when the current period ends. - if (self.distribution_counter % self.stake_subsidy_period_length == 0) { - let decrease_amount = self.current_distribution_amount as u128 - * (self.stake_subsidy_decrease_rate as u128) / BASIS_POINT_DENOMINATOR; - self.current_distribution_amount = self.current_distribution_amount - (decrease_amount as u64) - }; - - stake_subsidy - } - - /// Returns the amount of stake subsidy to be added at the end of the current epoch. - public fun current_epoch_subsidy_amount(self: &StakeSubsidy): u64 { - math::min(self.current_distribution_amount, self.balance.value()) - } - - #[test_only] - /// Returns the number of distributions that have occurred. - public(package) fun get_distribution_counter(self: &StakeSubsidy): u64 { - self.distribution_counter - } -} diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move index 028e612c7da..665ee55a2b1 100644 --- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move +++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move @@ -13,7 +13,6 @@ module iota_system::governance_test_utils { use iota_system::validator::{Self, Validator}; use iota_system::iota_system::{Self, IotaSystemState}; use iota_system::iota_system_state_inner; - use iota_system::stake_subsidy; use iota::test_scenario::{Self, Scenario}; use iota::test_utils; use iota::balance::Balance; @@ -63,7 +62,6 @@ module iota_system::governance_test_utils { ) { let system_parameters = iota_system_state_inner::create_system_parameters( 42, // epoch_duration_ms, doesn't matter what number we put here - 0, // stake_subsidy_start_epoch 150, // max_validator_count 1, // min_validator_joining_stake @@ -73,14 +71,6 @@ module iota_system::governance_test_utils { ctx, ); - let stake_subsidy = stake_subsidy::create( - balance::create_for_testing(iota_supply_amount * MICROS_PER_IOTA), // iota_supply - 0, // stake subsidy initial distribution amount - 10, // stake_subsidy_period_length - 0, // stake_subsidy_decrease_rate - ctx, - ); - // We initialize the total supply to the given test value but we destroy the // supply balance since we will recreate balances for testing out of thin air. let mut iota_treasury_cap = coin::create_treasury_cap_for_testing(ctx); @@ -95,7 +85,6 @@ module iota_system::governance_test_utils { 1, // protocol version 0, // chain_start_timestamp_ms system_parameters, - stake_subsidy, ctx, ) } From bd4e36fea97d0485ff1bbd9b97542c917fca6944 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 27 Jun 2024 13:24:31 +0200 Subject: [PATCH 14/35] feat: Enable burning remainder supply in distribution schedule --- crates/iota-config/src/genesis.rs | 47 ++++++++++--------- .../packages/iota-system/sources/genesis.move | 2 + 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/crates/iota-config/src/genesis.rs b/crates/iota-config/src/genesis.rs index 369830fc80f..666bc92a038 100644 --- a/crates/iota-config/src/genesis.rs +++ b/crates/iota-config/src/genesis.rs @@ -349,12 +349,6 @@ pub struct GenesisChainParameters { pub chain_start_timestamp_ms: u64, pub epoch_duration_ms: u64, - // Stake Subsidy parameters - pub stake_subsidy_start_epoch: u64, - pub stake_subsidy_initial_distribution_amount: u64, - pub stake_subsidy_period_length: u64, - pub stake_subsidy_decrease_rate: u16, - // Validator committee parameters pub max_validator_count: u64, pub min_validator_joining_stake: u64, @@ -453,13 +447,8 @@ impl GenesisCeremonyParameters { pub fn to_genesis_chain_parameters(&self) -> GenesisChainParameters { GenesisChainParameters { protocol_version: self.protocol_version.as_u64(), - stake_subsidy_start_epoch: self.stake_subsidy_start_epoch, chain_start_timestamp_ms: self.chain_start_timestamp_ms, epoch_duration_ms: self.epoch_duration_ms, - stake_subsidy_initial_distribution_amount: self - .stake_subsidy_initial_distribution_amount, - stake_subsidy_period_length: self.stake_subsidy_period_length, - stake_subsidy_decrease_rate: self.stake_subsidy_decrease_rate, max_validator_count: iota_types::governance::MAX_VALIDATOR_COUNT, min_validator_joining_stake: iota_types::governance::MIN_VALIDATOR_JOINING_STAKE_MICROS, validator_low_stake_threshold: @@ -483,13 +472,13 @@ impl Default for GenesisCeremonyParameters { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub struct TokenDistributionSchedule { - pub stake_subsidy_fund_micros: u64, + pub funds_to_burn: u64, pub allocations: Vec, } impl TokenDistributionSchedule { pub fn validate(&self) { - let mut total_micros = self.stake_subsidy_fund_micros; + let mut total_micros = self.funds_to_burn; for allocation in &self.allocations { total_micros += allocation.amount_micros; @@ -536,6 +525,11 @@ impl TokenDistributionSchedule { } } + /// Creates a new distribution schedule that allocates a default amount to + /// every given validator address. + /// + /// The remainder of the total supply, if any, will be burned during the + /// genesis. pub fn new_for_validators_with_default_allocation>( validators: I, ) -> Self { @@ -555,7 +549,7 @@ impl TokenDistributionSchedule { .collect(); let schedule = Self { - stake_subsidy_fund_micros: supply, + funds_to_burn: supply, allocations, }; @@ -579,7 +573,7 @@ impl TokenDistributionSchedule { assert_eq!( TOTAL_SUPPLY_MICROS, allocations.iter().map(|a| a.amount_micros).sum::(), - "Token Distribution Schedule must add up to 10B Iota", + "Token Distribution Schedule must add up to the total IOTA supply of {TOTAL_SUPPLY_MICROS} nanos", ); let stake_subsidy_fund_allocation = allocations.pop().unwrap(); assert_eq!( @@ -595,7 +589,7 @@ impl TokenDistributionSchedule { ); let schedule = Self { - stake_subsidy_fund_micros: stake_subsidy_fund_allocation.amount_micros, + funds_to_burn: stake_subsidy_fund_allocation.amount_micros, allocations, }; @@ -612,7 +606,7 @@ impl TokenDistributionSchedule { writer.serialize(TokenAllocation { recipient_address: IotaAddress::default(), - amount_micros: self.stake_subsidy_fund_micros, + amount_micros: self.funds_to_burn, staked_with_validator: None, })?; @@ -633,7 +627,8 @@ pub struct TokenAllocation { #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct TokenDistributionScheduleBuilder { - pool: u64, + remaining_supply: u64, + funds_to_burn: u64, allocations: Vec, } @@ -641,7 +636,8 @@ impl TokenDistributionScheduleBuilder { #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { - pool: TOTAL_SUPPLY_MICROS, + remaining_supply: TOTAL_SUPPLY_MICROS, + funds_to_burn: 0, allocations: vec![], } } @@ -662,13 +658,22 @@ impl TokenDistributionScheduleBuilder { } pub fn add_allocation(&mut self, allocation: TokenAllocation) { - self.pool = self.pool.checked_sub(allocation.amount_micros).unwrap(); + self.remaining_supply = self + .remaining_supply + .checked_sub(allocation.amount_micros) + .unwrap(); self.allocations.push(allocation); } + /// Designates the remaining supply to be burned during the genesis. + pub fn burn_remainder(&mut self) { + self.funds_to_burn += self.remaining_supply; + self.remaining_supply = 0; + } + pub fn build(&self) -> TokenDistributionSchedule { let schedule = TokenDistributionSchedule { - stake_subsidy_fund_micros: self.pool, + funds_to_burn: self.remaining_supply, allocations: self.allocations.clone(), }; diff --git a/crates/iota-framework/packages/iota-system/sources/genesis.move b/crates/iota-framework/packages/iota-system/sources/genesis.move index 49b5ee7a7e9..1bfe4e3b698 100644 --- a/crates/iota-framework/packages/iota-system/sources/genesis.move +++ b/crates/iota-framework/packages/iota-system/sources/genesis.move @@ -49,6 +49,7 @@ module iota_system::genesis { } public struct TokenDistributionSchedule { + funds_to_burn: u64, allocations: vector, } @@ -83,6 +84,7 @@ module iota_system::genesis { assert!(ctx.epoch() == 0, ENotCalledAtGenesis); let TokenDistributionSchedule { + funds_to_burn: _, allocations, } = token_distribution_schedule; From 83ace78390a949396004e64471b24093d9d2666e Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 27 Jun 2024 13:26:41 +0200 Subject: [PATCH 15/35] feat: Align Iota System State Rust with Move types --- .../iota_system_state_inner_v1.rs | 52 ++++--------------- .../iota_system_state_inner_v2.rs | 24 +++------ 2 files changed, 17 insertions(+), 59 deletions(-) diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs index 3b1c076ac70..311201d93dc 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs @@ -34,9 +34,6 @@ pub struct SystemParametersV1 { /// The duration of an epoch, in milliseconds. pub epoch_duration_ms: u64, - /// The starting epoch in which stake subsidies start being paid out - pub stake_subsidy_start_epoch: u64, - /// Maximum number of active validators at any moment. /// We do not allow the number of validators in any epoch to go above this. pub max_validator_count: u64, @@ -468,7 +465,6 @@ pub struct IotaSystemStateInnerV1 { pub parameters: SystemParametersV1, pub reference_gas_price: u64, pub validator_report_records: VecMap>, - pub stake_subsidy: StakeSubsidyV1, pub safe_mode: bool, pub safe_mode_storage_rewards: Balance, pub safe_mode_computation_rewards: Balance, @@ -479,29 +475,6 @@ pub struct IotaSystemStateInnerV1 { // TODO: Use getters instead of all pub. } -#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] -pub struct StakeSubsidyV1 { - /// Balance of IOTA set aside for stake subsidies that will be drawn down - /// over time. - pub balance: Balance, - - /// Count of the number of times stake subsidies have been distributed. - pub distribution_counter: u64, - - /// The amount of stake subsidy to be drawn down per distribution. - /// This amount decays and decreases over time. - pub current_distribution_amount: u64, - - /// Number of distributions to occur before the distribution amount decays. - pub stake_subsidy_period_length: u64, - - /// The rate at which the distribution amount decays at the end of each - /// period. Expressed in basis points. - pub stake_subsidy_decrease_rate: u16, - - pub extra_fields: Bag, -} - impl IotaSystemStateTrait for IotaSystemStateInnerV1 { fn epoch(&self) -> u64 { self.epoch @@ -657,7 +630,6 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { storage_fund, parameters: SystemParametersV1 { - stake_subsidy_start_epoch, epoch_duration_ms, max_validator_count, min_validator_joining_stake, @@ -671,15 +643,6 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { VecMap { contents: validator_report_records, }, - stake_subsidy: - StakeSubsidyV1 { - balance: stake_subsidy_balance, - distribution_counter: stake_subsidy_distribution_counter, - current_distribution_amount: stake_subsidy_current_distribution_amount, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, - extra_fields: _, - }, safe_mode, safe_mode_storage_rewards, safe_mode_computation_rewards, @@ -703,11 +666,13 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { safe_mode_storage_rebates, safe_mode_non_refundable_storage_fee, epoch_start_timestamp_ms, - stake_subsidy_start_epoch, + // TODO: Remove + stake_subsidy_start_epoch: 0, epoch_duration_ms, - stake_subsidy_distribution_counter, - stake_subsidy_balance: stake_subsidy_balance.value(), - stake_subsidy_current_distribution_amount, + // TODO: Remove + stake_subsidy_distribution_counter: 0, + stake_subsidy_balance: 0, + stake_subsidy_current_distribution_amount: 0, total_stake, active_validators: active_validators .into_iter() @@ -735,8 +700,9 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { validator_low_stake_threshold, validator_very_low_stake_threshold, validator_low_stake_grace_period, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, + // TODO: Remove + stake_subsidy_period_length: 0, + stake_subsidy_decrease_rate: 0, } } } diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs index d6b0dca9481..5764f7e89b0 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs @@ -22,7 +22,7 @@ use crate::{ iota_system_state::{ epoch_start_iota_system_state::EpochStartSystemState, get_validators_from_table_vec, - iota_system_state_inner_v1::{StakeSubsidyV1, StorageFundV1, ValidatorSetV1}, + iota_system_state_inner_v1::{StorageFundV1, ValidatorSetV1}, }, storage::ObjectStore, }; @@ -76,7 +76,6 @@ pub struct IotaSystemStateInnerV2 { pub parameters: SystemParametersV2, pub reference_gas_price: u64, pub validator_report_records: VecMap>, - pub stake_subsidy: StakeSubsidyV1, pub safe_mode: bool, pub safe_mode_storage_rewards: Balance, pub safe_mode_computation_rewards: Balance, @@ -257,15 +256,6 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { VecMap { contents: validator_report_records, }, - stake_subsidy: - StakeSubsidyV1 { - balance: stake_subsidy_balance, - distribution_counter: stake_subsidy_distribution_counter, - current_distribution_amount: stake_subsidy_current_distribution_amount, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, - extra_fields: _, - }, safe_mode, safe_mode_storage_rewards, safe_mode_computation_rewards, @@ -291,9 +281,10 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { epoch_start_timestamp_ms, stake_subsidy_start_epoch, epoch_duration_ms, - stake_subsidy_distribution_counter, - stake_subsidy_balance: stake_subsidy_balance.value(), - stake_subsidy_current_distribution_amount, + // TODO: Remove + stake_subsidy_distribution_counter: 0, + stake_subsidy_balance: 0, + stake_subsidy_current_distribution_amount: 0, total_stake, active_validators: active_validators .into_iter() @@ -321,8 +312,9 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { validator_low_stake_threshold, validator_very_low_stake_threshold, validator_low_stake_grace_period, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, + // TODO: Remove + stake_subsidy_period_length: 0, + stake_subsidy_decrease_rate: 0, } } } From fca23c9bcd0655ccab91f7dc943e86cd92ca3471 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 27 Jun 2024 13:27:19 +0200 Subject: [PATCH 16/35] feat: Remove stake subsidy entry from inspector --- crates/iota/src/genesis_inspector.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/iota/src/genesis_inspector.rs b/crates/iota/src/genesis_inspector.rs index ecfb19e0389..568f03bc755 100644 --- a/crates/iota/src/genesis_inspector.rs +++ b/crates/iota/src/genesis_inspector.rs @@ -60,10 +60,6 @@ pub(crate) fn examine_genesis_checkpoint(genesis: UnsignedGenesis) { system_object.storage_fund.non_refundable_balance.value(), ), ); - entry.insert( - "Stake Subsidy".to_string(), - (STR_IOTA, system_object.stake_subsidy.balance.value()), - ); // Prepare Object Info let mut owner_map = BTreeMap::new(); From 6bf9caf07f52d7012a30407e423e1185c117b28d Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 27 Jun 2024 13:39:23 +0200 Subject: [PATCH 17/35] feat: Mint and burn gas coin supply in genesis PTB --- .../packages/iota-framework/sources/iota.move | 12 +-- crates/iota-genesis-builder/src/lib.rs | 95 ++++++++++--------- 2 files changed, 50 insertions(+), 57 deletions(-) diff --git a/crates/iota-framework/packages/iota-framework/sources/iota.move b/crates/iota-framework/packages/iota-framework/sources/iota.move index 6288bf60300..bd9ece4a1e4 100644 --- a/crates/iota-framework/packages/iota-framework/sources/iota.move +++ b/crates/iota-framework/packages/iota-framework/sources/iota.move @@ -5,7 +5,6 @@ /// Coin is the token used to pay for gas in IOTA. /// It has 9 decimals, and the smallest unit (10^-9) is called "nano". module iota::iota { - use iota::balance::Balance; use iota::coin::{Self, TreasuryCap}; use iota::url; @@ -18,6 +17,7 @@ module iota::iota { /// 10^-9 of a IOTA token const NANO_PER_IOTA: u64 = 1_000_000_000; + #[allow(unused_const)] /// The total supply of IOTA denominated in Nano (4.6 Billion * 10^9) const TOTAL_SUPPLY_NANO: u64 = 4_600_000_000_000_000_000; @@ -46,16 +46,6 @@ module iota::iota { treasury } - #[allow(unused_function)] - /// Increase the IOTA supply. - /// This should be called only once during genesis creation. - fun increase_supply(cap: &mut TreasuryCap, ctx: &TxContext): Balance { - assert!(ctx.sender() == @0x0, ENotSystemAddress); - assert!(ctx.epoch() == 0, EAlreadyMinted); - - cap.supply_mut().increase_supply(TOTAL_SUPPLY_NANO) - } - public entry fun transfer(c: coin::Coin, recipient: address) { transfer::public_transfer(c, recipient) } diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs index 6a22aedc8ee..8a69b3eb2d5 100644 --- a/crates/iota-genesis-builder/src/lib.rs +++ b/crates/iota-genesis-builder/src/lib.rs @@ -33,7 +33,7 @@ use iota_types::{ effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, epoch_data::EpochData, gas::IotaGasStatus, - gas_coin::GasCoin, + gas_coin::{GasCoin, GAS, TOTAL_SUPPLY_MICROS}, governance::StakedIota, in_memory_storage::InMemoryStorage, inner_temporary_store::InnerTemporaryStore, @@ -297,6 +297,8 @@ impl Builder { Ok(()) } + // TODO: Double check if we have to add additional checks here for newly + // introduced fields. /// Runs through validation checks on the generated output (the initial /// chain state) based on the input values present in the builder fn validate_output(&self) { @@ -310,10 +312,6 @@ impl Builder { protocol_version, chain_start_timestamp_ms, epoch_duration_ms, - stake_subsidy_start_epoch, - stake_subsidy_initial_distribution_amount, - stake_subsidy_period_length, - stake_subsidy_decrease_rate, max_validator_count, min_validator_joining_stake, validator_low_stake_threshold, @@ -411,10 +409,6 @@ impl Builder { ); assert_eq!(system_state.parameters.epoch_duration_ms, epoch_duration_ms); - assert_eq!( - system_state.parameters.stake_subsidy_start_epoch, - stake_subsidy_start_epoch, - ); assert_eq!( system_state.parameters.max_validator_count, max_validator_count, @@ -436,20 +430,6 @@ impl Builder { validator_low_stake_grace_period, ); - assert_eq!(system_state.stake_subsidy.distribution_counter, 0); - assert_eq!( - system_state.stake_subsidy.current_distribution_amount, - stake_subsidy_initial_distribution_amount, - ); - assert_eq!( - system_state.stake_subsidy.stake_subsidy_period_length, - stake_subsidy_period_length, - ); - assert_eq!( - system_state.stake_subsidy.stake_subsidy_decrease_rate, - stake_subsidy_decrease_rate, - ); - assert!(!system_state.safe_mode); assert_eq!( system_state.epoch_start_timestamp_ms, @@ -467,13 +447,9 @@ impl Builder { assert_eq!(system_state.validators.inactive_validators.size, 0); assert_eq!(system_state.validators.validator_candidates.size, 0); - // Check distribution is correct + // TODO: Consider adding total supply check with changed distribution schedule, + // unless already in place. Check distribution is correct let token_distribution_schedule = self.token_distribution_schedule.clone().unwrap(); - assert_eq!( - system_state.stake_subsidy.balance.value(), - token_distribution_schedule.stake_subsidy_fund_micros - ); - let mut gas_objects: BTreeMap = unsigned_genesis .objects() .iter() @@ -1114,27 +1090,54 @@ pub fn generate_genesis_system_object( vec![], vec![], ); + + let iota_supply = builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("coin").to_owned(), + ident_str!("supply_mut").to_owned(), + vec![GAS::type_().into()], + vec![iota_treasury_cap], + ); + + let total_iota_supply = builder + .input(CallArg::Pure( + bcs::to_bytes(&TOTAL_SUPPLY_MICROS).expect("serialization of u64 should succeed"), + )) + .expect("adding the total IOTA supply argument should succeed"); let total_iota = builder.programmable_move_call( IOTA_FRAMEWORK_PACKAGE_ID, - ident_str!("iota").to_owned(), + ident_str!("balance").to_owned(), ident_str!("increase_supply").to_owned(), - vec![], - vec![iota_treasury_cap], + vec![GAS::type_().into()], + vec![iota_supply, total_iota_supply], ); - // TODO: - // IOTA supply that already distributed to the users needs to be burned here - // or inside the `genesis::new` function. - // Rename the `destroy_storage_rebates` function or create a specific one. - - // builder.programmable_move_call( - // IOTA_FRAMEWORK_PACKAGE_ID, - // BALANCE_MODULE_NAME.to_owned(), - // BALANCE_DESTROY_REBATES_FUNCTION_NAME.to_owned(), - // vec![GAS::type_tag()], - // vec![total_iota], - // ); - - // Step 5: Run genesis. + + // Step 5: Burn the tokens that are marked as such, according to the token distribution schedule. + let iotas_to_burn_arg = builder + .input(CallArg::Pure( + bcs::to_bytes(&token_distribution_schedule.funds_to_burn) + .expect("serialization of u64 should succeed"), + )) + .expect("adding the funds to burn argument should succeed"); + let iotas_to_burn_balance = builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("balance").to_owned(), + ident_str!("split").to_owned(), + vec![GAS::type_().into()], + vec![total_iota, iotas_to_burn_arg], + ); + + builder.programmable_move_call( + IOTA_FRAMEWORK_PACKAGE_ID, + ident_str!("balance").to_owned(), + ident_str!("decrease_supply").to_owned(), + vec![GAS::type_().into()], + vec![iota_supply, iotas_to_burn_balance], + ); + + // TODO: Rename the `destroy_storage_rebates` function or create a specific one. + + // Step 6: Run genesis. // The first argument is the system state uid we got from step 1 and the second // one is the IOTA `TreasuryCap` we got from step 4. let mut arguments = vec![iota_system_state_uid, iota_treasury_cap, total_iota]; From e8034f8892d5e081b59502ec9e5aca10cd222773 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Thu, 27 Jun 2024 13:39:57 +0200 Subject: [PATCH 18/35] feat: Update docs of change move modules --- .../docs/iota-framework/iota.md | 31 --- .../docs/iota-system/genesis.md | 42 +--- .../docs/iota-system/iota_system.md | 5 +- .../iota-system/iota_system_state_inner.md | 42 +--- .../docs/iota-system/stake_subsidy.md | 213 ------------------ 5 files changed, 6 insertions(+), 327 deletions(-) delete mode 100644 crates/iota-framework/docs/iota-system/stake_subsidy.md diff --git a/crates/iota-framework/docs/iota-framework/iota.md b/crates/iota-framework/docs/iota-framework/iota.md index dac7072c03b..b98484ab93c 100644 --- a/crates/iota-framework/docs/iota-framework/iota.md +++ b/crates/iota-framework/docs/iota-framework/iota.md @@ -9,12 +9,10 @@ It has 9 decimals, and the smallest unit (10^-9) is called "nano". - [Struct `IOTA`](#0x2_iota_IOTA) - [Constants](#@Constants_0) - [Function `new`](#0x2_iota_new) -- [Function `increase_supply`](#0x2_iota_increase_supply) - [Function `transfer`](#0x2_iota_transfer)
use 0x1::option;
-use 0x2::balance;
 use 0x2::coin;
 use 0x2::transfer;
 use 0x2::tx_context;
@@ -135,35 +133,6 @@ This should be called only once during genesis creation.
 
 
 
-
-
-
-
-## Function `increase_supply`
-
-Increase the IOTA supply.
-This should be called only once during genesis creation.
-
-
-
fun increase_supply(cap: &mut coin::TreasuryCap<iota::IOTA>, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
-
- - - -
-Implementation - - -
fun increase_supply(cap: &mut TreasuryCap<IOTA>, ctx: &TxContext): Balance<IOTA> {
-    assert!(ctx.sender() == @0x0, ENotSystemAddress);
-    assert!(ctx.epoch() == 0, EAlreadyMinted);
-
-    cap.supply_mut().increase_supply(TOTAL_SUPPLY_NANO)
-}
-
- - -
diff --git a/crates/iota-framework/docs/iota-system/genesis.md b/crates/iota-framework/docs/iota-system/genesis.md index 15afdec723b..fde47a17337 100644 --- a/crates/iota-framework/docs/iota-system/genesis.md +++ b/crates/iota-framework/docs/iota-system/genesis.md @@ -23,7 +23,6 @@ title: Module `0x3::genesis` use 0x2::tx_context; use 0x3::iota_system; use 0x3::iota_system_state_inner; -use 0x3::stake_subsidy; use 0x3::validator; use 0x3::validator_set;
@@ -174,30 +173,6 @@ title: Module `0x3::genesis`
-
-
-stake_subsidy_start_epoch: u64 -
-
- -
-
-stake_subsidy_initial_distribution_amount: u64 -
-
- -
-
-stake_subsidy_period_length: u64 -
-
- -
-
-stake_subsidy_decrease_rate: u16 -
-
-
max_validator_count: u64 @@ -251,7 +226,7 @@ title: Module `0x3::genesis`
-stake_subsidy_fund_micros: u64 +funds_to_burn: u64
@@ -352,7 +327,7 @@ all the information we need in the system.
fun create(
     iota_system_state_id: UID,
     iota_treasury_cap: TreasuryCap<IOTA>,
-    mut iota_supply: Balance<IOTA>,
+    iota_supply: Balance<IOTA>,
     genesis_chain_parameters: GenesisChainParameters,
     genesis_validators: vector<GenesisValidatorMetadata>,
     token_distribution_schedule: TokenDistributionSchedule,
@@ -362,11 +337,10 @@ all the information we need in the system.
     assert!(ctx.epoch() == 0, ENotCalledAtGenesis);
 
     let TokenDistributionSchedule {
-        stake_subsidy_fund_micros,
+        funds_to_burn: _,
         allocations,
     } = token_distribution_schedule;
 
-    let subsidy_fund = iota_supply.split(stake_subsidy_fund_micros);
     let storage_fund = balance::zero();
 
     // Create all the `Validator` structs
@@ -435,7 +409,6 @@ all the information we need in the system.
 
     let system_parameters = iota_system_state_inner::create_system_parameters(
         genesis_chain_parameters.epoch_duration_ms,
-        genesis_chain_parameters.stake_subsidy_start_epoch,
 
         // Validator committee parameters
         genesis_chain_parameters.max_validator_count,
@@ -447,14 +420,6 @@ all the information we need in the system.
         ctx,
     );
 
-    let stake_subsidy = stake_subsidy::create(
-        subsidy_fund,
-        genesis_chain_parameters.stake_subsidy_initial_distribution_amount,
-        genesis_chain_parameters.stake_subsidy_period_length,
-        genesis_chain_parameters.stake_subsidy_decrease_rate,
-        ctx,
-    );
-
     iota_system::create(
         iota_system_state_id,
         iota_treasury_cap,
@@ -463,7 +428,6 @@ all the information we need in the system.
         genesis_chain_parameters.protocol_version,
         genesis_chain_parameters.chain_start_timestamp_ms,
         system_parameters,
-        stake_subsidy,
         ctx,
     );
 }
diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md
index e4d8ae69993..ae3b64aa08e 100644
--- a/crates/iota-framework/docs/iota-system/iota_system.md
+++ b/crates/iota-framework/docs/iota-system/iota_system.md
@@ -95,7 +95,6 @@ the IotaSystemStateInner version, or vice versa.
 use 0x2::transfer;
 use 0x2::tx_context;
 use 0x3::iota_system_state_inner;
-use 0x3::stake_subsidy;
 use 0x3::staking_pool;
 use 0x3::validator;
 use 0x3::validator_cap;
@@ -167,7 +166,7 @@ Create a new IotaSystemState object and make it shared.
 This function will be called only once in genesis.
 
 
-
public(friend) fun create(id: object::UID, iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext)
+
public(friend) fun create(id: object::UID, iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, ctx: &mut tx_context::TxContext)
 
@@ -184,7 +183,6 @@ This function will be called only once in genesis. protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: SystemParameters, - stake_subsidy: StakeSubsidy, ctx: &mut TxContext, ) { let system_state = iota_system_state_inner::create( @@ -194,7 +192,6 @@ This function will be called only once in genesis. protocol_version, epoch_start_timestamp_ms, parameters, - stake_subsidy, ctx, ); let version = iota_system_state_inner::genesis_system_state_version(); diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 5c3832e6efd..f3376b58b5f 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -79,7 +79,6 @@ title: Module `0x3::iota_system_state_inner` use 0x2::tx_context; use 0x2::vec_map; use 0x2::vec_set; -use 0x3::stake_subsidy; use 0x3::staking_pool; use 0x3::storage_fund; use 0x3::validator; @@ -113,12 +112,6 @@ A list of system config parameters. The duration of an epoch, in milliseconds.
-stake_subsidy_start_epoch: u64 -
-
- The starting epoch in which stake subsidies start being paid out -
-
max_validator_count: u64
@@ -188,12 +181,6 @@ Added min_validator_count. The duration of an epoch, in milliseconds.
-stake_subsidy_start_epoch: u64 -
-
- The starting epoch in which stake subsidies start being paid out -
-
min_validator_count: u64
@@ -326,12 +313,6 @@ The top-level object containing all information of the Iota system. the reports should be based on validator ids
-stake_subsidy: stake_subsidy::StakeSubsidy -
-
- Schedule of stake subsidies given out each epoch. -
-
safe_mode: bool
@@ -464,12 +445,6 @@ Uses SystemParametersV2 as the parameters. the reports should be based on validator ids
-stake_subsidy: stake_subsidy::StakeSubsidy -
-
- Schedule of stake subsidies given out each epoch. -
-
safe_mode: bool
@@ -755,7 +730,7 @@ Create a new IotaSystemState object and make it shared. This function will be called only once in genesis. -
public(friend) fun create(iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, stake_subsidy: stake_subsidy::StakeSubsidy, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
+
public(friend) fun create(iota_treasury_cap: coin::TreasuryCap<iota::IOTA>, validators: vector<validator::Validator>, initial_storage_fund: balance::Balance<iota::IOTA>, protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: iota_system_state_inner::SystemParameters, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
 
@@ -771,7 +746,6 @@ This function will be called only once in genesis. protocol_version: u64, epoch_start_timestamp_ms: u64, parameters: SystemParameters, - stake_subsidy: StakeSubsidy, ctx: &mut TxContext, ): IotaSystemStateInner { let validators = validator_set::new(validators, ctx); @@ -787,7 +761,6 @@ This function will be called only once in genesis. parameters, reference_gas_price, validator_report_records: vec_map::empty(), - stake_subsidy, safe_mode: false, safe_mode_storage_rewards: balance::zero(), safe_mode_computation_rewards: balance::zero(), @@ -810,7 +783,7 @@ This function will be called only once in genesis. -
public(friend) fun create_system_parameters(epoch_duration_ms: u64, stake_subsidy_start_epoch: u64, max_validator_count: u64, min_validator_joining_stake: u64, validator_low_stake_threshold: u64, validator_very_low_stake_threshold: u64, validator_low_stake_grace_period: u64, ctx: &mut tx_context::TxContext): iota_system_state_inner::SystemParameters
+
public(friend) fun create_system_parameters(epoch_duration_ms: u64, max_validator_count: u64, min_validator_joining_stake: u64, validator_low_stake_threshold: u64, validator_very_low_stake_threshold: u64, validator_low_stake_grace_period: u64, ctx: &mut tx_context::TxContext): iota_system_state_inner::SystemParameters
 
@@ -821,7 +794,6 @@ This function will be called only once in genesis.
public(package) fun create_system_parameters(
     epoch_duration_ms: u64,
-    stake_subsidy_start_epoch: u64,
 
     // Validator committee parameters
     max_validator_count: u64,
@@ -833,7 +805,6 @@ This function will be called only once in genesis.
 ): SystemParameters {
     SystemParameters {
         epoch_duration_ms,
-        stake_subsidy_start_epoch,
         max_validator_count,
         min_validator_joining_stake,
         validator_low_stake_threshold,
@@ -874,7 +845,6 @@ This function will be called only once in genesis.
         parameters,
         reference_gas_price,
         validator_report_records,
-        stake_subsidy,
         safe_mode,
         safe_mode_storage_rewards,
         safe_mode_computation_rewards,
@@ -885,7 +855,6 @@ This function will be called only once in genesis.
     } = self;
     let SystemParameters {
         epoch_duration_ms,
-        stake_subsidy_start_epoch,
         max_validator_count,
         min_validator_joining_stake,
         validator_low_stake_threshold,
@@ -902,7 +871,6 @@ This function will be called only once in genesis.
         storage_fund,
         parameters: SystemParametersV2 {
             epoch_duration_ms,
-            stake_subsidy_start_epoch,
             min_validator_count: 4,
             max_validator_count,
             min_validator_joining_stake,
@@ -913,7 +881,6 @@ This function will be called only once in genesis.
         },
         reference_gas_price,
         validator_report_records,
-        stake_subsidy,
         safe_mode,
         safe_mode_storage_rewards,
         safe_mode_computation_rewards,
@@ -2112,11 +2079,6 @@ gas coins.
         EBpsTooLarge,
     );
 
-    // TODO: remove this in later upgrade.
-    if (self.parameters.stake_subsidy_start_epoch > 0) {
-        self.parameters.stake_subsidy_start_epoch = 20;
-    };
-
     // Accumulate the gas summary during safe_mode before processing any rewards:
     let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all();
     storage_reward.join(safe_mode_storage_rewards);
diff --git a/crates/iota-framework/docs/iota-system/stake_subsidy.md b/crates/iota-framework/docs/iota-system/stake_subsidy.md
deleted file mode 100644
index fce7bc03cdb..00000000000
--- a/crates/iota-framework/docs/iota-system/stake_subsidy.md
+++ /dev/null
@@ -1,213 +0,0 @@
----
-title: Module `0x3::stake_subsidy`
----
-
-
-
--  [Struct `StakeSubsidy`](#0x3_stake_subsidy_StakeSubsidy)
--  [Constants](#@Constants_0)
--  [Function `create`](#0x3_stake_subsidy_create)
--  [Function `advance_epoch`](#0x3_stake_subsidy_advance_epoch)
--  [Function `current_epoch_subsidy_amount`](#0x3_stake_subsidy_current_epoch_subsidy_amount)
-
-
-
use 0x2::bag;
-use 0x2::balance;
-use 0x2::iota;
-use 0x2::math;
-use 0x2::tx_context;
-
- - - - - -## Struct `StakeSubsidy` - - - -
struct StakeSubsidy has store
-
- - - -
-Fields - - -
-
-balance: balance::Balance<iota::IOTA> -
-
- Balance of IOTA set aside for stake subsidies that will be drawn down over time. -
-
-distribution_counter: u64 -
-
- Count of the number of times stake subsidies have been distributed. -
-
-current_distribution_amount: u64 -
-
- The amount of stake subsidy to be drawn down per distribution. - This amount decays and decreases over time. -
-
-stake_subsidy_period_length: u64 -
-
- Number of distributions to occur before the distribution amount decays. -
-
-stake_subsidy_decrease_rate: u16 -
-
- The rate at which the distribution amount decays at the end of each - period. Expressed in basis points. -
-
-extra_fields: bag::Bag -
-
- Any extra fields that's not defined statically. -
-
- - -
- - - -## Constants - - - - - - -
const BASIS_POINT_DENOMINATOR: u128 = 10000;
-
- - - - - - - -
const ESubsidyDecreaseRateTooLarge: u64 = 0;
-
- - - - - -## Function `create` - - - -
public(friend) fun create(balance: balance::Balance<iota::IOTA>, initial_distribution_amount: u64, stake_subsidy_period_length: u64, stake_subsidy_decrease_rate: u16, ctx: &mut tx_context::TxContext): stake_subsidy::StakeSubsidy
-
- - - -
-Implementation - - -
public(package) fun create(
-    balance: Balance<IOTA>,
-    initial_distribution_amount: u64,
-    stake_subsidy_period_length: u64,
-    stake_subsidy_decrease_rate: u16,
-    ctx: &mut TxContext,
-): StakeSubsidy {
-    // Rate can't be higher than 100%.
-    assert!(
-        stake_subsidy_decrease_rate <= BASIS_POINT_DENOMINATOR as u16,
-        ESubsidyDecreaseRateTooLarge,
-    );
-
-    StakeSubsidy {
-        balance,
-        distribution_counter: 0,
-        current_distribution_amount: initial_distribution_amount,
-        stake_subsidy_period_length,
-        stake_subsidy_decrease_rate,
-        extra_fields: bag::new(ctx),
-    }
-}
-
- - - -
- - - -## Function `advance_epoch` - -Advance the epoch counter and draw down the subsidy for the epoch. - - -
public(friend) fun advance_epoch(self: &mut stake_subsidy::StakeSubsidy): balance::Balance<iota::IOTA>
-
- - - -
-Implementation - - -
public(package) fun advance_epoch(self: &mut StakeSubsidy): Balance<IOTA> {
-    // Take the minimum of the reward amount and the remaining balance in
-    // order to ensure we don't overdraft the remaining stake subsidy
-    // balance
-    let to_withdraw = math::min(self.current_distribution_amount, self.balance.value());
-
-    // Drawn down the subsidy for this epoch.
-    let stake_subsidy = self.balance.split(to_withdraw);
-
-    self.distribution_counter = self.distribution_counter + 1;
-
-    // Decrease the subsidy amount only when the current period ends.
-    if (self.distribution_counter % self.stake_subsidy_period_length == 0) {
-        let decrease_amount = self.current_distribution_amount as u128
-            * (self.stake_subsidy_decrease_rate as u128) / BASIS_POINT_DENOMINATOR;
-        self.current_distribution_amount = self.current_distribution_amount - (decrease_amount as u64)
-    };
-
-    stake_subsidy
-}
-
- - - -
- - - -## Function `current_epoch_subsidy_amount` - -Returns the amount of stake subsidy to be added at the end of the current epoch. - - -
public fun current_epoch_subsidy_amount(self: &stake_subsidy::StakeSubsidy): u64
-
- - - -
-Implementation - - -
public fun current_epoch_subsidy_amount(self: &StakeSubsidy): u64 {
-    math::min(self.current_distribution_amount, self.balance.value())
-}
-
- - - -
From 782df31cab5a2eea4bdffedc6bdfd34ba5b86782 Mon Sep 17 00:00:00 2001 From: Dkwcs Date: Thu, 27 Jun 2024 15:32:19 +0300 Subject: [PATCH 19/35] feat(iota-framework): storage deposits basic implementation --- .../docs/iota-system/storage_deposits.md | 134 ++++++++++++++++++ .../iota-system/sources/storage_deposits.move | 42 ++++++ 2 files changed, 176 insertions(+) create mode 100644 crates/iota-framework/docs/iota-system/storage_deposits.md create mode 100644 crates/iota-framework/packages/iota-system/sources/storage_deposits.move diff --git a/crates/iota-framework/docs/iota-system/storage_deposits.md b/crates/iota-framework/docs/iota-system/storage_deposits.md new file mode 100644 index 00000000000..076a4d7675d --- /dev/null +++ b/crates/iota-framework/docs/iota-system/storage_deposits.md @@ -0,0 +1,134 @@ +--- +title: Module `0x3::storage_deposits` +--- + + + +- [Struct `StorageDeposits`](#0x3_storage_deposits_StorageDeposits) +- [Function `new`](#0x3_storage_deposits_new) +- [Function `advance_epoch`](#0x3_storage_deposits_advance_epoch) +- [Function `total_balance`](#0x3_storage_deposits_total_balance) + + +
use 0x2::balance;
+use 0x2::iota;
+
+ + + + + +## Struct `StorageDeposits` + +Struct representing the storage deposits fund, containing a Balance: +- storage_balance tracks the total balance of storage fees collected from transactions. + + +
struct StorageDeposits has store
+
+ + + +
+Fields + + +
+
+storage_balance: balance::Balance<iota::IOTA> +
+
+ +
+
+ + +
+ + + +## Function `new` + +Called by iota_system at genesis time. + + +
public(friend) fun new(initial_balance: balance::Balance<iota::IOTA>): storage_deposits::StorageDeposits
+
+ + + +
+Implementation + + +
public(package) fun new(initial_balance: Balance<IOTA>) : StorageDeposits {
+    StorageDeposits {
+        // Initialize the storage deposits balance
+        storage_balance: initial_balance,
+    }
+}
+
+ + + +
+ + + +## Function `advance_epoch` + +Called by iota_system at epoch change times to process the inflows and outflows of storage deposits. + + +
public(friend) fun advance_epoch(self: &mut storage_deposits::StorageDeposits, storage_charges: balance::Balance<iota::IOTA>, storage_rebate_amount: u64): balance::Balance<iota::IOTA>
+
+ + + +
+Implementation + + +
public(package) fun advance_epoch(
+    self: &mut StorageDeposits,
+    storage_charges: Balance<IOTA>,
+    storage_rebate_amount: u64,
+) : Balance<IOTA> {
+    self.storage_balance.join(storage_charges);
+
+    let storage_rebate = self.storage_balance.split(storage_rebate_amount);
+
+    //TODO: possibly mint and burn tokens here
+    // mint_iota(treasury_cap, storage_charges.value(), ctx);
+    // burn_iota(treasury_cap, storage_rebate_amount, ctx);
+    storage_rebate
+}
+
+ + + +
+ + + +## Function `total_balance` + + + +
public fun total_balance(self: &storage_deposits::StorageDeposits): u64
+
+ + + +
+Implementation + + +
public fun total_balance(self: &StorageDeposits): u64 {
+    self.storage_balance.value()
+}
+
+ + + +
diff --git a/crates/iota-framework/packages/iota-system/sources/storage_deposits.move b/crates/iota-framework/packages/iota-system/sources/storage_deposits.move new file mode 100644 index 00000000000..a262cd64f84 --- /dev/null +++ b/crates/iota-framework/packages/iota-system/sources/storage_deposits.move @@ -0,0 +1,42 @@ +// Copyright (c) Mysten Labs, Inc. +// Modifications Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +module iota_system::storage_deposits { + use iota::balance::Balance; + use iota::iota::IOTA; + + /// Struct representing the storage deposits fund, containing a `Balance`: + /// - `storage_balance` tracks the total balance of storage fees collected from transactions. + public struct StorageDeposits has store { + storage_balance: Balance, + } + + /// Called by `iota_system` at genesis time. + public(package) fun new(initial_balance: Balance) : StorageDeposits { + StorageDeposits { + // Initialize the storage deposits balance + storage_balance: initial_balance, + } + } + + /// Called by `iota_system` at epoch change times to process the inflows and outflows of storage deposits. + public(package) fun advance_epoch( + self: &mut StorageDeposits, + storage_charges: Balance, + storage_rebate_amount: u64, + ) : Balance { + self.storage_balance.join(storage_charges); + + let storage_rebate = self.storage_balance.split(storage_rebate_amount); + + //TODO: possibly mint and burn tokens here + // mint_iota(treasury_cap, storage_charges.value(), ctx); + // burn_iota(treasury_cap, storage_rebate_amount, ctx); + storage_rebate + } + + public fun total_balance(self: &StorageDeposits): u64 { + self.storage_balance.value() + } +} From 7cb1fc6add9136a43510c0c801d68110d125fef1 Mon Sep 17 00:00:00 2001 From: Dkwcs Date: Fri, 28 Jun 2024 00:00:15 +0300 Subject: [PATCH 20/35] feat(iota-framework): remove storage_fund earnings rewards(storage_fund_reinvestment removed) --- .../iota-system/iota_system_state_inner.md | 28 ++----------------- .../docs/iota-system/storage_deposits.md | 17 +++++++---- .../docs/iota-system/storage_fund.md | 6 ++-- .../sources/iota_system_state_inner.move | 20 ++++--------- .../iota-system/sources/storage_fund.move | 8 ++---- 5 files changed, 24 insertions(+), 55 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index f3376b58b5f..b1fc7676ac1 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -537,12 +537,6 @@ the epoch advancement transaction.
-
-
-storage_fund_reinvestment: u64 -
-
-
storage_charge: u64 @@ -561,12 +555,6 @@ the epoch advancement transaction.
-
-
-stake_subsidy_amount: u64 -
-
-
total_gas_fees: u64 @@ -2115,11 +2103,6 @@ gas coins. let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128; let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64); - let storage_fund_reinvestment_amount = - storage_fund_reward_amount * (storage_fund_reinvest_rate as u128) / BASIS_POINT_DENOMINATOR; - let storage_fund_reinvestment = storage_fund_reward.split( - storage_fund_reinvestment_amount as u64, - ); self.epoch = self.epoch + 1; // Sanity check to make sure we are advancing to the right epoch. @@ -2145,22 +2128,20 @@ gas coins. let storage_fund_reward_amount_after_distribution = storage_fund_reward.value(); let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution; let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution; - + storage_fund_reward.destroy_zero(); self.protocol_version = next_protocol_version; // Derive the reference gas price for the new epoch self.reference_gas_price = self.validators.derive_reference_gas_price(); // Because of precision issues with integer divisions, we expect that there will be some - // remaining balance in `storage_fund_reward` and `computation_reward`. + // remaining balance in `computation_reward`. // All of these go to the storage fund. - let mut leftover_staking_rewards = storage_fund_reward; - leftover_staking_rewards.join(computation_reward); + let leftover_staking_rewards = computation_reward; let leftover_storage_fund_inflow = leftover_staking_rewards.value(); let refunded_storage_rebate = self.storage_fund.advance_epoch( storage_reward, - storage_fund_reinvestment, leftover_staking_rewards, storage_rebate_amount, non_refundable_storage_fee_amount, @@ -2173,11 +2154,8 @@ gas coins. reference_gas_price: self.reference_gas_price, total_stake: new_total_stake, storage_charge, - storage_fund_reinvestment: storage_fund_reinvestment_amount as u64, storage_rebate: storage_rebate_amount, storage_fund_balance: self.storage_fund.total_balance(), - // TODO: Remove - stake_subsidy_amount: 0, total_gas_fees: computation_charge, total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed, leftover_storage_fund_inflow, diff --git a/crates/iota-framework/docs/iota-system/storage_deposits.md b/crates/iota-framework/docs/iota-system/storage_deposits.md index 076a4d7675d..fe4b2fa8278 100644 --- a/crates/iota-framework/docs/iota-system/storage_deposits.md +++ b/crates/iota-framework/docs/iota-system/storage_deposits.md @@ -35,7 +35,13 @@ Struct representing the storage deposits fund, containing a Balance
-storage_balance: balance::Balance<iota::IOTA> +refundable_balance: balance::Balance<iota::IOTA> +
+
+ +
+
+non_refundable_balance: balance::Balance<iota::IOTA>
@@ -64,7 +70,8 @@ Called by iota_system
public(package) fun new(initial_balance: Balance<IOTA>) : StorageDeposits {
     StorageDeposits {
         // Initialize the storage deposits balance
-        storage_balance: initial_balance,
+        refundable_balance: initial_balance,
+        non_refundable_balance: balance::zero()
     }
 }
 
@@ -94,9 +101,9 @@ Called by iota_system storage_charges: Balance<IOTA>, storage_rebate_amount: u64, ) : Balance<IOTA> { - self.storage_balance.join(storage_charges); + self.refundable_balance.join(storage_charges); - let storage_rebate = self.storage_balance.split(storage_rebate_amount); + let storage_rebate = self.refundable_balance.split(storage_rebate_amount); //TODO: possibly mint and burn tokens here // mint_iota(treasury_cap, storage_charges.value(), ctx); @@ -125,7 +132,7 @@ Called by iota_system
public fun total_balance(self: &StorageDeposits): u64 {
-    self.storage_balance.value()
+    self.refundable_balance.value() + self.non_refundable_balance.value()
 }
 
diff --git a/crates/iota-framework/docs/iota-system/storage_fund.md b/crates/iota-framework/docs/iota-system/storage_fund.md index a9205a960c8..ba3be277350 100644 --- a/crates/iota-framework/docs/iota-system/storage_fund.md +++ b/crates/iota-framework/docs/iota-system/storage_fund.md @@ -94,7 +94,7 @@ Called by iota_system Called by iota_system at epoch change times to process the inflows and outflows of storage fund. -
public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<iota::IOTA>, storage_fund_reinvestment: balance::Balance<iota::IOTA>, leftover_staking_rewards: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64): balance::Balance<iota::IOTA>
+
public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<iota::IOTA>, leftover_staking_rewards: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64): balance::Balance<iota::IOTA>
 
@@ -106,13 +106,11 @@ Called by iota_system
public(package) fun advance_epoch(
     self: &mut StorageFund,
     storage_charges: Balance<IOTA>,
-    storage_fund_reinvestment: Balance<IOTA>,
     leftover_staking_rewards: Balance<IOTA>,
     storage_rebate_amount: u64,
     non_refundable_storage_fee_amount: u64,
 ) : Balance<IOTA> {
-    // Both the reinvestment and leftover rewards are not to be refunded so they go to the non-refundable balance.
-    self.non_refundable_balance.join(storage_fund_reinvestment);
+    // Add any leftover staking rewards to the non-refundable balance.
     self.non_refundable_balance.join(leftover_staking_rewards);
 
     // The storage charges for the epoch come from the storage rebate of the new objects created
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
index 118e84e75a0..9ce3cf1da16 100644
--- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
+++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move
@@ -196,11 +196,9 @@ module iota_system::iota_system_state_inner {
         protocol_version: u64,
         reference_gas_price: u64,
         total_stake: u64,
-        storage_fund_reinvestment: u64,
         storage_charge: u64,
         storage_rebate: u64,
         storage_fund_balance: u64,
-        stake_subsidy_amount: u64,
         total_gas_fees: u64,
         total_stake_rewards_distributed: u64,
         leftover_storage_fund_inflow: u64,
@@ -797,6 +795,7 @@ module iota_system::iota_system_state_inner {
         candidate.update_candidate_network_pubkey(network_pubkey);
     }
 
+
     /// This function should be called at the end of an epoch, and advances the system to the next epoch.
     /// It does the following things:
     /// 1. Add storage charge to the storage fund.
@@ -865,11 +864,6 @@ module iota_system::iota_system_state_inner {
 
         let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128;
         let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64);
-        let storage_fund_reinvestment_amount =
-            storage_fund_reward_amount * (storage_fund_reinvest_rate as u128) / BASIS_POINT_DENOMINATOR;
-        let storage_fund_reinvestment = storage_fund_reward.split(
-            storage_fund_reinvestment_amount as u64,
-        );
 
         self.epoch = self.epoch + 1;
         // Sanity check to make sure we are advancing to the right epoch.
@@ -893,24 +887,23 @@ module iota_system::iota_system_state_inner {
 
         let computation_reward_amount_after_distribution = computation_reward.value();
         let storage_fund_reward_amount_after_distribution = storage_fund_reward.value();
+        //TODO: remove
+        storage_fund_reward.destroy_zero();
         let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution;
         let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution;
-
         self.protocol_version = next_protocol_version;
 
         // Derive the reference gas price for the new epoch
         self.reference_gas_price = self.validators.derive_reference_gas_price();
         // Because of precision issues with integer divisions, we expect that there will be some
-        // remaining balance in `storage_fund_reward` and `computation_reward`.
+        // remaining balance in  `computation_reward`.
         // All of these go to the storage fund.
-        let mut leftover_staking_rewards = storage_fund_reward;
-        leftover_staking_rewards.join(computation_reward);
+        let leftover_staking_rewards = computation_reward;
         let leftover_storage_fund_inflow = leftover_staking_rewards.value();
 
         let refunded_storage_rebate =
             self.storage_fund.advance_epoch(
                 storage_reward,
-                storage_fund_reinvestment,
                 leftover_staking_rewards,
                 storage_rebate_amount,
                 non_refundable_storage_fee_amount,
@@ -923,11 +916,8 @@ module iota_system::iota_system_state_inner {
                 reference_gas_price: self.reference_gas_price,
                 total_stake: new_total_stake,
                 storage_charge,
-                storage_fund_reinvestment: storage_fund_reinvestment_amount as u64,
                 storage_rebate: storage_rebate_amount,
                 storage_fund_balance: self.storage_fund.total_balance(),
-                // TODO: Remove
-                stake_subsidy_amount: 0,
                 total_gas_fees: computation_charge,
                 total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed,
                 leftover_storage_fund_inflow,
diff --git a/crates/iota-framework/packages/iota-system/sources/storage_fund.move b/crates/iota-framework/packages/iota-system/sources/storage_fund.move
index 02b1187b07d..92767cc1a73 100644
--- a/crates/iota-framework/packages/iota-system/sources/storage_fund.move
+++ b/crates/iota-framework/packages/iota-system/sources/storage_fund.move
@@ -6,8 +6,6 @@ module iota_system::storage_fund {
     use iota::balance::{Self, Balance};
     use iota::iota::IOTA;
 
-    /* friend iota_system::iota_system_state_inner; */
-
     /// Struct representing the storage fund, containing two `Balance`s:
     /// - `total_object_storage_rebates` has the invariant that it's the sum of `storage_rebate` of
     ///    all objects currently stored on-chain. To maintain this invariant, the only inflow of this
@@ -34,13 +32,11 @@ module iota_system::storage_fund {
     public(package) fun advance_epoch(
         self: &mut StorageFund,
         storage_charges: Balance,
-        storage_fund_reinvestment: Balance,
         leftover_staking_rewards: Balance,
         storage_rebate_amount: u64,
         non_refundable_storage_fee_amount: u64,
     ) : Balance {
-        // Both the reinvestment and leftover rewards are not to be refunded so they go to the non-refundable balance.
-        self.non_refundable_balance.join(storage_fund_reinvestment);
+        // Add any leftover staking rewards to the non-refundable balance.
         self.non_refundable_balance.join(leftover_staking_rewards);
 
         // The storage charges for the epoch come from the storage rebate of the new objects created
@@ -68,4 +64,4 @@ module iota_system::storage_fund {
     public fun total_balance(self: &StorageFund): u64 {
         self.total_object_storage_rebates.value() + self.non_refundable_balance.value()
     }
-}
+}
\ No newline at end of file

From 4349f8051bd588dcfba5b79bc923ae52a9e6b9fc Mon Sep 17 00:00:00 2001
From: Dkwcs 
Date: Fri, 28 Jun 2024 00:11:25 +0300
Subject: [PATCH 21/35] refactor(iota-framework):  clear
 storage_fund_reinvest_rate variable usage

---
 .../iota-framework/docs/iota-system/iota_system.md |  5 +----
 .../docs/iota-system/iota_system_state_inner.md    | 13 ++++---------
 .../packages/iota-system/sources/iota_system.move  |  5 -----
 .../sources/iota_system_state_inner.move           |  8 +-------
 .../iota-system/sources/storage_deposits.move      | 14 ++++++++------
 .../iota-system/tests/governance_test_utils.move   |  4 ++--
 6 files changed, 16 insertions(+), 33 deletions(-)

diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md
index ae3b64aa08e..dbf99998636 100644
--- a/crates/iota-framework/docs/iota-system/iota_system.md
+++ b/crates/iota-framework/docs/iota-system/iota_system.md
@@ -1359,7 +1359,7 @@ gas coins.
 4. Update all validators.
 
 
-
fun advance_epoch(validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
fun advance_epoch(validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -1377,8 +1377,6 @@ gas coins. next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, - storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, @@ -1394,7 +1392,6 @@ gas coins. computation_reward, storage_rebate, non_refundable_storage_fee, - storage_fund_reinvest_rate, reward_slashing_rate, epoch_start_timestamp_ms, ctx, diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index b1fc7676ac1..934e12ce427 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -2033,7 +2033,7 @@ gas coins. 4. Update all validators. -
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -2051,8 +2051,6 @@ gas coins. mut computation_reward: Balance<IOTA>, mut storage_rebate_amount: u64, mut non_refundable_storage_fee_amount: u64, - storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, @@ -2061,11 +2059,7 @@ gas coins. let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64; // Rates can't be higher than 100%. - assert!( - storage_fund_reinvest_rate <= bps_denominator_u64 - && reward_slashing_rate <= bps_denominator_u64, - EBpsTooLarge, - ); + assert!(reward_slashing_rate <= bps_denominator_u64, EBpsTooLarge); // Accumulate the gas summary during safe_mode before processing any rewards: let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all(); @@ -2126,9 +2120,10 @@ gas coins. let computation_reward_amount_after_distribution = computation_reward.value(); let storage_fund_reward_amount_after_distribution = storage_fund_reward.value(); + //TODO: remove + storage_fund_reward.destroy_zero(); let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution; let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution; - storage_fund_reward.destroy_zero(); self.protocol_version = next_protocol_version; // Derive the reference gas price for the new epoch diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move index 21974e9436a..c6159e73d70 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move @@ -543,8 +543,6 @@ module iota_system::iota_system { next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, - storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, @@ -560,7 +558,6 @@ module iota_system::iota_system { computation_reward, storage_rebate, non_refundable_storage_fee, - storage_fund_reinvest_rate, reward_slashing_rate, epoch_start_timestamp_ms, ctx, @@ -750,7 +747,6 @@ module iota_system::iota_system { computation_charge: u64, storage_rebate: u64, non_refundable_storage_fee: u64, - storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut TxContext, @@ -766,7 +762,6 @@ module iota_system::iota_system { next_protocol_version, storage_rebate, non_refundable_storage_fee, - storage_fund_reinvest_rate, reward_slashing_rate, epoch_start_timestamp_ms, ctx, diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index 9ce3cf1da16..c466d278e5d 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -812,8 +812,6 @@ module iota_system::iota_system_state_inner { mut computation_reward: Balance, mut storage_rebate_amount: u64, mut non_refundable_storage_fee_amount: u64, - storage_fund_reinvest_rate: u64, // share of storage fund's rewards that's reinvested - // into storage fund, in basis point. reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, @@ -822,11 +820,7 @@ module iota_system::iota_system_state_inner { let bps_denominator_u64 = BASIS_POINT_DENOMINATOR as u64; // Rates can't be higher than 100%. - assert!( - storage_fund_reinvest_rate <= bps_denominator_u64 - && reward_slashing_rate <= bps_denominator_u64, - EBpsTooLarge, - ); + assert!(reward_slashing_rate <= bps_denominator_u64, EBpsTooLarge); // Accumulate the gas summary during safe_mode before processing any rewards: let safe_mode_storage_rewards = self.safe_mode_storage_rewards.withdraw_all(); diff --git a/crates/iota-framework/packages/iota-system/sources/storage_deposits.move b/crates/iota-framework/packages/iota-system/sources/storage_deposits.move index a262cd64f84..00a5ae0a89e 100644 --- a/crates/iota-framework/packages/iota-system/sources/storage_deposits.move +++ b/crates/iota-framework/packages/iota-system/sources/storage_deposits.move @@ -3,20 +3,22 @@ // SPDX-License-Identifier: Apache-2.0 module iota_system::storage_deposits { - use iota::balance::Balance; + use iota::balance::{Self, Balance}; use iota::iota::IOTA; /// Struct representing the storage deposits fund, containing a `Balance`: /// - `storage_balance` tracks the total balance of storage fees collected from transactions. public struct StorageDeposits has store { - storage_balance: Balance, + refundable_balance: Balance, + non_refundable_balance: Balance } /// Called by `iota_system` at genesis time. public(package) fun new(initial_balance: Balance) : StorageDeposits { StorageDeposits { // Initialize the storage deposits balance - storage_balance: initial_balance, + refundable_balance: initial_balance, + non_refundable_balance: balance::zero() } } @@ -26,9 +28,9 @@ module iota_system::storage_deposits { storage_charges: Balance, storage_rebate_amount: u64, ) : Balance { - self.storage_balance.join(storage_charges); + self.refundable_balance.join(storage_charges); - let storage_rebate = self.storage_balance.split(storage_rebate_amount); + let storage_rebate = self.refundable_balance.split(storage_rebate_amount); //TODO: possibly mint and burn tokens here // mint_iota(treasury_cap, storage_charges.value(), ctx); @@ -37,6 +39,6 @@ module iota_system::storage_deposits { } public fun total_balance(self: &StorageDeposits): u64 { - self.storage_balance.value() + self.refundable_balance.value() + self.non_refundable_balance.value() } } diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move index 665ee55a2b1..40f2d5438f1 100644 --- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move +++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move @@ -118,7 +118,7 @@ module iota_system::governance_test_utils { let ctx = scenario.ctx(); let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, validator_target_reward, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, 0, ctx, + new_epoch, 1, validator_target_reward, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, ctx, ); test_scenario::return_shared(system_state); scenario.next_epoch(@0x0); @@ -146,7 +146,7 @@ module iota_system::governance_test_utils { let validator_target_reward = computation_charge * MICROS_PER_IOTA; let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, validator_target_reward, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, 0, reward_slashing_rate, 0, ctx + new_epoch, 1, validator_target_reward, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, reward_slashing_rate, 0, ctx ); test_utils::destroy(storage_rebate); test_scenario::return_shared(system_state); From 97c9c5838e44de9fad2ad39a2300d42f0efb41e8 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 28 Jun 2024 12:30:59 +0200 Subject: [PATCH 22/35] feat: Compute the total validator reward based on target reward --- .../iota-system/iota_system_state_inner.md | 18 ++----- .../docs/iota-system/validator_set.md | 47 +++++++++++++++++++ .../sources/iota_system_state_inner.move | 18 ++----- .../iota-system/sources/validator_set.move | 25 ++++++++++ .../iota-system/tests/delegation_tests.move | 21 +++++---- .../tests/rewards_distribution_tests.move | 43 ++++++++--------- 6 files changed, 115 insertions(+), 57 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 934e12ce427..837ef76bc0c 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -2078,19 +2078,11 @@ gas coins. let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); - let mut computation_reward = if (computation_reward.value() < validator_target_reward) { - let tokens_to_mint = validator_target_reward - computation_reward.value(); - let new_tokens = self.iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint); - computation_reward.join(new_tokens); - computation_reward - } else if (computation_reward.value() > validator_target_reward) { - let tokens_to_burn = computation_reward.value() - validator_target_reward; - let rewards_to_burn = computation_reward.split(tokens_to_burn); - self.iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn); - computation_reward - } else { - computation_reward - }; + let mut computation_reward = self.validators.match_iota_supply_to_target_reward( + validator_target_reward, + computation_reward, + &mut self.iota_treasury_cap, + ); let total_stake_u128 = total_stake as u128; let computation_charge_u128 = computation_charge as u128; diff --git a/crates/iota-framework/docs/iota-system/validator_set.md b/crates/iota-framework/docs/iota-system/validator_set.md index 98d96d0b20c..404f07dd667 100644 --- a/crates/iota-framework/docs/iota-system/validator_set.md +++ b/crates/iota-framework/docs/iota-system/validator_set.md @@ -31,6 +31,7 @@ title: Module `0x3::validator_set` - [Function `pool_exchange_rates`](#0x3_validator_set_pool_exchange_rates) - [Function `next_epoch_validator_count`](#0x3_validator_set_next_epoch_validator_count) - [Function `is_active_validator_by_iota_address`](#0x3_validator_set_is_active_validator_by_iota_address) +- [Function `match_iota_supply_to_target_reward`](#0x3_validator_set_match_iota_supply_to_target_reward) - [Function `is_duplicate_with_active_validator`](#0x3_validator_set_is_duplicate_with_active_validator) - [Function `is_duplicate_validator`](#0x3_validator_set_is_duplicate_validator) - [Function `count_duplicates_vec`](#0x3_validator_set_count_duplicates_vec) @@ -75,6 +76,7 @@ title: Module `0x3::validator_set` use 0x1::vector; use 0x2::bag; use 0x2::balance; +use 0x2::coin; use 0x2::event; use 0x2::iota; use 0x2::object; @@ -1461,6 +1463,51 @@ Returns true iff the address exists in active validators. + + + + +## Function `match_iota_supply_to_target_reward` + +Inflate or deflate the IOTA supply depending on the given target reward per validator +and the amount of computation fees burned in this epoch. + + +
public(friend) fun match_iota_supply_to_target_reward(self: &validator_set::ValidatorSet, validator_target_reward: u64, computation_reward: balance::Balance<iota::IOTA>, iota_treasury_cap: &mut coin::TreasuryCap<iota::IOTA>): balance::Balance<iota::IOTA>
+
+ + + +
+Implementation + + +
public(package) fun match_iota_supply_to_target_reward(
+  self: &ValidatorSet,
+  validator_target_reward: u64,
+  mut computation_reward: Balance<IOTA>,
+  iota_treasury_cap: &mut iota::coin::TreasuryCap<IOTA>
+): Balance<IOTA> {
+  let validator_reward_total = validator_target_reward * self.active_validators.length();
+
+  if (computation_reward.value() < validator_reward_total) {
+    let tokens_to_mint = validator_reward_total - computation_reward.value();
+    let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint);
+    computation_reward.join(new_tokens);
+    computation_reward
+  } else if (computation_reward.value() > validator_reward_total) {
+    let tokens_to_burn = computation_reward.value() - validator_reward_total;
+    let rewards_to_burn = computation_reward.split(tokens_to_burn);
+    iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn);
+    computation_reward
+  } else {
+    computation_reward
+  }
+}
+
+ + +
diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index c466d278e5d..e6a241207fa 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -839,19 +839,11 @@ module iota_system::iota_system_state_inner { let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); - let mut computation_reward = if (computation_reward.value() < validator_target_reward) { - let tokens_to_mint = validator_target_reward - computation_reward.value(); - let new_tokens = self.iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint); - computation_reward.join(new_tokens); - computation_reward - } else if (computation_reward.value() > validator_target_reward) { - let tokens_to_burn = computation_reward.value() - validator_target_reward; - let rewards_to_burn = computation_reward.split(tokens_to_burn); - self.iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn); - computation_reward - } else { - computation_reward - }; + let mut computation_reward = self.validators.match_iota_supply_to_target_reward( + validator_target_reward, + computation_reward, + &mut self.iota_treasury_cap, + ); let total_stake_u128 = total_stake as u128; let computation_charge_u128 = computation_charge as u128; diff --git a/crates/iota-framework/packages/iota-system/sources/validator_set.move b/crates/iota-framework/packages/iota-system/sources/validator_set.move index 6ef543868b1..dbf6ac21120 100644 --- a/crates/iota-framework/packages/iota-system/sources/validator_set.move +++ b/crates/iota-framework/packages/iota-system/sources/validator_set.move @@ -580,6 +580,31 @@ module iota_system::validator_set { find_validator(&self.active_validators, validator_address).is_some() } + /// Inflate or deflate the IOTA supply depending on the given target reward per validator + /// and the amount of computation fees burned in this epoch. + public(package) fun match_iota_supply_to_target_reward( + self: &ValidatorSet, + validator_target_reward: u64, + mut computation_reward: Balance, + iota_treasury_cap: &mut iota::coin::TreasuryCap + ): Balance { + let validator_reward_total = validator_target_reward * self.active_validators.length(); + + if (computation_reward.value() < validator_reward_total) { + let tokens_to_mint = validator_reward_total - computation_reward.value(); + let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint); + computation_reward.join(new_tokens); + computation_reward + } else if (computation_reward.value() > validator_reward_total) { + let tokens_to_burn = computation_reward.value() - validator_reward_total; + let rewards_to_burn = computation_reward.split(tokens_to_burn); + iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn); + computation_reward + } else { + computation_reward + } + } + // ==== private helpers ==== /// Checks whether `new_validator` is duplicate with any currently active validators. diff --git a/crates/iota-framework/packages/iota-system/tests/delegation_tests.move b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move index e98e4bc32eb..bb3cebe91b0 100644 --- a/crates/iota-framework/packages/iota-system/tests/delegation_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move @@ -28,6 +28,7 @@ module iota_system::stake_tests { unstake, }; + const VALIDATOR_COUNT: u64 = 2; const VALIDATOR_ADDR_1: address = @0x1; const VALIDATOR_ADDR_2: address = @0x2; @@ -233,7 +234,7 @@ module iota_system::stake_tests { if (should_distribute_rewards) { // Each validator pool gets 30 MICROS and each validator gets an additional 10 MICROS. - advance_epoch_with_reward_amounts(80, 0, 80, scenario); + advance_epoch_with_reward_amounts(80/VALIDATOR_COUNT, 0, 80, scenario); } else { advance_epoch(scenario); }; @@ -292,7 +293,7 @@ module iota_system::stake_tests { // Add some rewards after the validator requests to leave. Since the validator is still active // this epoch, they should get the rewards from this epoch. - advance_epoch_with_reward_amounts(80, 0, 80, scenario); + advance_epoch_with_reward_amounts(80/VALIDATOR_COUNT, 0, 80, scenario); // Each validator pool gets 30 MICROS and validators shares the 20 MICROS from the storage fund // so validator gets another 10 MICROS. @@ -374,8 +375,8 @@ module iota_system::stake_tests { stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); // Advance epoch twice with some rewards - advance_epoch_with_reward_amounts(400, 0, 400, scenario); - advance_epoch_with_reward_amounts(900, 0, 900, scenario); + advance_epoch_with_reward_amounts(400/VALIDATOR_COUNT, 0, 400, scenario); + advance_epoch_with_reward_amounts(900/VALIDATOR_COUNT, 0, 900, scenario); // Unstake from the preactive validator. There should be no rewards earned. unstake(STAKER_ADDR_1, 0, scenario); @@ -412,7 +413,7 @@ module iota_system::stake_tests { // Delegate 100 IOTA to the preactive validator stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); - advance_epoch_with_reward_amounts(300, 0, 300, scenario); + advance_epoch_with_reward_amounts(300/VALIDATOR_COUNT, 0, 300, scenario); // At this point we got the following distribution of stake: // V1: 250, V2: 250, storage fund: 100 @@ -426,7 +427,7 @@ module iota_system::stake_tests { // At this point we got the following distribution of stake: // V1: 250, V2: 250, V3: 250, storage fund: 100 - advance_epoch_with_reward_amounts(85, 0, 85, scenario); + advance_epoch_with_reward_amounts(85/VALIDATOR_COUNT, 0, 85, scenario); // staker 1 and 3 unstake from the validator and earns about 2/5 * (85 - 10) * 1/3 = 10 IOTA each. // Although they stake in different epochs, they earn the same rewards as long as they unstake @@ -437,7 +438,7 @@ module iota_system::stake_tests { unstake(STAKER_ADDR_3, 0, scenario); assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 110002000000); - advance_epoch_with_reward_amounts(85, 0, 85, scenario); + advance_epoch_with_reward_amounts(85/VALIDATOR_COUNT, 0, 85, scenario); unstake(STAKER_ADDR_2, 0, scenario); // staker 2 earns about 5 IOTA from the previous epoch and 24-ish from this one // so in total she has about 50 + 5 + 24 = 79 IOTA. @@ -463,7 +464,7 @@ module iota_system::stake_tests { // staker 1 earns a bit greater than 30 IOTA here. A bit greater because the new validator's voting power // is slightly greater than 1/3 of the total voting power. - advance_epoch_with_reward_amounts(90, 0, 90, scenario); + advance_epoch_with_reward_amounts(90/VALIDATOR_COUNT, 0, 90, scenario); // And now the validator leaves the validator set. remove_validator(NEW_VALIDATOR_ADDR, scenario); @@ -488,7 +489,7 @@ module iota_system::stake_tests { stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); // Advance epoch and give out some rewards. The candidate should get nothing, of course. - advance_epoch_with_reward_amounts(800, 0, 800, scenario); + advance_epoch_with_reward_amounts(800/VALIDATOR_COUNT, 0, 800, scenario); // Now the candidate leaves. remove_validator_candidate(NEW_VALIDATOR_ADDR, scenario); @@ -517,7 +518,7 @@ module iota_system::stake_tests { test_scenario::return_to_address(@0x42, staked_iota); advance_epoch(scenario); // advances epoch to effectuate the stake // Each staking pool gets 10 IOTA of rewards. - advance_epoch_with_reward_amounts(20, 0, 20, scenario); + advance_epoch_with_reward_amounts(20/VALIDATOR_COUNT, 0, 20, scenario); let mut system_state = scenario.take_shared(); let rates = system_state.pool_exchange_rates(&pool_id); assert_eq(rates.length(), 3); diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move index 801ca269bb2..6197b921c10 100644 --- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move @@ -23,6 +23,7 @@ module iota_system::rewards_distribution_tests { use iota::test_utils::assert_eq; use iota::address; + const VALIDATOR_COUNT: u64 = 4; const VALIDATOR_ADDR_1: address = @0x1; const VALIDATOR_ADDR_2: address = @0x2; const VALIDATOR_ADDR_3: address = @0x3; @@ -44,7 +45,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(100, 0, 100, scenario); + advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 100, scenario); assert_validator_total_stake_amounts( validator_addrs(), vector[125 * MICROS_PER_IOTA, 225 * MICROS_PER_IOTA, 325 * MICROS_PER_IOTA, 425 * MICROS_PER_IOTA], @@ -54,7 +55,7 @@ module iota_system::rewards_distribution_tests { stake_with(VALIDATOR_ADDR_2, VALIDATOR_ADDR_2, 720, scenario); advance_epoch(scenario); - advance_epoch_with_reward_amounts(100, 0, 100, scenario); + advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 100, scenario); // Even though validator 2 has a lot more stake now, it should not get more rewards because // the voting power is capped at 10%. assert_validator_total_stake_amounts( @@ -74,7 +75,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(100, 0, 100, scenario); + advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 100, scenario); assert_validator_total_stake_amounts(validator_addrs(), vector[100_000_025 * MICROS_PER_IOTA, 200_000_025 * MICROS_PER_IOTA, 300_000_025 * MICROS_PER_IOTA, 400_000_025 * MICROS_PER_IOTA], scenario); scenario_val.end(); } @@ -88,7 +89,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(100, 0, 100, scenario); + advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 100, scenario); let new_supply = total_supply(scenario); assert!(prev_supply == new_supply, 0); @@ -105,7 +106,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(60, 0, 100, scenario); + advance_epoch_with_reward_amounts(60/VALIDATOR_COUNT, 0, 100, scenario); let new_supply = total_supply(scenario); // 40 tokens should have been burned. @@ -123,7 +124,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(100, 0, 60, scenario); + advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 60, scenario); let new_supply = total_supply(scenario); // 40 tokens should have been minted. @@ -146,19 +147,19 @@ module iota_system::rewards_distribution_tests { assert_validator_self_stake_amounts(validator_addrs(), vector[100 * MICROS_PER_IOTA, 200 * MICROS_PER_IOTA, 300 * MICROS_PER_IOTA, 400 * MICROS_PER_IOTA], scenario); // Each pool gets 30 IOTA. - advance_epoch_with_reward_amounts(120, 0, 120, scenario); + advance_epoch_with_reward_amounts(120/VALIDATOR_COUNT, 0, 120, scenario); assert_validator_self_stake_amounts(validator_addrs(), vector[110 * MICROS_PER_IOTA, 220 * MICROS_PER_IOTA, 330 * MICROS_PER_IOTA, 430 * MICROS_PER_IOTA], scenario); unstake(STAKER_ADDR_1, 0, scenario); stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 600, scenario); // Each pool gets 30 IOTA. - advance_epoch_with_reward_amounts(120, 0, 120, scenario); + advance_epoch_with_reward_amounts(120/VALIDATOR_COUNT, 0, 120, scenario); // staker 1 receives only 20 IOTA of rewards, not 40 since we are using pre-epoch exchange rate. assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 220 * MICROS_PER_IOTA); assert_validator_self_stake_amounts(validator_addrs(), vector[140 * MICROS_PER_IOTA, 240 * MICROS_PER_IOTA, 360 * MICROS_PER_IOTA, 460 * MICROS_PER_IOTA], scenario); unstake(STAKER_ADDR_2, 0, scenario); assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 120 * MICROS_PER_IOTA); // 20 IOTA of rewards received - advance_epoch_with_reward_amounts(40, 0, 40, scenario); + advance_epoch_with_reward_amounts(40/VALIDATOR_COUNT, 0, 40, scenario); unstake(STAKER_ADDR_2, 0, scenario); // unstake 600 principal IOTA // additional 600 IOTA of principal and 46 IOTA of rewards withdrawn to Coin @@ -182,17 +183,17 @@ module iota_system::rewards_distribution_tests { advance_epoch(scenario); - advance_epoch_with_reward_amounts(150000, 0, 150000, scenario); + advance_epoch_with_reward_amounts(150000/VALIDATOR_COUNT, 0, 150000, scenario); // stake a small amount stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 10, scenario); - advance_epoch_with_reward_amounts(130, 0, 130, scenario); + advance_epoch_with_reward_amounts(130/VALIDATOR_COUNT, 0, 130, scenario); // unstake the stakes unstake(STAKER_ADDR_1, 1, scenario); // and advance epoch should succeed - advance_epoch_with_reward_amounts(150, 0, 150, scenario); + advance_epoch_with_reward_amounts(150/VALIDATOR_COUNT, 0, 150, scenario); scenario_val.end(); } @@ -208,7 +209,7 @@ module iota_system::rewards_distribution_tests { // V1: 200, V2: 300, V3: 300, V4: 400 set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_2, 2000, scenario); // 50% commission - advance_epoch_with_reward_amounts(120, 0, 120, scenario); + advance_epoch_with_reward_amounts(120/VALIDATOR_COUNT, 0, 120, scenario); // V1: 230, V2: 330, V3: 330, V4: 430 // 2 IOTA, or 20 % of staker_2's rewards, goes to validator_2 assert_validator_non_self_stake_amounts(validator_addrs(), vector[115 * MICROS_PER_IOTA, 108 * MICROS_PER_IOTA, 0, 0], scenario); @@ -216,7 +217,7 @@ module iota_system::rewards_distribution_tests { set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_1, 1000, scenario); // 10% commission - advance_epoch_with_reward_amounts(240, 0, 240, scenario); + advance_epoch_with_reward_amounts(240/VALIDATOR_COUNT, 0, 240, scenario); assert_validator_total_stake_amounts(validator_addrs(), vector[290 * MICROS_PER_IOTA, 390 * MICROS_PER_IOTA, 390 * MICROS_PER_IOTA, 490 * MICROS_PER_IOTA], scenario); // Staker 1 rewards in the recent distribution is 0.9 x 30 = 27 IOTA @@ -337,7 +338,7 @@ module iota_system::rewards_distribution_tests { // 1000 IOTA of storage rewards, 1500 IOTA of computation rewards, 50% slashing threshold // and 20% slashing rate advance_epoch_with_reward_amounts_and_slashing_rates( - 1000, 1500, 2000, scenario + 1000/VALIDATOR_COUNT, 1500, 2000, scenario ); // Each unslashed validator staking pool gets 300 IOTA of computation rewards + 75 IOTA of storage fund rewards + @@ -381,7 +382,7 @@ module iota_system::rewards_distribution_tests { report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_1, scenario); advance_epoch_with_reward_amounts_and_slashing_rates( - 1000, 3000, 10_000, scenario + 1000/VALIDATOR_COUNT, 3000, 10_000, scenario ); // All validators should have 0 rewards added so their stake stays the same. @@ -407,23 +408,23 @@ module iota_system::rewards_distribution_tests { stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 220, scenario); - advance_epoch_with_reward_amounts(40, 0, 40, scenario); + advance_epoch_with_reward_amounts(40/VALIDATOR_COUNT, 0, 40, scenario); stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 480, scenario); // Staker 1 gets 2/3 * 1/4 * 120 = 20 IOTA here. - advance_epoch_with_reward_amounts(120, 0, 120, scenario); + advance_epoch_with_reward_amounts(120/VALIDATOR_COUNT, 0, 120, scenario); stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 130, scenario); stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 390, scenario); // Staker 1 gets 20 IOTA here and staker 2 gets 40 IOTA here. - advance_epoch_with_reward_amounts(280, 0, 280, scenario); + advance_epoch_with_reward_amounts(280/VALIDATOR_COUNT, 0, 280, scenario); stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 280, scenario); stake_with(STAKER_ADDR_4, VALIDATOR_ADDR_1, 1400, scenario); // Staker 1 gets 30 IOTA, staker 2 gets 40 IOTA and staker 3 gets 30 IOTA. - advance_epoch_with_reward_amounts(440, 0, 440, scenario); + advance_epoch_with_reward_amounts(440/VALIDATOR_COUNT, 0, 440, scenario); scenario.next_tx(@0x0); let mut system_state = scenario.take_shared(); @@ -480,7 +481,7 @@ module iota_system::rewards_distribution_tests { create_iota_system_state_for_testing(validators, 0, 0, ctx); // Each validator's stake gets doubled. - advance_epoch_with_reward_amounts(10000, 0, 10000, scenario); + advance_epoch_with_reward_amounts(10000/VALIDATOR_COUNT, 0, 10000, scenario); let mut i = 0; scenario.next_tx(@0x0); From 5913666ee07c04364a94a55ad29dc8799c0b25f5 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 28 Jun 2024 13:58:40 +0200 Subject: [PATCH 23/35] feat: Add total iota supply to system state summary --- crates/iota-protocol-config/src/lib.rs | 3 +-- .../iota_system_state_inner_v1.rs | 4 ++-- .../iota_system_state_inner_v2.rs | 4 ++-- .../iota_system_state_summary.rs | 16 +++++++--------- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/crates/iota-protocol-config/src/lib.rs b/crates/iota-protocol-config/src/lib.rs index 555ed70d672..e20898d6fe0 100644 --- a/crates/iota-protocol-config/src/lib.rs +++ b/crates/iota-protocol-config/src/lib.rs @@ -659,8 +659,7 @@ pub struct ProtocolConfig { /// Unit gas price, Micros per internal gas unit. storage_gas_price: Option, - /// The number of tokens that validators should receive per epoch when - /// performing optimally. + /// The number of tokens that the set of validators should receive per epoch. validator_target_reward: Option, /// === Core Protocol === diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs index 311201d93dc..6def4bb67ac 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs @@ -591,8 +591,7 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { epoch, protocol_version, system_state_version, - // TODO: Add this to the system state summary. - iota_treasury_cap: _, + iota_treasury_cap, validators: ValidatorSetV1 { total_stake, @@ -666,6 +665,7 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { safe_mode_storage_rebates, safe_mode_non_refundable_storage_fee, epoch_start_timestamp_ms, + total_iota_supply_nanos: iota_treasury_cap.total_supply.value, // TODO: Remove stake_subsidy_start_epoch: 0, epoch_duration_ms, diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs index 5764f7e89b0..6a94c596c5b 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs @@ -202,8 +202,7 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { epoch, protocol_version, system_state_version, - // TODO: Add this to the system state summary. - iota_treasury_cap: _, + iota_treasury_cap, validators: ValidatorSetV1 { total_stake, @@ -281,6 +280,7 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { epoch_start_timestamp_ms, stake_subsidy_start_epoch, epoch_duration_ms, + total_iota_supply_nanos: iota_treasury_cap.total_supply.value, // TODO: Remove stake_subsidy_distribution_counter: 0, stake_subsidy_balance: 0, diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs b/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs index c6c11c80d04..ef808b51445 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs @@ -11,15 +11,7 @@ use serde_with::serde_as; use super::{IotaSystemState, IotaSystemStateTrait}; use crate::{ - base_types::{AuthorityName, IotaAddress, ObjectID}, - committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, - dynamic_field::get_dynamic_field_from_store, - error::IotaError, - id::ID, - iota_serde::{BigInt, Readable}, - iota_system_state::get_validator_from_table, - multiaddr::Multiaddr, - storage::ObjectStore, + base_types::{AuthorityName, IotaAddress, ObjectID}, committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, dynamic_field::get_dynamic_field_from_store, error::IotaError, gas_coin::TOTAL_SUPPLY_MICROS, id::ID, iota_serde::{BigInt, Readable}, iota_system_state::get_validator_from_table, multiaddr::Multiaddr, storage::ObjectStore }; /// This is the JSON-RPC type for the IOTA system state object. @@ -128,6 +120,11 @@ pub struct IotaSystemStateSummary { #[serde_as(as = "Readable, _>")] pub validator_low_stake_grace_period: u64, + /// The current total supply of IOTA in nanos. + #[schemars(with = "BigInt")] + #[serde_as(as = "Readable, _>")] + pub total_iota_supply_nanos: u64, + // Stake subsidy information /// Balance of IOTA set aside for stake subsidies that will be drawn down /// over time. @@ -359,6 +356,7 @@ impl Default for IotaSystemStateSummary { validator_low_stake_threshold: 0, validator_very_low_stake_threshold: 0, validator_low_stake_grace_period: 0, + total_iota_supply_nanos: TOTAL_SUPPLY_MICROS, stake_subsidy_balance: 0, stake_subsidy_distribution_counter: 0, stake_subsidy_current_distribution_amount: 0, From 31cafc9b7403c9f3d47e808140fd748cdf9c2c2a Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 28 Jun 2024 14:07:24 +0200 Subject: [PATCH 24/35] feat: Remove stake subsidy params form state summary --- .../iota_system_state_inner_v1.rs | 9 ----- .../iota_system_state_inner_v2.rs | 12 ------- .../iota_system_state_summary.rs | 35 ------------------- 3 files changed, 56 deletions(-) diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs index 6def4bb67ac..09cab92f4ea 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v1.rs @@ -666,13 +666,7 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { safe_mode_non_refundable_storage_fee, epoch_start_timestamp_ms, total_iota_supply_nanos: iota_treasury_cap.total_supply.value, - // TODO: Remove - stake_subsidy_start_epoch: 0, epoch_duration_ms, - // TODO: Remove - stake_subsidy_distribution_counter: 0, - stake_subsidy_balance: 0, - stake_subsidy_current_distribution_amount: 0, total_stake, active_validators: active_validators .into_iter() @@ -700,9 +694,6 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { validator_low_stake_threshold, validator_very_low_stake_threshold, validator_low_stake_grace_period, - // TODO: Remove - stake_subsidy_period_length: 0, - stake_subsidy_decrease_rate: 0, } } } diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs index 6a94c596c5b..115880ef7a5 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_inner_v2.rs @@ -33,9 +33,6 @@ pub struct SystemParametersV2 { /// The duration of an epoch, in milliseconds. pub epoch_duration_ms: u64, - /// The starting epoch in which stake subsidies start being paid out - pub stake_subsidy_start_epoch: u64, - /// Minimum number of active validators at any moment. pub min_validator_count: u64, @@ -240,7 +237,6 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { storage_fund, parameters: SystemParametersV2 { - stake_subsidy_start_epoch, epoch_duration_ms, min_validator_count: _, // TODO: Add it to RPC layer in the future. max_validator_count, @@ -278,13 +274,8 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { safe_mode_storage_rebates, safe_mode_non_refundable_storage_fee, epoch_start_timestamp_ms, - stake_subsidy_start_epoch, epoch_duration_ms, total_iota_supply_nanos: iota_treasury_cap.total_supply.value, - // TODO: Remove - stake_subsidy_distribution_counter: 0, - stake_subsidy_balance: 0, - stake_subsidy_current_distribution_amount: 0, total_stake, active_validators: active_validators .into_iter() @@ -312,9 +303,6 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { validator_low_stake_threshold, validator_very_low_stake_threshold, validator_low_stake_grace_period, - // TODO: Remove - stake_subsidy_period_length: 0, - stake_subsidy_decrease_rate: 0, } } } diff --git a/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs b/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs index ef808b51445..5a86a215266 100644 --- a/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs +++ b/crates/iota-types/src/iota_system_state/iota_system_state_summary.rs @@ -84,11 +84,6 @@ pub struct IotaSystemStateSummary { #[serde_as(as = "Readable, _>")] pub epoch_duration_ms: u64, - /// The starting epoch in which stake subsidies start being paid out - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_start_epoch: u64, - /// Maximum number of active validators at any moment. /// We do not allow the number of validators in any epoch to go above this. #[schemars(with = "BigInt")] @@ -125,30 +120,6 @@ pub struct IotaSystemStateSummary { #[serde_as(as = "Readable, _>")] pub total_iota_supply_nanos: u64, - // Stake subsidy information - /// Balance of IOTA set aside for stake subsidies that will be drawn down - /// over time. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_balance: u64, - /// This counter may be different from the current epoch number if - /// in some epochs we decide to skip the subsidy. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_distribution_counter: u64, - /// The amount of stake subsidy to be drawn down per epoch. - /// This amount decays and decreases over time. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_current_distribution_amount: u64, - /// Number of distributions to occur before the distribution amount decays. - #[schemars(with = "BigInt")] - #[serde_as(as = "Readable, _>")] - pub stake_subsidy_period_length: u64, - /// The rate at which the distribution amount decays at the end of each - /// period. Expressed in basis points. - pub stake_subsidy_decrease_rate: u16, - // Validator set /// Total amount of stake from all active validators at the beginning of the /// epoch. @@ -350,18 +321,12 @@ impl Default for IotaSystemStateSummary { safe_mode_non_refundable_storage_fee: 0, epoch_start_timestamp_ms: 0, epoch_duration_ms: 0, - stake_subsidy_start_epoch: 0, max_validator_count: 0, min_validator_joining_stake: 0, validator_low_stake_threshold: 0, validator_very_low_stake_threshold: 0, validator_low_stake_grace_period: 0, total_iota_supply_nanos: TOTAL_SUPPLY_MICROS, - stake_subsidy_balance: 0, - stake_subsidy_distribution_counter: 0, - stake_subsidy_current_distribution_amount: 0, - stake_subsidy_period_length: 0, - stake_subsidy_decrease_rate: 0, total_stake: 0, active_validators: vec![], pending_active_validators_id: ObjectID::ZERO, From 5615ebba47db053b139e2285c1a9193f302a726e Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 28 Jun 2024 14:18:45 +0200 Subject: [PATCH 25/35] feat: Remove more stake subsidy related params --- crates/iota-graphql-rpc/src/types/mod.rs | 1 - .../src/types/stake_subsidy.rs | 31 ------------------- .../src/types/system_parameters.rs | 3 -- .../src/types/system_state_summary.rs | 18 ++--------- .../iota-indexer/src/apis/governance_api.rs | 15 +++++---- crates/iota-json-rpc/src/governance_api.rs | 18 ++++++----- 6 files changed, 21 insertions(+), 65 deletions(-) delete mode 100644 crates/iota-graphql-rpc/src/types/stake_subsidy.rs diff --git a/crates/iota-graphql-rpc/src/types/mod.rs b/crates/iota-graphql-rpc/src/types/mod.rs index 7c1c026ab15..bc7d250b44e 100644 --- a/crates/iota-graphql-rpc/src/types/mod.rs +++ b/crates/iota-graphql-rpc/src/types/mod.rs @@ -42,7 +42,6 @@ pub(crate) mod protocol_config; pub(crate) mod query; pub(crate) mod safe_mode; pub(crate) mod stake; -pub(crate) mod stake_subsidy; pub(crate) mod storage_fund; pub(crate) mod string_input; pub(crate) mod system_parameters; diff --git a/crates/iota-graphql-rpc/src/types/stake_subsidy.rs b/crates/iota-graphql-rpc/src/types/stake_subsidy.rs deleted file mode 100644 index 4073c251747..00000000000 --- a/crates/iota-graphql-rpc/src/types/stake_subsidy.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// Modifications Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use async_graphql::*; - -use super::big_int::BigInt; - -/// Parameters that control the distribution of the stake subsidy. -#[derive(Clone, Debug, PartialEq, Eq, SimpleObject)] -pub(crate) struct StakeSubsidy { - /// IOTA set aside for stake subsidies -- reduces over time as stake - /// subsidies are paid out over time. - pub balance: Option, - - /// Number of times stake subsidies have been distributed subsidies are - /// distributed with other staking rewards, at the end of the epoch. - pub distribution_counter: Option, - - /// Amount of stake subsidy deducted from the balance per distribution -- - /// decays over time. - pub current_distribution_amount: Option, - - /// Maximum number of stake subsidy distributions that occur with the same - /// distribution amount (before the amount is reduced). - pub period_length: Option, - - /// Percentage of the current distribution amount to deduct at the end of - /// the current subsidy period, expressed in basis points. - pub decrease_rate: Option, -} diff --git a/crates/iota-graphql-rpc/src/types/system_parameters.rs b/crates/iota-graphql-rpc/src/types/system_parameters.rs index f506aa69ef6..091fa23661f 100644 --- a/crates/iota-graphql-rpc/src/types/system_parameters.rs +++ b/crates/iota-graphql-rpc/src/types/system_parameters.rs @@ -11,9 +11,6 @@ pub(crate) struct SystemParameters { /// Target duration of an epoch, in milliseconds. pub duration_ms: Option, - /// The epoch at which stake subsidies start being paid out. - pub stake_subsidy_start_epoch: Option, - /// The minimum number of active validators that the system supports. pub min_validator_count: Option, diff --git a/crates/iota-graphql-rpc/src/types/system_state_summary.rs b/crates/iota-graphql-rpc/src/types/system_state_summary.rs index 93c397f9568..f5661b0b222 100644 --- a/crates/iota-graphql-rpc/src/types/system_state_summary.rs +++ b/crates/iota-graphql-rpc/src/types/system_state_summary.rs @@ -6,8 +6,8 @@ use async_graphql::*; use iota_types::iota_system_state::iota_system_state_summary::IotaSystemStateSummary as NativeSystemStateSummary; use super::{ - big_int::BigInt, gas::GasCostSummary, safe_mode::SafeMode, stake_subsidy::StakeSubsidy, - storage_fund::StorageFund, system_parameters::SystemParameters, + big_int::BigInt, gas::GasCostSummary, safe_mode::SafeMode, storage_fund::StorageFund, + system_parameters::SystemParameters, }; #[derive(Clone, Debug)] @@ -58,7 +58,6 @@ impl SystemStateSummary { async fn system_parameters(&self) -> Option { Some(SystemParameters { duration_ms: Some(BigInt::from(self.native.epoch_duration_ms)), - stake_subsidy_start_epoch: Some(self.native.stake_subsidy_start_epoch), // TODO min validator count can be extracted, but it requires some JSON RPC changes, // so we decided to wait on it for now. min_validator_count: None, @@ -77,17 +76,4 @@ impl SystemStateSummary { )), }) } - - /// Parameters related to the subsidy that supplements staking rewards - async fn system_stake_subsidy(&self) -> Option { - Some(StakeSubsidy { - balance: Some(BigInt::from(self.native.stake_subsidy_balance)), - distribution_counter: Some(self.native.stake_subsidy_distribution_counter), - current_distribution_amount: Some(BigInt::from( - self.native.stake_subsidy_current_distribution_amount, - )), - period_length: Some(self.native.stake_subsidy_period_length), - decrease_rate: Some(self.native.stake_subsidy_decrease_rate as u64), - }) - } } diff --git a/crates/iota-indexer/src/apis/governance_api.rs b/crates/iota-indexer/src/apis/governance_api.rs index 0460b245058..ddf5b2dd087 100644 --- a/crates/iota-indexer/src/apis/governance_api.rs +++ b/crates/iota-indexer/src/apis/governance_api.rs @@ -51,14 +51,17 @@ impl GovernanceReadApi { let system_state_summary: IotaSystemStateSummary = self.get_latest_iota_system_state().await?; let epoch = system_state_summary.epoch; - let stake_subsidy_start_epoch = system_state_summary.stake_subsidy_start_epoch; + // let stake_subsidy_start_epoch = + // system_state_summary.stake_subsidy_start_epoch; - let exchange_rate_table = exchange_rates(self, system_state_summary).await?; + // let exchange_rate_table = exchange_rates(self, system_state_summary).await?; - let apys = iota_json_rpc::governance_api::calculate_apys( - stake_subsidy_start_epoch, - exchange_rate_table, - ); + // TODO: Create issue to fix this later. + let apys = vec![]; + // let apys = iota_json_rpc::governance_api::calculate_apys( + // stake_subsidy_start_epoch, + // exchange_rate_table, + // ); Ok(ValidatorApys { apys, epoch }) } diff --git a/crates/iota-json-rpc/src/governance_api.rs b/crates/iota-json-rpc/src/governance_api.rs index 8a830817c4d..f8c3d9a8c83 100644 --- a/crates/iota-json-rpc/src/governance_api.rs +++ b/crates/iota-json-rpc/src/governance_api.rs @@ -412,14 +412,16 @@ impl GovernanceReadApiServer for GovernanceReadApi { let system_state_summary: IotaSystemStateSummary = self.get_latest_iota_system_state().await?; - let exchange_rate_table = exchange_rates(&self.state, system_state_summary.epoch) - .await - .map_err(Error::from)?; - - let apys = calculate_apys( - system_state_summary.stake_subsidy_start_epoch, - exchange_rate_table, - ); + // let exchange_rate_table = exchange_rates(&self.state, system_state_summary.epoch) + // .await + // .map_err(Error::from)?; + + let apys = vec![]; + // TODO: Create issue to fix this later. + // = calculate_apys( + // system_state_summary.stake_subsidy_start_epoch, + // exchange_rate_table, + // ); Ok(ValidatorApys { apys, From ae3ebfbcca4578bd5f4a0cd7ab24ccfb9477b230 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 28 Jun 2024 14:31:57 +0200 Subject: [PATCH 26/35] fix: Align `SystemEpochInfoEvent` to Move --- crates/iota-types/src/event.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/iota-types/src/event.rs b/crates/iota-types/src/event.rs index 58ad0f82c45..ca2dc777cb8 100755 --- a/crates/iota-types/src/event.rs +++ b/crates/iota-types/src/event.rs @@ -169,11 +169,9 @@ pub struct SystemEpochInfoEvent { pub protocol_version: u64, pub reference_gas_price: u64, pub total_stake: u64, - pub storage_fund_reinvestment: u64, pub storage_charge: u64, pub storage_rebate: u64, pub storage_fund_balance: u64, - pub stake_subsidy_amount: u64, pub total_gas_fees: u64, pub total_stake_rewards_distributed: u64, pub leftover_storage_fund_inflow: u64, From 2b7204c188128dd28e195a99530ed4a8a967526c Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 28 Jun 2024 14:36:58 +0200 Subject: [PATCH 27/35] feat: Add todo for potentially emitting supply change --- .../iota-framework/docs/iota-system/iota_system_state_inner.md | 1 + .../packages/iota-system/sources/iota_system_state_inner.move | 1 + 2 files changed, 2 insertions(+) diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 837ef76bc0c..2d581c5f222 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -2134,6 +2134,7 @@ gas coins. non_refundable_storage_fee_amount, ); + // TODO: Consider emitting the minted or burned tokens from the IOTA supply here for informational purposes. event::emit( SystemEpochInfoEvent { epoch: self.epoch, diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index e6a241207fa..b74f82bf90b 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -895,6 +895,7 @@ module iota_system::iota_system_state_inner { non_refundable_storage_fee_amount, ); + // TODO: Consider emitting the minted or burned tokens from the IOTA supply here for informational purposes. event::emit( SystemEpochInfoEvent { epoch: self.epoch, From e8756824448d280bba568cfea0d1832b73e9a7d3 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Fri, 28 Jun 2024 16:10:46 +0200 Subject: [PATCH 28/35] fix: Rename stake subsidy allocation to funds to burn --- crates/iota-config/src/genesis.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/iota-config/src/genesis.rs b/crates/iota-config/src/genesis.rs index 709fa4c8d48..581ea1f81be 100644 --- a/crates/iota-config/src/genesis.rs +++ b/crates/iota-config/src/genesis.rs @@ -575,21 +575,19 @@ impl TokenDistributionSchedule { allocations.iter().map(|a| a.amount_nanos).sum::(), "Token Distribution Schedule must add up to the total IOTA supply of {TOTAL_SUPPLY_NANOS} nanos", ); - let stake_subsidy_fund_allocation = allocations.pop().unwrap(); + let funds_to_burn_allocation = allocations.pop().unwrap(); assert_eq!( IotaAddress::default(), - stake_subsidy_fund_allocation.recipient_address, + funds_to_burn_allocation.recipient_address, "Final allocation must be for stake subsidy fund", ); assert!( - stake_subsidy_fund_allocation - .staked_with_validator - .is_none(), + funds_to_burn_allocation.staked_with_validator.is_none(), "Can't stake the stake subsidy fund", ); let schedule = Self { - funds_to_burn: stake_subsidy_fund_allocation.amount_nanos, + funds_to_burn: funds_to_burn_allocation.amount_nanos, allocations, }; From a9f78349e804d59531bcc0a27ebad7460d0c04eb Mon Sep 17 00:00:00 2001 From: Dkwcs Date: Sat, 29 Jun 2024 16:50:46 +0300 Subject: [PATCH 29/35] feat(iota-framework): non_refundable_storage_fee and leftover_staking_rewards removing, 100% refund --- .../docs/iota-system/iota_system.md | 4 +- .../iota-system/iota_system_state_inner.md | 49 +-------- .../docs/iota-system/storage_fund.md | 12 +-- .../docs/iota-system/validator_set.md | 102 +++--------------- .../iota-system/sources/iota_system.move | 4 - .../sources/iota_system_state_inner.move | 37 +------ .../iota-system/sources/storage_fund.move | 10 +- .../iota-system/sources/validator_set.move | 82 ++------------ .../tests/governance_test_utils.move | 8 +- .../tests/validator_set_tests.move | 6 -- crates/iota-genesis-builder/src/lib.rs | 4 +- 11 files changed, 44 insertions(+), 274 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system.md b/crates/iota-framework/docs/iota-system/iota_system.md index dbf99998636..3df8bccda4b 100644 --- a/crates/iota-framework/docs/iota-system/iota_system.md +++ b/crates/iota-framework/docs/iota-system/iota_system.md @@ -1359,7 +1359,7 @@ gas coins. 4. Update all validators. -
fun advance_epoch(validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, non_refundable_storage_fee: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
fun advance_epoch(validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, wrapper: &mut iota_system::IotaSystemState, new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -1376,7 +1376,6 @@ gas coins. new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, - non_refundable_storage_fee: u64, reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, @@ -1391,7 +1390,6 @@ gas coins. storage_reward, computation_reward, storage_rebate, - non_refundable_storage_fee, reward_slashing_rate, epoch_start_timestamp_ms, ctx, diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 2d581c5f222..588fa52c4e8 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -561,18 +561,6 @@ the epoch advancement transaction.
-
-
-total_stake_rewards_distributed: u64 -
-
- -
-
-leftover_storage_fund_inflow: u64 -
-
-
@@ -2033,7 +2021,7 @@ gas coins. 4. Update all validators. -
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
+
public(friend) fun advance_epoch(self: &mut iota_system_state_inner::IotaSystemStateInnerV2, new_epoch: u64, next_protocol_version: u64, validator_target_reward: u64, storage_reward: balance::Balance<iota::IOTA>, computation_reward: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -2050,7 +2038,6 @@ gas coins. mut storage_reward: Balance<IOTA>, mut computation_reward: Balance<IOTA>, mut storage_rebate_amount: u64, - mut non_refundable_storage_fee_amount: u64, reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, @@ -2068,13 +2055,8 @@ gas coins. computation_reward.join(safe_mode_computation_rewards); storage_rebate_amount = storage_rebate_amount + self.safe_mode_storage_rebates; self.safe_mode_storage_rebates = 0; - non_refundable_storage_fee_amount = non_refundable_storage_fee_amount + self.safe_mode_non_refundable_storage_fee; self.safe_mode_non_refundable_storage_fee = 0; - let total_validators_stake = self.validators.total_stake(); - let storage_fund_balance = self.storage_fund.total_balance(); - let total_stake = storage_fund_balance + total_validators_stake; - let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); @@ -2084,22 +2066,12 @@ gas coins. &mut self.iota_treasury_cap, ); - let total_stake_u128 = total_stake as u128; - let computation_charge_u128 = computation_charge as u128; - - let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128; - let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64); - self.epoch = self.epoch + 1; // Sanity check to make sure we are advancing to the right epoch. assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch); - let computation_reward_amount_before_distribution = computation_reward.value(); - let storage_fund_reward_amount_before_distribution = storage_fund_reward.value(); - self.validators.advance_epoch( &mut computation_reward, - &mut storage_fund_reward, &mut self.validator_report_records, reward_slashing_rate, self.parameters.validator_low_stake_threshold, @@ -2108,30 +2080,19 @@ gas coins. ctx, ); + self.iota_treasury_cap.supply_mut().decrease_supply(computation_reward); let new_total_stake = self.validators.total_stake(); - let computation_reward_amount_after_distribution = computation_reward.value(); - let storage_fund_reward_amount_after_distribution = storage_fund_reward.value(); - //TODO: remove - storage_fund_reward.destroy_zero(); - let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution; - let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution; + self.protocol_version = next_protocol_version; // Derive the reference gas price for the new epoch self.reference_gas_price = self.validators.derive_reference_gas_price(); - // Because of precision issues with integer divisions, we expect that there will be some - // remaining balance in `computation_reward`. - // All of these go to the storage fund. - let leftover_staking_rewards = computation_reward; - let leftover_storage_fund_inflow = leftover_staking_rewards.value(); let refunded_storage_rebate = self.storage_fund.advance_epoch( storage_reward, - leftover_staking_rewards, storage_rebate_amount, - non_refundable_storage_fee_amount, ); // TODO: Consider emitting the minted or burned tokens from the IOTA supply here for informational purposes. @@ -2145,9 +2106,7 @@ gas coins. storage_rebate: storage_rebate_amount, storage_fund_balance: self.storage_fund.total_balance(), total_gas_fees: computation_charge, - total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed, - leftover_storage_fund_inflow, - } + } ); self.safe_mode = false; // Double check that the gas from safe mode has been processed. diff --git a/crates/iota-framework/docs/iota-system/storage_fund.md b/crates/iota-framework/docs/iota-system/storage_fund.md index ba3be277350..c23ed52d59a 100644 --- a/crates/iota-framework/docs/iota-system/storage_fund.md +++ b/crates/iota-framework/docs/iota-system/storage_fund.md @@ -94,7 +94,7 @@ Called by iota_system Called by iota_system at epoch change times to process the inflows and outflows of storage fund. -
public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<iota::IOTA>, leftover_staking_rewards: balance::Balance<iota::IOTA>, storage_rebate_amount: u64, non_refundable_storage_fee_amount: u64): balance::Balance<iota::IOTA>
+
public(friend) fun advance_epoch(self: &mut storage_fund::StorageFund, storage_charges: balance::Balance<iota::IOTA>, storage_rebate_amount: u64): balance::Balance<iota::IOTA>
 
@@ -106,22 +106,13 @@ Called by iota_system
public(package) fun advance_epoch(
     self: &mut StorageFund,
     storage_charges: Balance<IOTA>,
-    leftover_staking_rewards: Balance<IOTA>,
     storage_rebate_amount: u64,
-    non_refundable_storage_fee_amount: u64,
 ) : Balance<IOTA> {
-    // Add any leftover staking rewards to the non-refundable balance.
-    self.non_refundable_balance.join(leftover_staking_rewards);
-
     // The storage charges for the epoch come from the storage rebate of the new objects created
     // and the new storage rebates of the objects modified during the epoch so we put the charges
     // into `total_object_storage_rebates`.
     self.total_object_storage_rebates.join(storage_charges);
 
-    // Split out the non-refundable portion of the storage rebate and put it into the non-refundable balance.
-    let non_refundable_storage_fee = self.total_object_storage_rebates.split(non_refundable_storage_fee_amount);
-    self.non_refundable_balance.join(non_refundable_storage_fee);
-
     // `storage_rebates` include the already refunded rebates of deleted objects and old rebates of modified objects and
     // should be taken out of the `total_object_storage_rebates`.
     let storage_rebate = self.total_object_storage_rebates.split(storage_rebate_amount);
@@ -176,6 +167,7 @@ Called by iota_system
 
 
 
public fun total_balance(self: &StorageFund): u64 {
+    //TODO: fix
     self.total_object_storage_rebates.value() + self.non_refundable_balance.value()
 }
 
diff --git a/crates/iota-framework/docs/iota-system/validator_set.md b/crates/iota-framework/docs/iota-system/validator_set.md index 404f07dd667..92564d1fb03 100644 --- a/crates/iota-framework/docs/iota-system/validator_set.md +++ b/crates/iota-framework/docs/iota-system/validator_set.md @@ -232,12 +232,6 @@ each validator, emitted during epoch advancement.
-
-
-storage_fund_staking_reward: u64 -
-
-
pool_token_exchange_rate: staking_pool::PoolTokenExchangeRate @@ -320,12 +314,6 @@ V2 of ValidatorEpochInfoEvent containing more information about the validator.
-
-
-storage_fund_staking_reward: u64 -
-
-
pool_token_exchange_rate: staking_pool::PoolTokenExchangeRate @@ -994,7 +982,7 @@ It does the following things: 5. At the end, we calculate the total stake for the new epoch. -
public(friend) fun advance_epoch(self: &mut validator_set::ValidatorSet, computation_reward: &mut balance::Balance<iota::IOTA>, storage_fund_reward: &mut balance::Balance<iota::IOTA>, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, reward_slashing_rate: u64, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, ctx: &mut tx_context::TxContext)
+
public(friend) fun advance_epoch(self: &mut validator_set::ValidatorSet, computation_reward: &mut balance::Balance<iota::IOTA>, validator_report_records: &mut vec_map::VecMap<address, vec_set::VecSet<address>>, reward_slashing_rate: u64, low_stake_threshold: u64, very_low_stake_threshold: u64, low_stake_grace_period: u64, ctx: &mut tx_context::TxContext)
 
@@ -1006,7 +994,6 @@ It does the following things:
public(package) fun advance_epoch(
     self: &mut ValidatorSet,
     computation_reward: &mut Balance<IOTA>,
-    storage_fund_reward: &mut Balance<IOTA>,
     validator_report_records: &mut VecMap<address, VecSet<address>>,
     reward_slashing_rate: u64,
     low_stake_threshold: u64,
@@ -1018,11 +1005,10 @@ It does the following things:
     let total_voting_power = voting_power::total_voting_power();
 
     // Compute the reward distribution without taking into account the tallying rule slashing.
-    let (unadjusted_staking_reward_amounts, unadjusted_storage_fund_reward_amounts) = compute_unadjusted_reward_distribution(
+    let unadjusted_staking_reward_amounts = compute_unadjusted_reward_distribution(
         &self.active_validators,
         total_voting_power,
         computation_reward.value(),
-        storage_fund_reward.value(),
     );
 
     // Use the tallying rule report records for the epoch to compute validators that will be
@@ -1033,30 +1019,24 @@ It does the following things:
 
     // Compute the reward adjustments of slashed validators, to be taken into
     // account in adjusted reward computation.
-    let (total_staking_reward_adjustment, individual_staking_reward_adjustments,
-         total_storage_fund_reward_adjustment, individual_storage_fund_reward_adjustments
-        ) =
+    let (total_staking_reward_adjustment, individual_staking_reward_adjustments) =
         compute_reward_adjustments(
             get_validator_indices(&self.active_validators, &slashed_validators),
             reward_slashing_rate,
             &unadjusted_staking_reward_amounts,
-            &unadjusted_storage_fund_reward_amounts,
         );
 
     // Compute the adjusted amounts of stake each validator should get given the tallying rule
     // reward adjustments we computed before.
     // `compute_adjusted_reward_distribution` must be called before `distribute_reward` and `adjust_stake_and_gas_price` to
     // make sure we are using the current epoch's stake information to compute reward distribution.
-    let (adjusted_staking_reward_amounts, adjusted_storage_fund_reward_amounts) = compute_adjusted_reward_distribution(
+    let adjusted_staking_reward_amounts = compute_adjusted_reward_distribution(
         &self.active_validators,
         total_voting_power,
         total_slashed_validator_voting_power,
         unadjusted_staking_reward_amounts,
-        unadjusted_storage_fund_reward_amounts,
         total_staking_reward_adjustment,
         individual_staking_reward_adjustments,
-        total_storage_fund_reward_adjustment,
-        individual_storage_fund_reward_adjustments
     );
 
     // Distribute the rewards before adjusting stake so that we immediately start compounding
@@ -1064,9 +1044,7 @@ It does the following things:
     distribute_reward(
         &mut self.active_validators,
         &adjusted_staking_reward_amounts,
-        &adjusted_storage_fund_reward_amounts,
         computation_reward,
-        storage_fund_reward,
         ctx
     );
 
@@ -1075,8 +1053,7 @@ It does the following things:
     process_pending_stakes_and_withdraws(&mut self.active_validators, ctx);
 
     // Emit events after we have processed all the rewards distribution and pending stakes.
-    emit_validator_epoch_events(new_epoch, &self.active_validators, &adjusted_staking_reward_amounts,
-        &adjusted_storage_fund_reward_amounts, validator_report_records, &slashed_validators);
+    emit_validator_epoch_events(new_epoch, &self.active_validators, &adjusted_staking_reward_amounts, validator_report_records, &slashed_validators);
 
     // Note that all their staged next epoch metadata will be effectuated below.
     process_pending_validators(self, new_epoch);
@@ -2437,7 +2414,7 @@ Compute both the individual reward adjustments and total reward adjustment for s
 as well as storage fund rewards.
 
 
-
fun compute_reward_adjustments(slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>, unadjusted_storage_fund_reward_amounts: &vector<u64>): (u64, vec_map::VecMap<u64, u64>, u64, vec_map::VecMap<u64, u64>)
+
fun compute_reward_adjustments(slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>): (u64, vec_map::VecMap<u64, u64>)
 
@@ -2450,17 +2427,12 @@ as well as storage fund rewards. mut slashed_validator_indices: vector<u64>, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector<u64>, - unadjusted_storage_fund_reward_amounts: &vector<u64>, ): ( u64, // sum of staking reward adjustments VecMap<u64, u64>, // mapping of individual validator's staking reward adjustment from index -> amount - u64, // sum of storage fund reward adjustments - VecMap<u64, u64>, // mapping of individual validator's storage fund reward adjustment from index -> amount ) { let mut total_staking_reward_adjustment = 0; let mut individual_staking_reward_adjustments = vec_map::empty(); - let mut total_storage_fund_reward_adjustment = 0; - let mut individual_storage_fund_reward_adjustments = vec_map::empty(); while (!slashed_validator_indices.is_empty()) { let validator_index = slashed_validator_indices.pop_back(); @@ -2475,19 +2447,9 @@ as well as storage fund rewards. individual_staking_reward_adjustments.insert(validator_index, staking_reward_adjustment_u128 as u64); total_staking_reward_adjustment = total_staking_reward_adjustment + (staking_reward_adjustment_u128 as u64); - // Do the same thing for storage fund rewards. - let unadjusted_storage_fund_reward = unadjusted_storage_fund_reward_amounts[validator_index]; - let storage_fund_reward_adjustment_u128 = - unadjusted_storage_fund_reward as u128 * (reward_slashing_rate as u128) - / BASIS_POINT_DENOMINATOR; - individual_storage_fund_reward_adjustments.insert(validator_index, storage_fund_reward_adjustment_u128 as u64); - total_storage_fund_reward_adjustment = total_storage_fund_reward_adjustment + (storage_fund_reward_adjustment_u128 as u64); }; - ( - total_staking_reward_adjustment, individual_staking_reward_adjustments, - total_storage_fund_reward_adjustment, individual_storage_fund_reward_adjustments - ) + (total_staking_reward_adjustment, individual_staking_reward_adjustments,) }
@@ -2548,7 +2510,7 @@ account the tallying rule results. Returns the unadjusted amounts of staking reward and storage fund reward for each validator. -
fun compute_unadjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_staking_reward: u64, total_storage_fund_reward: u64): (vector<u64>, vector<u64>)
+
fun compute_unadjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_staking_reward: u64): vector<u64>
 
@@ -2561,12 +2523,9 @@ Returns the unadjusted amounts of staking reward and storage fund reward for eac validators: &vector<Validator>, total_voting_power: u64, total_staking_reward: u64, - total_storage_fund_reward: u64, -): (vector<u64>, vector<u64>) { +): vector<u64> { let mut staking_reward_amounts = vector[]; - let mut storage_fund_reward_amounts = vector[]; let length = validators.length(); - let storage_fund_reward_per_validator = total_storage_fund_reward / length; let mut i = 0; while (i < length) { let validator = &validators[i]; @@ -2577,10 +2536,9 @@ Returns the unadjusted amounts of staking reward and storage fund reward for eac let reward_amount = voting_power * (total_staking_reward as u128) / (total_voting_power as u128); staking_reward_amounts.push_back(reward_amount as u64); // Storage fund's share of the rewards are equally distributed among validators. - storage_fund_reward_amounts.push_back(storage_fund_reward_per_validator); i = i + 1; }; - (staking_reward_amounts, storage_fund_reward_amounts) + staking_reward_amounts }
@@ -2597,7 +2555,7 @@ Returns the staking rewards each validator gets and the storage fund rewards eac The staking rewards are shared with the stakers while the storage fund ones are not. -
fun compute_adjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector<u64>, unadjusted_storage_fund_reward_amounts: vector<u64>, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: vec_map::VecMap<u64, u64>, total_storage_fund_reward_adjustment: u64, individual_storage_fund_reward_adjustments: vec_map::VecMap<u64, u64>): (vector<u64>, vector<u64>)
+
fun compute_adjusted_reward_distribution(validators: &vector<validator::Validator>, total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector<u64>, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: vec_map::VecMap<u64, u64>): vector<u64>
 
@@ -2611,18 +2569,13 @@ The staking rewards are shared with the stakers while the storage fund ones are total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector<u64>, - unadjusted_storage_fund_reward_amounts: vector<u64>, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: VecMap<u64, u64>, - total_storage_fund_reward_adjustment: u64, - individual_storage_fund_reward_adjustments: VecMap<u64, u64>, -): (vector<u64>, vector<u64>) { +): vector<u64> { let total_unslashed_validator_voting_power = total_voting_power - total_slashed_validator_voting_power; let mut adjusted_staking_reward_amounts = vector[]; - let mut adjusted_storage_fund_reward_amounts = vector[]; let length = validators.length(); - let num_unslashed_validators = length - individual_staking_reward_adjustments.size(); let mut i = 0; while (i < length) { @@ -2648,24 +2601,10 @@ The staking rewards are shared with the stakers while the storage fund ones are }; adjusted_staking_reward_amounts.push_back(adjusted_staking_reward_amount); - // Compute adjusted storage fund reward. - let unadjusted_storage_fund_reward_amount = unadjusted_storage_fund_reward_amounts[i]; - let adjusted_storage_fund_reward_amount = - // If the validator is one of the slashed ones, then subtract the adjustment. - if (individual_storage_fund_reward_adjustments.contains(&i)) { - let adjustment = individual_storage_fund_reward_adjustments[&i]; - unadjusted_storage_fund_reward_amount - adjustment - } else { - // Otherwise the slashed rewards should be equally distributed among the unslashed validators. - let adjustment = total_storage_fund_reward_adjustment / num_unslashed_validators; - unadjusted_storage_fund_reward_amount + adjustment - }; - adjusted_storage_fund_reward_amounts.push_back(adjusted_storage_fund_reward_amount); - i = i + 1; }; - (adjusted_staking_reward_amounts, adjusted_storage_fund_reward_amounts) + adjusted_staking_reward_amounts }
@@ -2679,7 +2618,7 @@ The staking rewards are shared with the stakers while the storage fund ones are -
fun distribute_reward(validators: &mut vector<validator::Validator>, adjusted_staking_reward_amounts: &vector<u64>, adjusted_storage_fund_reward_amounts: &vector<u64>, staking_rewards: &mut balance::Balance<iota::IOTA>, storage_fund_reward: &mut balance::Balance<iota::IOTA>, ctx: &mut tx_context::TxContext)
+
fun distribute_reward(validators: &mut vector<validator::Validator>, adjusted_staking_reward_amounts: &vector<u64>, staking_rewards: &mut balance::Balance<iota::IOTA>, ctx: &mut tx_context::TxContext)
 
@@ -2691,9 +2630,7 @@ The staking rewards are shared with the stakers while the storage fund ones are
fun distribute_reward(
     validators: &mut vector<Validator>,
     adjusted_staking_reward_amounts: &vector<u64>,
-    adjusted_storage_fund_reward_amounts: &vector<u64>,
     staking_rewards: &mut Balance<IOTA>,
-    storage_fund_reward: &mut Balance<IOTA>,
     ctx: &mut TxContext
 ) {
     let length = validators.length();
@@ -2708,12 +2645,7 @@ The staking rewards are shared with the stakers while the storage fund ones are
         let validator_commission_amount = (staking_reward_amount as u128) * (validator.commission_rate() as u128) / BASIS_POINT_DENOMINATOR;
 
         // The validator reward = storage_fund_reward + commission.
-        let mut validator_reward = staker_reward.split(validator_commission_amount as u64);
-
-        // Add storage fund rewards to the validator's reward.
-        validator_reward.join(
-	    	storage_fund_reward.split(adjusted_storage_fund_reward_amounts[i])
-	    );
+        let validator_reward = staker_reward.split(validator_commission_amount as u64);
 
         // Add rewards to the validator. Don't try and distribute rewards though if the payout is zero.
         if (validator_reward.value() > 0) {
@@ -2743,7 +2675,7 @@ Emit events containing information of each validator for the epoch,
 including stakes, rewards, performance, etc.
 
 
-
fun emit_validator_epoch_events(new_epoch: u64, vs: &vector<validator::Validator>, pool_staking_reward_amounts: &vector<u64>, storage_fund_staking_reward_amounts: &vector<u64>, report_records: &vec_map::VecMap<address, vec_set::VecSet<address>>, slashed_validators: &vector<address>)
+
fun emit_validator_epoch_events(new_epoch: u64, vs: &vector<validator::Validator>, pool_staking_reward_amounts: &vector<u64>, report_records: &vec_map::VecMap<address, vec_set::VecSet<address>>, slashed_validators: &vector<address>)
 
@@ -2756,7 +2688,6 @@ including stakes, rewards, performance, etc. new_epoch: u64, vs: &vector<Validator>, pool_staking_reward_amounts: &vector<u64>, - storage_fund_staking_reward_amounts: &vector<u64>, report_records: &VecMap<address, VecSet<address>>, slashed_validators: &vector<address>, ) { @@ -2783,7 +2714,6 @@ including stakes, rewards, performance, etc. voting_power: v.voting_power(), commission_rate: v.commission_rate(), pool_staking_reward: pool_staking_reward_amounts[i], - storage_fund_staking_reward: storage_fund_staking_reward_amounts[i], pool_token_exchange_rate: v.pool_token_exchange_rate_at_epoch(new_epoch), tallying_rule_reporters, tallying_rule_global_score, diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system.move b/crates/iota-framework/packages/iota-system/sources/iota_system.move index c6159e73d70..e88ae0cbc78 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move @@ -542,7 +542,6 @@ module iota_system::iota_system { new_epoch: u64, next_protocol_version: u64, storage_rebate: u64, - non_refundable_storage_fee: u64, reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, @@ -557,7 +556,6 @@ module iota_system::iota_system { storage_reward, computation_reward, storage_rebate, - non_refundable_storage_fee, reward_slashing_rate, epoch_start_timestamp_ms, ctx, @@ -746,7 +744,6 @@ module iota_system::iota_system { storage_charge: u64, computation_charge: u64, storage_rebate: u64, - non_refundable_storage_fee: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut TxContext, @@ -761,7 +758,6 @@ module iota_system::iota_system { new_epoch, next_protocol_version, storage_rebate, - non_refundable_storage_fee, reward_slashing_rate, epoch_start_timestamp_ms, ctx, diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index b74f82bf90b..ee99a8a7783 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -200,8 +200,6 @@ module iota_system::iota_system_state_inner { storage_rebate: u64, storage_fund_balance: u64, total_gas_fees: u64, - total_stake_rewards_distributed: u64, - leftover_storage_fund_inflow: u64, } // Errors @@ -811,7 +809,6 @@ module iota_system::iota_system_state_inner { mut storage_reward: Balance, mut computation_reward: Balance, mut storage_rebate_amount: u64, - mut non_refundable_storage_fee_amount: u64, reward_slashing_rate: u64, // how much rewards are slashed to punish a validator, in bps. epoch_start_timestamp_ms: u64, // Timestamp of the epoch start ctx: &mut TxContext, @@ -829,13 +826,8 @@ module iota_system::iota_system_state_inner { computation_reward.join(safe_mode_computation_rewards); storage_rebate_amount = storage_rebate_amount + self.safe_mode_storage_rebates; self.safe_mode_storage_rebates = 0; - non_refundable_storage_fee_amount = non_refundable_storage_fee_amount + self.safe_mode_non_refundable_storage_fee; self.safe_mode_non_refundable_storage_fee = 0; - let total_validators_stake = self.validators.total_stake(); - let storage_fund_balance = self.storage_fund.total_balance(); - let total_stake = storage_fund_balance + total_validators_stake; - let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); @@ -845,22 +837,12 @@ module iota_system::iota_system_state_inner { &mut self.iota_treasury_cap, ); - let total_stake_u128 = total_stake as u128; - let computation_charge_u128 = computation_charge as u128; - - let storage_fund_reward_amount = storage_fund_balance as u128 * computation_charge_u128 / total_stake_u128; - let mut storage_fund_reward = computation_reward.split(storage_fund_reward_amount as u64); - self.epoch = self.epoch + 1; // Sanity check to make sure we are advancing to the right epoch. assert!(new_epoch == self.epoch, EAdvancedToWrongEpoch); - let computation_reward_amount_before_distribution = computation_reward.value(); - let storage_fund_reward_amount_before_distribution = storage_fund_reward.value(); - self.validators.advance_epoch( &mut computation_reward, - &mut storage_fund_reward, &mut self.validator_report_records, reward_slashing_rate, self.parameters.validator_low_stake_threshold, @@ -869,30 +851,19 @@ module iota_system::iota_system_state_inner { ctx, ); + self.iota_treasury_cap.supply_mut().decrease_supply(computation_reward); let new_total_stake = self.validators.total_stake(); - let computation_reward_amount_after_distribution = computation_reward.value(); - let storage_fund_reward_amount_after_distribution = storage_fund_reward.value(); - //TODO: remove - storage_fund_reward.destroy_zero(); - let computation_reward_distributed = computation_reward_amount_before_distribution - computation_reward_amount_after_distribution; - let storage_fund_reward_distributed = storage_fund_reward_amount_before_distribution - storage_fund_reward_amount_after_distribution; + self.protocol_version = next_protocol_version; // Derive the reference gas price for the new epoch self.reference_gas_price = self.validators.derive_reference_gas_price(); - // Because of precision issues with integer divisions, we expect that there will be some - // remaining balance in `computation_reward`. - // All of these go to the storage fund. - let leftover_staking_rewards = computation_reward; - let leftover_storage_fund_inflow = leftover_staking_rewards.value(); let refunded_storage_rebate = self.storage_fund.advance_epoch( storage_reward, - leftover_staking_rewards, storage_rebate_amount, - non_refundable_storage_fee_amount, ); // TODO: Consider emitting the minted or burned tokens from the IOTA supply here for informational purposes. @@ -906,9 +877,7 @@ module iota_system::iota_system_state_inner { storage_rebate: storage_rebate_amount, storage_fund_balance: self.storage_fund.total_balance(), total_gas_fees: computation_charge, - total_stake_rewards_distributed: computation_reward_distributed + storage_fund_reward_distributed, - leftover_storage_fund_inflow, - } + } ); self.safe_mode = false; // Double check that the gas from safe mode has been processed. diff --git a/crates/iota-framework/packages/iota-system/sources/storage_fund.move b/crates/iota-framework/packages/iota-system/sources/storage_fund.move index 92767cc1a73..d66053dc962 100644 --- a/crates/iota-framework/packages/iota-system/sources/storage_fund.move +++ b/crates/iota-framework/packages/iota-system/sources/storage_fund.move @@ -32,22 +32,13 @@ module iota_system::storage_fund { public(package) fun advance_epoch( self: &mut StorageFund, storage_charges: Balance, - leftover_staking_rewards: Balance, storage_rebate_amount: u64, - non_refundable_storage_fee_amount: u64, ) : Balance { - // Add any leftover staking rewards to the non-refundable balance. - self.non_refundable_balance.join(leftover_staking_rewards); - // The storage charges for the epoch come from the storage rebate of the new objects created // and the new storage rebates of the objects modified during the epoch so we put the charges // into `total_object_storage_rebates`. self.total_object_storage_rebates.join(storage_charges); - // Split out the non-refundable portion of the storage rebate and put it into the non-refundable balance. - let non_refundable_storage_fee = self.total_object_storage_rebates.split(non_refundable_storage_fee_amount); - self.non_refundable_balance.join(non_refundable_storage_fee); - // `storage_rebates` include the already refunded rebates of deleted objects and old rebates of modified objects and // should be taken out of the `total_object_storage_rebates`. let storage_rebate = self.total_object_storage_rebates.split(storage_rebate_amount); @@ -62,6 +53,7 @@ module iota_system::storage_fund { } public fun total_balance(self: &StorageFund): u64 { + //TODO: fix self.total_object_storage_rebates.value() + self.non_refundable_balance.value() } } \ No newline at end of file diff --git a/crates/iota-framework/packages/iota-system/sources/validator_set.move b/crates/iota-framework/packages/iota-system/sources/validator_set.move index dbf6ac21120..19b21ec81b2 100644 --- a/crates/iota-framework/packages/iota-system/sources/validator_set.move +++ b/crates/iota-framework/packages/iota-system/sources/validator_set.move @@ -77,7 +77,6 @@ module iota_system::validator_set { stake: u64, commission_rate: u64, pool_staking_reward: u64, - storage_fund_staking_reward: u64, pool_token_exchange_rate: PoolTokenExchangeRate, tallying_rule_reporters: vector
, tallying_rule_global_score: u64, @@ -92,7 +91,6 @@ module iota_system::validator_set { voting_power: u64, commission_rate: u64, pool_staking_reward: u64, - storage_fund_staking_reward: u64, pool_token_exchange_rate: PoolTokenExchangeRate, tallying_rule_reporters: vector
, tallying_rule_global_score: u64, @@ -344,7 +342,6 @@ module iota_system::validator_set { public(package) fun advance_epoch( self: &mut ValidatorSet, computation_reward: &mut Balance, - storage_fund_reward: &mut Balance, validator_report_records: &mut VecMap>, reward_slashing_rate: u64, low_stake_threshold: u64, @@ -356,11 +353,10 @@ module iota_system::validator_set { let total_voting_power = voting_power::total_voting_power(); // Compute the reward distribution without taking into account the tallying rule slashing. - let (unadjusted_staking_reward_amounts, unadjusted_storage_fund_reward_amounts) = compute_unadjusted_reward_distribution( + let unadjusted_staking_reward_amounts = compute_unadjusted_reward_distribution( &self.active_validators, total_voting_power, computation_reward.value(), - storage_fund_reward.value(), ); // Use the tallying rule report records for the epoch to compute validators that will be @@ -371,30 +367,24 @@ module iota_system::validator_set { // Compute the reward adjustments of slashed validators, to be taken into // account in adjusted reward computation. - let (total_staking_reward_adjustment, individual_staking_reward_adjustments, - total_storage_fund_reward_adjustment, individual_storage_fund_reward_adjustments - ) = + let (total_staking_reward_adjustment, individual_staking_reward_adjustments) = compute_reward_adjustments( get_validator_indices(&self.active_validators, &slashed_validators), reward_slashing_rate, &unadjusted_staking_reward_amounts, - &unadjusted_storage_fund_reward_amounts, ); // Compute the adjusted amounts of stake each validator should get given the tallying rule // reward adjustments we computed before. // `compute_adjusted_reward_distribution` must be called before `distribute_reward` and `adjust_stake_and_gas_price` to // make sure we are using the current epoch's stake information to compute reward distribution. - let (adjusted_staking_reward_amounts, adjusted_storage_fund_reward_amounts) = compute_adjusted_reward_distribution( + let adjusted_staking_reward_amounts = compute_adjusted_reward_distribution( &self.active_validators, total_voting_power, total_slashed_validator_voting_power, unadjusted_staking_reward_amounts, - unadjusted_storage_fund_reward_amounts, total_staking_reward_adjustment, individual_staking_reward_adjustments, - total_storage_fund_reward_adjustment, - individual_storage_fund_reward_adjustments ); // Distribute the rewards before adjusting stake so that we immediately start compounding @@ -402,9 +392,7 @@ module iota_system::validator_set { distribute_reward( &mut self.active_validators, &adjusted_staking_reward_amounts, - &adjusted_storage_fund_reward_amounts, computation_reward, - storage_fund_reward, ctx ); @@ -413,8 +401,7 @@ module iota_system::validator_set { process_pending_stakes_and_withdraws(&mut self.active_validators, ctx); // Emit events after we have processed all the rewards distribution and pending stakes. - emit_validator_epoch_events(new_epoch, &self.active_validators, &adjusted_staking_reward_amounts, - &adjusted_storage_fund_reward_amounts, validator_report_records, &slashed_validators); + emit_validator_epoch_events(new_epoch, &self.active_validators, &adjusted_staking_reward_amounts, validator_report_records, &slashed_validators); // Note that all their staged next epoch metadata will be effectuated below. process_pending_validators(self, new_epoch); @@ -1001,17 +988,12 @@ module iota_system::validator_set { mut slashed_validator_indices: vector, reward_slashing_rate: u64, unadjusted_staking_reward_amounts: &vector, - unadjusted_storage_fund_reward_amounts: &vector, ): ( u64, // sum of staking reward adjustments VecMap, // mapping of individual validator's staking reward adjustment from index -> amount - u64, // sum of storage fund reward adjustments - VecMap, // mapping of individual validator's storage fund reward adjustment from index -> amount ) { let mut total_staking_reward_adjustment = 0; let mut individual_staking_reward_adjustments = vec_map::empty(); - let mut total_storage_fund_reward_adjustment = 0; - let mut individual_storage_fund_reward_adjustments = vec_map::empty(); while (!slashed_validator_indices.is_empty()) { let validator_index = slashed_validator_indices.pop_back(); @@ -1025,20 +1007,10 @@ module iota_system::validator_set { // Insert into individual mapping and record into the total adjustment sum. individual_staking_reward_adjustments.insert(validator_index, staking_reward_adjustment_u128 as u64); total_staking_reward_adjustment = total_staking_reward_adjustment + (staking_reward_adjustment_u128 as u64); - - // Do the same thing for storage fund rewards. - let unadjusted_storage_fund_reward = unadjusted_storage_fund_reward_amounts[validator_index]; - let storage_fund_reward_adjustment_u128 = - unadjusted_storage_fund_reward as u128 * (reward_slashing_rate as u128) - / BASIS_POINT_DENOMINATOR; - individual_storage_fund_reward_adjustments.insert(validator_index, storage_fund_reward_adjustment_u128 as u64); - total_storage_fund_reward_adjustment = total_storage_fund_reward_adjustment + (storage_fund_reward_adjustment_u128 as u64); + }; - ( - total_staking_reward_adjustment, individual_staking_reward_adjustments, - total_storage_fund_reward_adjustment, individual_storage_fund_reward_adjustments - ) + (total_staking_reward_adjustment, individual_staking_reward_adjustments,) } /// Process the validator report records of the epoch and return the addresses of the @@ -1072,12 +1044,9 @@ module iota_system::validator_set { validators: &vector, total_voting_power: u64, total_staking_reward: u64, - total_storage_fund_reward: u64, - ): (vector, vector) { + ): vector { let mut staking_reward_amounts = vector[]; - let mut storage_fund_reward_amounts = vector[]; let length = validators.length(); - let storage_fund_reward_per_validator = total_storage_fund_reward / length; let mut i = 0; while (i < length) { let validator = &validators[i]; @@ -1088,10 +1057,9 @@ module iota_system::validator_set { let reward_amount = voting_power * (total_staking_reward as u128) / (total_voting_power as u128); staking_reward_amounts.push_back(reward_amount as u64); // Storage fund's share of the rewards are equally distributed among validators. - storage_fund_reward_amounts.push_back(storage_fund_reward_per_validator); i = i + 1; }; - (staking_reward_amounts, storage_fund_reward_amounts) + staking_reward_amounts } /// Use the reward adjustment info to compute the adjusted rewards each validator should get. @@ -1102,18 +1070,13 @@ module iota_system::validator_set { total_voting_power: u64, total_slashed_validator_voting_power: u64, unadjusted_staking_reward_amounts: vector, - unadjusted_storage_fund_reward_amounts: vector, total_staking_reward_adjustment: u64, individual_staking_reward_adjustments: VecMap, - total_storage_fund_reward_adjustment: u64, - individual_storage_fund_reward_adjustments: VecMap, - ): (vector, vector) { + ): vector { let total_unslashed_validator_voting_power = total_voting_power - total_slashed_validator_voting_power; let mut adjusted_staking_reward_amounts = vector[]; - let mut adjusted_storage_fund_reward_amounts = vector[]; let length = validators.length(); - let num_unslashed_validators = length - individual_staking_reward_adjustments.size(); let mut i = 0; while (i < length) { @@ -1139,32 +1102,16 @@ module iota_system::validator_set { }; adjusted_staking_reward_amounts.push_back(adjusted_staking_reward_amount); - // Compute adjusted storage fund reward. - let unadjusted_storage_fund_reward_amount = unadjusted_storage_fund_reward_amounts[i]; - let adjusted_storage_fund_reward_amount = - // If the validator is one of the slashed ones, then subtract the adjustment. - if (individual_storage_fund_reward_adjustments.contains(&i)) { - let adjustment = individual_storage_fund_reward_adjustments[&i]; - unadjusted_storage_fund_reward_amount - adjustment - } else { - // Otherwise the slashed rewards should be equally distributed among the unslashed validators. - let adjustment = total_storage_fund_reward_adjustment / num_unslashed_validators; - unadjusted_storage_fund_reward_amount + adjustment - }; - adjusted_storage_fund_reward_amounts.push_back(adjusted_storage_fund_reward_amount); - i = i + 1; }; - (adjusted_staking_reward_amounts, adjusted_storage_fund_reward_amounts) + adjusted_staking_reward_amounts } fun distribute_reward( validators: &mut vector, adjusted_staking_reward_amounts: &vector, - adjusted_storage_fund_reward_amounts: &vector, staking_rewards: &mut Balance, - storage_fund_reward: &mut Balance, ctx: &mut TxContext ) { let length = validators.length(); @@ -1179,12 +1126,7 @@ module iota_system::validator_set { let validator_commission_amount = (staking_reward_amount as u128) * (validator.commission_rate() as u128) / BASIS_POINT_DENOMINATOR; // The validator reward = storage_fund_reward + commission. - let mut validator_reward = staker_reward.split(validator_commission_amount as u64); - - // Add storage fund rewards to the validator's reward. - validator_reward.join( - storage_fund_reward.split(adjusted_storage_fund_reward_amounts[i]) - ); + let validator_reward = staker_reward.split(validator_commission_amount as u64); // Add rewards to the validator. Don't try and distribute rewards though if the payout is zero. if (validator_reward.value() > 0) { @@ -1207,7 +1149,6 @@ module iota_system::validator_set { new_epoch: u64, vs: &vector, pool_staking_reward_amounts: &vector, - storage_fund_staking_reward_amounts: &vector, report_records: &VecMap>, slashed_validators: &vector
, ) { @@ -1234,7 +1175,6 @@ module iota_system::validator_set { voting_power: v.voting_power(), commission_rate: v.commission_rate(), pool_staking_reward: pool_staking_reward_amounts[i], - storage_fund_staking_reward: storage_fund_staking_reward_amounts[i], pool_token_exchange_rate: v.pool_token_exchange_rate_at_epoch(new_epoch), tallying_rule_reporters, tallying_rule_global_score, diff --git a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move index 40f2d5438f1..408edb66254 100644 --- a/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move +++ b/crates/iota-framework/packages/iota-system/tests/governance_test_utils.move @@ -109,7 +109,7 @@ module iota_system::governance_test_utils { } public fun advance_epoch_with_reward_amounts_return_rebate( - validator_target_reward: u64, storage_charge: u64, computation_charge: u64, stoarge_rebate: u64, non_refundable_storage_rebate: u64, scenario: &mut Scenario, + validator_target_reward: u64, storage_charge: u64, computation_charge: u64, stoarge_rebate: u64, scenario: &mut Scenario, ): Balance { scenario.next_tx(@0x0); let new_epoch = scenario.ctx().epoch() + 1; @@ -118,7 +118,7 @@ module iota_system::governance_test_utils { let ctx = scenario.ctx(); let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, validator_target_reward, storage_charge, computation_charge, stoarge_rebate, non_refundable_storage_rebate, 0, 0, ctx, + new_epoch, 1, validator_target_reward, storage_charge, computation_charge, stoarge_rebate, 0, 0, ctx, ); test_scenario::return_shared(system_state); scenario.next_epoch(@0x0); @@ -128,7 +128,7 @@ module iota_system::governance_test_utils { public fun advance_epoch_with_reward_amounts( validator_target_reward: u64, storage_charge: u64, computation_charge: u64, scenario: &mut Scenario ) { - let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(validator_target_reward * MICROS_PER_IOTA, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, scenario); + let storage_rebate = advance_epoch_with_reward_amounts_return_rebate(validator_target_reward * MICROS_PER_IOTA, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, scenario); test_utils::destroy(storage_rebate) } @@ -146,7 +146,7 @@ module iota_system::governance_test_utils { let validator_target_reward = computation_charge * MICROS_PER_IOTA; let storage_rebate = system_state.advance_epoch_for_testing( - new_epoch, 1, validator_target_reward, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, 0, reward_slashing_rate, 0, ctx + new_epoch, 1, validator_target_reward, storage_charge * MICROS_PER_IOTA, computation_charge * MICROS_PER_IOTA, 0, reward_slashing_rate, 0, ctx ); test_utils::destroy(storage_rebate); test_scenario::return_shared(system_state); diff --git a/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move b/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move index 87461e3a91f..978a895afcd 100644 --- a/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/validator_set_tests.move @@ -433,11 +433,9 @@ module iota_system::validator_set_tests { fun advance_epoch_with_dummy_rewards(validator_set: &mut ValidatorSet, scenario: &mut Scenario) { scenario.next_epoch(@0x0); let mut dummy_computation_reward = balance::zero(); - let mut dummy_storage_fund_reward = balance::zero(); validator_set.advance_epoch( &mut dummy_computation_reward, - &mut dummy_storage_fund_reward, &mut vec_map::empty(), 0, // reward_slashing_rate 0, // low_stake_threshold @@ -447,7 +445,6 @@ module iota_system::validator_set_tests { ); dummy_computation_reward.destroy_zero(); - dummy_storage_fund_reward.destroy_zero(); } fun advance_epoch_with_low_stake_params( @@ -459,10 +456,8 @@ module iota_system::validator_set_tests { ) { scenario.next_epoch(@0x0); let mut dummy_computation_reward = balance::zero(); - let mut dummy_storage_fund_reward = balance::zero(); validator_set.advance_epoch( &mut dummy_computation_reward, - &mut dummy_storage_fund_reward, &mut vec_map::empty(), 0, // reward_slashing_rate low_stake_threshold * MICROS_PER_IOTA, @@ -472,7 +467,6 @@ module iota_system::validator_set_tests { ); dummy_computation_reward.destroy_zero(); - dummy_storage_fund_reward.destroy_zero(); } fun add_and_activate_validator(validator_set: &mut ValidatorSet, validator: Validator, scenario: &mut Scenario) { diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs index cc5b39c87b3..016f21fd905 100644 --- a/crates/iota-genesis-builder/src/lib.rs +++ b/crates/iota-genesis-builder/src/lib.rs @@ -33,7 +33,7 @@ use iota_types::{ effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, epoch_data::EpochData, gas::IotaGasStatus, - gas_coin::{GasCoin, GAS, TOTAL_SUPPLY_MICROS}, + gas_coin::{GasCoin, GAS, NANOS_PER_IOTA}, governance::StakedIota, in_memory_storage::InMemoryStorage, inner_temporary_store::InnerTemporaryStore, @@ -1101,7 +1101,7 @@ pub fn generate_genesis_system_object( let total_iota_supply = builder .input(CallArg::Pure( - bcs::to_bytes(&TOTAL_SUPPLY_MICROS).expect("serialization of u64 should succeed"), + bcs::to_bytes(&NANOS_PER_IOTA).expect("serialization of u64 should succeed"), )) .expect("adding the total IOTA supply argument should succeed"); let total_iota = builder.programmable_move_call( From b636d98304e8758d399ea4692c8d38d5558dfc34 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Mon, 1 Jul 2024 09:25:38 +0200 Subject: [PATCH 30/35] fix: Revert to validator target reward being total --- .../sources/iota_system_state_inner.move | 27 ++++++++-- .../iota-system/sources/validator_set.move | 25 ---------- .../iota-system/tests/delegation_tests.move | 21 ++++---- .../tests/rewards_distribution_tests.move | 50 +++++++++---------- 4 files changed, 58 insertions(+), 65 deletions(-) diff --git a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move index ee99a8a7783..6a6bc7ee0c2 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system_state_inner.move @@ -830,8 +830,7 @@ module iota_system::iota_system_state_inner { let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); - - let mut computation_reward = self.validators.match_iota_supply_to_target_reward( + let mut computation_reward = match_iota_supply_to_target_reward( validator_target_reward, computation_reward, &mut self.iota_treasury_cap, @@ -851,10 +850,10 @@ module iota_system::iota_system_state_inner { ctx, ); + // Burn any leftover rewards that were not distributed (e.g. due to slashing). self.iota_treasury_cap.supply_mut().decrease_supply(computation_reward); let new_total_stake = self.validators.total_stake(); - self.protocol_version = next_protocol_version; // Derive the reference gas price for the new epoch @@ -890,6 +889,28 @@ module iota_system::iota_system_state_inner { refunded_storage_rebate } + /// Inflate or deflate the IOTA supply depending on the given target reward per validator + /// and the amount of computation fees burned in this epoch. + public(package) fun match_iota_supply_to_target_reward( + validator_target_reward: u64, + mut computation_reward: Balance, + iota_treasury_cap: &mut iota::coin::TreasuryCap + ): Balance { + if (computation_reward.value() < validator_target_reward) { + let tokens_to_mint = validator_target_reward - computation_reward.value(); + let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint); + computation_reward.join(new_tokens); + computation_reward + } else if (computation_reward.value() > validator_target_reward) { + let tokens_to_burn = computation_reward.value() - validator_target_reward; + let rewards_to_burn = computation_reward.split(tokens_to_burn); + iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn); + computation_reward + } else { + computation_reward + } + } + /// Return the current epoch number. Useful for applications that need a coarse-grained concept of time, /// since epochs are ever-increasing and epoch changes are intended to happen every 24 hours. public(package) fun epoch(self: &IotaSystemStateInnerV2): u64 { diff --git a/crates/iota-framework/packages/iota-system/sources/validator_set.move b/crates/iota-framework/packages/iota-system/sources/validator_set.move index 19b21ec81b2..968647c488b 100644 --- a/crates/iota-framework/packages/iota-system/sources/validator_set.move +++ b/crates/iota-framework/packages/iota-system/sources/validator_set.move @@ -567,31 +567,6 @@ module iota_system::validator_set { find_validator(&self.active_validators, validator_address).is_some() } - /// Inflate or deflate the IOTA supply depending on the given target reward per validator - /// and the amount of computation fees burned in this epoch. - public(package) fun match_iota_supply_to_target_reward( - self: &ValidatorSet, - validator_target_reward: u64, - mut computation_reward: Balance, - iota_treasury_cap: &mut iota::coin::TreasuryCap - ): Balance { - let validator_reward_total = validator_target_reward * self.active_validators.length(); - - if (computation_reward.value() < validator_reward_total) { - let tokens_to_mint = validator_reward_total - computation_reward.value(); - let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint); - computation_reward.join(new_tokens); - computation_reward - } else if (computation_reward.value() > validator_reward_total) { - let tokens_to_burn = computation_reward.value() - validator_reward_total; - let rewards_to_burn = computation_reward.split(tokens_to_burn); - iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn); - computation_reward - } else { - computation_reward - } - } - // ==== private helpers ==== /// Checks whether `new_validator` is duplicate with any currently active validators. diff --git a/crates/iota-framework/packages/iota-system/tests/delegation_tests.move b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move index bb3cebe91b0..e98e4bc32eb 100644 --- a/crates/iota-framework/packages/iota-system/tests/delegation_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/delegation_tests.move @@ -28,7 +28,6 @@ module iota_system::stake_tests { unstake, }; - const VALIDATOR_COUNT: u64 = 2; const VALIDATOR_ADDR_1: address = @0x1; const VALIDATOR_ADDR_2: address = @0x2; @@ -234,7 +233,7 @@ module iota_system::stake_tests { if (should_distribute_rewards) { // Each validator pool gets 30 MICROS and each validator gets an additional 10 MICROS. - advance_epoch_with_reward_amounts(80/VALIDATOR_COUNT, 0, 80, scenario); + advance_epoch_with_reward_amounts(80, 0, 80, scenario); } else { advance_epoch(scenario); }; @@ -293,7 +292,7 @@ module iota_system::stake_tests { // Add some rewards after the validator requests to leave. Since the validator is still active // this epoch, they should get the rewards from this epoch. - advance_epoch_with_reward_amounts(80/VALIDATOR_COUNT, 0, 80, scenario); + advance_epoch_with_reward_amounts(80, 0, 80, scenario); // Each validator pool gets 30 MICROS and validators shares the 20 MICROS from the storage fund // so validator gets another 10 MICROS. @@ -375,8 +374,8 @@ module iota_system::stake_tests { stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); // Advance epoch twice with some rewards - advance_epoch_with_reward_amounts(400/VALIDATOR_COUNT, 0, 400, scenario); - advance_epoch_with_reward_amounts(900/VALIDATOR_COUNT, 0, 900, scenario); + advance_epoch_with_reward_amounts(400, 0, 400, scenario); + advance_epoch_with_reward_amounts(900, 0, 900, scenario); // Unstake from the preactive validator. There should be no rewards earned. unstake(STAKER_ADDR_1, 0, scenario); @@ -413,7 +412,7 @@ module iota_system::stake_tests { // Delegate 100 IOTA to the preactive validator stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); - advance_epoch_with_reward_amounts(300/VALIDATOR_COUNT, 0, 300, scenario); + advance_epoch_with_reward_amounts(300, 0, 300, scenario); // At this point we got the following distribution of stake: // V1: 250, V2: 250, storage fund: 100 @@ -427,7 +426,7 @@ module iota_system::stake_tests { // At this point we got the following distribution of stake: // V1: 250, V2: 250, V3: 250, storage fund: 100 - advance_epoch_with_reward_amounts(85/VALIDATOR_COUNT, 0, 85, scenario); + advance_epoch_with_reward_amounts(85, 0, 85, scenario); // staker 1 and 3 unstake from the validator and earns about 2/5 * (85 - 10) * 1/3 = 10 IOTA each. // Although they stake in different epochs, they earn the same rewards as long as they unstake @@ -438,7 +437,7 @@ module iota_system::stake_tests { unstake(STAKER_ADDR_3, 0, scenario); assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 110002000000); - advance_epoch_with_reward_amounts(85/VALIDATOR_COUNT, 0, 85, scenario); + advance_epoch_with_reward_amounts(85, 0, 85, scenario); unstake(STAKER_ADDR_2, 0, scenario); // staker 2 earns about 5 IOTA from the previous epoch and 24-ish from this one // so in total she has about 50 + 5 + 24 = 79 IOTA. @@ -464,7 +463,7 @@ module iota_system::stake_tests { // staker 1 earns a bit greater than 30 IOTA here. A bit greater because the new validator's voting power // is slightly greater than 1/3 of the total voting power. - advance_epoch_with_reward_amounts(90/VALIDATOR_COUNT, 0, 90, scenario); + advance_epoch_with_reward_amounts(90, 0, 90, scenario); // And now the validator leaves the validator set. remove_validator(NEW_VALIDATOR_ADDR, scenario); @@ -489,7 +488,7 @@ module iota_system::stake_tests { stake_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, scenario); // Advance epoch and give out some rewards. The candidate should get nothing, of course. - advance_epoch_with_reward_amounts(800/VALIDATOR_COUNT, 0, 800, scenario); + advance_epoch_with_reward_amounts(800, 0, 800, scenario); // Now the candidate leaves. remove_validator_candidate(NEW_VALIDATOR_ADDR, scenario); @@ -518,7 +517,7 @@ module iota_system::stake_tests { test_scenario::return_to_address(@0x42, staked_iota); advance_epoch(scenario); // advances epoch to effectuate the stake // Each staking pool gets 10 IOTA of rewards. - advance_epoch_with_reward_amounts(20/VALIDATOR_COUNT, 0, 20, scenario); + advance_epoch_with_reward_amounts(20, 0, 20, scenario); let mut system_state = scenario.take_shared(); let rates = system_state.pool_exchange_rates(&pool_id); assert_eq(rates.length(), 3); diff --git a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move index 6197b921c10..13f93a8e04a 100644 --- a/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move +++ b/crates/iota-framework/packages/iota-system/tests/rewards_distribution_tests.move @@ -23,7 +23,6 @@ module iota_system::rewards_distribution_tests { use iota::test_utils::assert_eq; use iota::address; - const VALIDATOR_COUNT: u64 = 4; const VALIDATOR_ADDR_1: address = @0x1; const VALIDATOR_ADDR_2: address = @0x2; const VALIDATOR_ADDR_3: address = @0x3; @@ -45,7 +44,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 100, scenario); + advance_epoch_with_reward_amounts(100, 0, 100, scenario); assert_validator_total_stake_amounts( validator_addrs(), vector[125 * MICROS_PER_IOTA, 225 * MICROS_PER_IOTA, 325 * MICROS_PER_IOTA, 425 * MICROS_PER_IOTA], @@ -55,7 +54,7 @@ module iota_system::rewards_distribution_tests { stake_with(VALIDATOR_ADDR_2, VALIDATOR_ADDR_2, 720, scenario); advance_epoch(scenario); - advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 100, scenario); + advance_epoch_with_reward_amounts(100, 0, 100, scenario); // Even though validator 2 has a lot more stake now, it should not get more rewards because // the voting power is capped at 10%. assert_validator_total_stake_amounts( @@ -75,7 +74,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 100, scenario); + advance_epoch_with_reward_amounts(100, 0, 100, scenario); assert_validator_total_stake_amounts(validator_addrs(), vector[100_000_025 * MICROS_PER_IOTA, 200_000_025 * MICROS_PER_IOTA, 300_000_025 * MICROS_PER_IOTA, 400_000_025 * MICROS_PER_IOTA], scenario); scenario_val.end(); } @@ -89,7 +88,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 100, scenario); + advance_epoch_with_reward_amounts(100, 0, 100, scenario); let new_supply = total_supply(scenario); assert!(prev_supply == new_supply, 0); @@ -106,7 +105,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(60/VALIDATOR_COUNT, 0, 100, scenario); + advance_epoch_with_reward_amounts(60, 0, 100, scenario); let new_supply = total_supply(scenario); // 40 tokens should have been burned. @@ -124,7 +123,7 @@ module iota_system::rewards_distribution_tests { // need to advance epoch so validator's staking starts counting advance_epoch(scenario); - advance_epoch_with_reward_amounts(100/VALIDATOR_COUNT, 0, 60, scenario); + advance_epoch_with_reward_amounts(100, 0, 60, scenario); let new_supply = total_supply(scenario); // 40 tokens should have been minted. @@ -147,19 +146,19 @@ module iota_system::rewards_distribution_tests { assert_validator_self_stake_amounts(validator_addrs(), vector[100 * MICROS_PER_IOTA, 200 * MICROS_PER_IOTA, 300 * MICROS_PER_IOTA, 400 * MICROS_PER_IOTA], scenario); // Each pool gets 30 IOTA. - advance_epoch_with_reward_amounts(120/VALIDATOR_COUNT, 0, 120, scenario); + advance_epoch_with_reward_amounts(120, 0, 120, scenario); assert_validator_self_stake_amounts(validator_addrs(), vector[110 * MICROS_PER_IOTA, 220 * MICROS_PER_IOTA, 330 * MICROS_PER_IOTA, 430 * MICROS_PER_IOTA], scenario); unstake(STAKER_ADDR_1, 0, scenario); stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 600, scenario); // Each pool gets 30 IOTA. - advance_epoch_with_reward_amounts(120/VALIDATOR_COUNT, 0, 120, scenario); + advance_epoch_with_reward_amounts(120, 0, 120, scenario); // staker 1 receives only 20 IOTA of rewards, not 40 since we are using pre-epoch exchange rate. assert_eq(total_iota_balance(STAKER_ADDR_1, scenario), 220 * MICROS_PER_IOTA); assert_validator_self_stake_amounts(validator_addrs(), vector[140 * MICROS_PER_IOTA, 240 * MICROS_PER_IOTA, 360 * MICROS_PER_IOTA, 460 * MICROS_PER_IOTA], scenario); unstake(STAKER_ADDR_2, 0, scenario); assert_eq(total_iota_balance(STAKER_ADDR_2, scenario), 120 * MICROS_PER_IOTA); // 20 IOTA of rewards received - advance_epoch_with_reward_amounts(40/VALIDATOR_COUNT, 0, 40, scenario); + advance_epoch_with_reward_amounts(40, 0, 40, scenario); unstake(STAKER_ADDR_2, 0, scenario); // unstake 600 principal IOTA // additional 600 IOTA of principal and 46 IOTA of rewards withdrawn to Coin @@ -183,17 +182,17 @@ module iota_system::rewards_distribution_tests { advance_epoch(scenario); - advance_epoch_with_reward_amounts(150000/VALIDATOR_COUNT, 0, 150000, scenario); + advance_epoch_with_reward_amounts(150000, 0, 150000, scenario); // stake a small amount stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 10, scenario); - advance_epoch_with_reward_amounts(130/VALIDATOR_COUNT, 0, 130, scenario); + advance_epoch_with_reward_amounts(130, 0, 130, scenario); // unstake the stakes unstake(STAKER_ADDR_1, 1, scenario); // and advance epoch should succeed - advance_epoch_with_reward_amounts(150/VALIDATOR_COUNT, 0, 150, scenario); + advance_epoch_with_reward_amounts(150, 0, 150, scenario); scenario_val.end(); } @@ -209,7 +208,7 @@ module iota_system::rewards_distribution_tests { // V1: 200, V2: 300, V3: 300, V4: 400 set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_2, 2000, scenario); // 50% commission - advance_epoch_with_reward_amounts(120/VALIDATOR_COUNT, 0, 120, scenario); + advance_epoch_with_reward_amounts(120, 0, 120, scenario); // V1: 230, V2: 330, V3: 330, V4: 430 // 2 IOTA, or 20 % of staker_2's rewards, goes to validator_2 assert_validator_non_self_stake_amounts(validator_addrs(), vector[115 * MICROS_PER_IOTA, 108 * MICROS_PER_IOTA, 0, 0], scenario); @@ -217,7 +216,7 @@ module iota_system::rewards_distribution_tests { set_commission_rate_and_advance_epoch(VALIDATOR_ADDR_1, 1000, scenario); // 10% commission - advance_epoch_with_reward_amounts(240/VALIDATOR_COUNT, 0, 240, scenario); + advance_epoch_with_reward_amounts(240, 0, 240, scenario); assert_validator_total_stake_amounts(validator_addrs(), vector[290 * MICROS_PER_IOTA, 390 * MICROS_PER_IOTA, 390 * MICROS_PER_IOTA, 490 * MICROS_PER_IOTA], scenario); // Staker 1 rewards in the recent distribution is 0.9 x 30 = 27 IOTA @@ -338,7 +337,7 @@ module iota_system::rewards_distribution_tests { // 1000 IOTA of storage rewards, 1500 IOTA of computation rewards, 50% slashing threshold // and 20% slashing rate advance_epoch_with_reward_amounts_and_slashing_rates( - 1000/VALIDATOR_COUNT, 1500, 2000, scenario + 1000, 1500, 2000, scenario ); // Each unslashed validator staking pool gets 300 IOTA of computation rewards + 75 IOTA of storage fund rewards + @@ -382,19 +381,18 @@ module iota_system::rewards_distribution_tests { report_validator(VALIDATOR_ADDR_4, VALIDATOR_ADDR_1, scenario); advance_epoch_with_reward_amounts_and_slashing_rates( - 1000/VALIDATOR_COUNT, 3000, 10_000, scenario + 1000, 1000, 10_000, scenario ); // All validators should have 0 rewards added so their stake stays the same. assert_validator_self_stake_amounts(validator_addrs(), vector[100 * MICROS_PER_IOTA, 200 * MICROS_PER_IOTA, 300 * MICROS_PER_IOTA, 400 * MICROS_PER_IOTA], scenario); scenario.next_tx(@0x0); - // Storage fund balance should increase by 4000 IOTA. + // We started with a total supply of 1000 IOTAs and the reward was 1000 IOTAs. + // Since everyone was slashed, all the computation reward should have been burned, so we expect a total supply of 0. let mut system_state = scenario.take_shared(); - assert_eq(system_state.get_storage_fund_total_balance(), 4000 * MICROS_PER_IOTA); - // The entire 1000 IOTA of storage rewards should go to the object rebate portion of the storage fund. - assert_eq(system_state.get_storage_fund_object_rebates(), 1000 * MICROS_PER_IOTA); + assert_eq(system_state.get_iota_supply(), 0); test_scenario::return_shared(system_state); scenario_val.end(); @@ -408,23 +406,23 @@ module iota_system::rewards_distribution_tests { stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 220, scenario); - advance_epoch_with_reward_amounts(40/VALIDATOR_COUNT, 0, 40, scenario); + advance_epoch_with_reward_amounts(40, 0, 40, scenario); stake_with(STAKER_ADDR_2, VALIDATOR_ADDR_1, 480, scenario); // Staker 1 gets 2/3 * 1/4 * 120 = 20 IOTA here. - advance_epoch_with_reward_amounts(120/VALIDATOR_COUNT, 0, 120, scenario); + advance_epoch_with_reward_amounts(120, 0, 120, scenario); stake_with(STAKER_ADDR_1, VALIDATOR_ADDR_1, 130, scenario); stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 390, scenario); // Staker 1 gets 20 IOTA here and staker 2 gets 40 IOTA here. - advance_epoch_with_reward_amounts(280/VALIDATOR_COUNT, 0, 280, scenario); + advance_epoch_with_reward_amounts(280, 0, 280, scenario); stake_with(STAKER_ADDR_3, VALIDATOR_ADDR_1, 280, scenario); stake_with(STAKER_ADDR_4, VALIDATOR_ADDR_1, 1400, scenario); // Staker 1 gets 30 IOTA, staker 2 gets 40 IOTA and staker 3 gets 30 IOTA. - advance_epoch_with_reward_amounts(440/VALIDATOR_COUNT, 0, 440, scenario); + advance_epoch_with_reward_amounts(440, 0, 440, scenario); scenario.next_tx(@0x0); let mut system_state = scenario.take_shared(); @@ -481,7 +479,7 @@ module iota_system::rewards_distribution_tests { create_iota_system_state_for_testing(validators, 0, 0, ctx); // Each validator's stake gets doubled. - advance_epoch_with_reward_amounts(10000/VALIDATOR_COUNT, 0, 10000, scenario); + advance_epoch_with_reward_amounts(10000, 0, 10000, scenario); let mut i = 0; scenario.next_tx(@0x0); From ceb0b382a44b6c5551cdb416e305637d25622d0b Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Mon, 1 Jul 2024 09:57:06 +0200 Subject: [PATCH 31/35] fix: Update docs --- .../iota-system/iota_system_state_inner.md | 48 +++++++++++++++++-- .../docs/iota-system/validator_set.md | 47 ------------------ 2 files changed, 45 insertions(+), 50 deletions(-) diff --git a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md index 588fa52c4e8..38ab3f8b0f2 100644 --- a/crates/iota-framework/docs/iota-system/iota_system_state_inner.md +++ b/crates/iota-framework/docs/iota-system/iota_system_state_inner.md @@ -48,6 +48,7 @@ title: Module `0x3::iota_system_state_inner` - [Function `update_validator_next_epoch_network_pubkey`](#0x3_iota_system_state_inner_update_validator_next_epoch_network_pubkey) - [Function `update_candidate_validator_network_pubkey`](#0x3_iota_system_state_inner_update_candidate_validator_network_pubkey) - [Function `advance_epoch`](#0x3_iota_system_state_inner_advance_epoch) +- [Function `match_iota_supply_to_target_reward`](#0x3_iota_system_state_inner_match_iota_supply_to_target_reward) - [Function `epoch`](#0x3_iota_system_state_inner_epoch) - [Function `protocol_version`](#0x3_iota_system_state_inner_protocol_version) - [Function `system_state_version`](#0x3_iota_system_state_inner_system_state_version) @@ -2059,8 +2060,7 @@ gas coins. let storage_charge = storage_reward.value(); let computation_charge = computation_reward.value(); - - let mut computation_reward = self.validators.match_iota_supply_to_target_reward( + let mut computation_reward = match_iota_supply_to_target_reward( validator_target_reward, computation_reward, &mut self.iota_treasury_cap, @@ -2080,10 +2080,10 @@ gas coins. ctx, ); + // Burn any leftover rewards that were not distributed (e.g. due to slashing). self.iota_treasury_cap.supply_mut().decrease_supply(computation_reward); let new_total_stake = self.validators.total_stake(); - self.protocol_version = next_protocol_version; // Derive the reference gas price for the new epoch @@ -2122,6 +2122,48 @@ gas coins. + + + + +## Function `match_iota_supply_to_target_reward` + +Inflate or deflate the IOTA supply depending on the given target reward per validator +and the amount of computation fees burned in this epoch. + + +
public(friend) fun match_iota_supply_to_target_reward(validator_target_reward: u64, computation_reward: balance::Balance<iota::IOTA>, iota_treasury_cap: &mut coin::TreasuryCap<iota::IOTA>): balance::Balance<iota::IOTA>
+
+ + + +
+Implementation + + +
public(package) fun match_iota_supply_to_target_reward(
+  validator_target_reward: u64,
+  mut computation_reward: Balance<IOTA>,
+  iota_treasury_cap: &mut iota::coin::TreasuryCap<IOTA>
+): Balance<IOTA> {
+  if (computation_reward.value() < validator_target_reward) {
+    let tokens_to_mint = validator_target_reward - computation_reward.value();
+    let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint);
+    computation_reward.join(new_tokens);
+    computation_reward
+  } else if (computation_reward.value() > validator_target_reward) {
+    let tokens_to_burn = computation_reward.value() - validator_target_reward;
+    let rewards_to_burn = computation_reward.split(tokens_to_burn);
+    iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn);
+    computation_reward
+  } else {
+    computation_reward
+  }
+}
+
+ + +
diff --git a/crates/iota-framework/docs/iota-system/validator_set.md b/crates/iota-framework/docs/iota-system/validator_set.md index 92564d1fb03..872645a8fa3 100644 --- a/crates/iota-framework/docs/iota-system/validator_set.md +++ b/crates/iota-framework/docs/iota-system/validator_set.md @@ -31,7 +31,6 @@ title: Module `0x3::validator_set` - [Function `pool_exchange_rates`](#0x3_validator_set_pool_exchange_rates) - [Function `next_epoch_validator_count`](#0x3_validator_set_next_epoch_validator_count) - [Function `is_active_validator_by_iota_address`](#0x3_validator_set_is_active_validator_by_iota_address) -- [Function `match_iota_supply_to_target_reward`](#0x3_validator_set_match_iota_supply_to_target_reward) - [Function `is_duplicate_with_active_validator`](#0x3_validator_set_is_duplicate_with_active_validator) - [Function `is_duplicate_validator`](#0x3_validator_set_is_duplicate_validator) - [Function `count_duplicates_vec`](#0x3_validator_set_count_duplicates_vec) @@ -76,7 +75,6 @@ title: Module `0x3::validator_set` use 0x1::vector; use 0x2::bag; use 0x2::balance; -use 0x2::coin; use 0x2::event; use 0x2::iota; use 0x2::object; @@ -1440,51 +1438,6 @@ Returns true iff the address exists in active validators. - - - - -## Function `match_iota_supply_to_target_reward` - -Inflate or deflate the IOTA supply depending on the given target reward per validator -and the amount of computation fees burned in this epoch. - - -
public(friend) fun match_iota_supply_to_target_reward(self: &validator_set::ValidatorSet, validator_target_reward: u64, computation_reward: balance::Balance<iota::IOTA>, iota_treasury_cap: &mut coin::TreasuryCap<iota::IOTA>): balance::Balance<iota::IOTA>
-
- - - -
-Implementation - - -
public(package) fun match_iota_supply_to_target_reward(
-  self: &ValidatorSet,
-  validator_target_reward: u64,
-  mut computation_reward: Balance<IOTA>,
-  iota_treasury_cap: &mut iota::coin::TreasuryCap<IOTA>
-): Balance<IOTA> {
-  let validator_reward_total = validator_target_reward * self.active_validators.length();
-
-  if (computation_reward.value() < validator_reward_total) {
-    let tokens_to_mint = validator_reward_total - computation_reward.value();
-    let new_tokens = iota_treasury_cap.supply_mut().increase_supply(tokens_to_mint);
-    computation_reward.join(new_tokens);
-    computation_reward
-  } else if (computation_reward.value() > validator_reward_total) {
-    let tokens_to_burn = computation_reward.value() - validator_reward_total;
-    let rewards_to_burn = computation_reward.split(tokens_to_burn);
-    iota_treasury_cap.supply_mut().decrease_supply(rewards_to_burn);
-    computation_reward
-  } else {
-    computation_reward
-  }
-}
-
- - -
From 5365161168e492c1833a398d98b100fbc0486826 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Mon, 1 Jul 2024 10:30:09 +0200 Subject: [PATCH 32/35] fix: Mint correct amount of nanos in genesis PTB --- crates/iota-genesis-builder/src/lib.rs | 4 ++-- crates/iota-indexer/src/types.rs | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs index 016f21fd905..a20c5d12a90 100644 --- a/crates/iota-genesis-builder/src/lib.rs +++ b/crates/iota-genesis-builder/src/lib.rs @@ -33,7 +33,7 @@ use iota_types::{ effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents}, epoch_data::EpochData, gas::IotaGasStatus, - gas_coin::{GasCoin, GAS, NANOS_PER_IOTA}, + gas_coin::{GasCoin, GAS, TOTAL_SUPPLY_NANOS}, governance::StakedIota, in_memory_storage::InMemoryStorage, inner_temporary_store::InnerTemporaryStore, @@ -1101,7 +1101,7 @@ pub fn generate_genesis_system_object( let total_iota_supply = builder .input(CallArg::Pure( - bcs::to_bytes(&NANOS_PER_IOTA).expect("serialization of u64 should succeed"), + bcs::to_bytes(&TOTAL_SUPPLY_NANOS).expect("serialization of u64 should succeed"), )) .expect("adding the total IOTA supply argument should succeed"); let total_iota = builder.programmable_move_call( diff --git a/crates/iota-indexer/src/types.rs b/crates/iota-indexer/src/types.rs index c6e29053d4c..655075f1cdc 100644 --- a/crates/iota-indexer/src/types.rs +++ b/crates/iota-indexer/src/types.rs @@ -144,11 +144,13 @@ impl IndexedEpochInfo { ), last_checkpoint_id: Some(*last_checkpoint_summary.sequence_number()), epoch_end_timestamp: Some(last_checkpoint_summary.timestamp_ms), - storage_fund_reinvestment: Some(event.storage_fund_reinvestment), + // TODO: Remove in a later step. + storage_fund_reinvestment: None, storage_charge: Some(event.storage_charge), storage_rebate: Some(event.storage_rebate), leftover_storage_fund_inflow: Some(event.leftover_storage_fund_inflow), - stake_subsidy_amount: Some(event.stake_subsidy_amount), + // TODO: Remove in a later step. + stake_subsidy_amount: None, total_gas_fees: Some(event.total_gas_fees), total_stake_rewards_distributed: Some(event.total_stake_rewards_distributed), epoch_commitments: last_checkpoint_summary @@ -589,7 +591,7 @@ impl From for ObjectChange { object_id, version, digest, - }, + }, } } } From 22d3c09f97042ef903d10e859dff637fa78841bb Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Mon, 1 Jul 2024 14:07:20 +0200 Subject: [PATCH 33/35] fix: advance_epoch params and conservation check --- .../latest/iota-adapter/src/execution_engine.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/iota-execution/latest/iota-adapter/src/execution_engine.rs b/iota-execution/latest/iota-adapter/src/execution_engine.rs index fb39c72e47a..cfa397f517c 100644 --- a/iota-execution/latest/iota-adapter/src/execution_engine.rs +++ b/iota-execution/latest/iota-adapter/src/execution_engine.rs @@ -274,7 +274,9 @@ mod checked { "No gas charges must be applied yet" ); - let is_genesis_tx = matches!(transaction_kind, TransactionKind::Genesis(_)); + let is_genesis_or_epoch_change_tx = matches!(transaction_kind, TransactionKind::Genesis(_)) + || transaction_kind.is_end_of_epoch_tx(); + let advance_epoch_gas_summary = transaction_kind.get_advance_epoch_tx_gas_summary(); // We must charge object read here during transaction execution, because if this @@ -348,7 +350,7 @@ mod checked { protocol_config.simple_conservation_checks(), enable_expensive_checks, &cost_summary, - is_genesis_tx, + is_genesis_or_epoch_change_tx, advance_epoch_gas_summary, ) { // FIXME: we cannot fail the transaction if this is an epoch change transaction. @@ -367,11 +369,11 @@ mod checked { simple_conservation_checks: bool, enable_expensive_checks: bool, cost_summary: &GasCostSummary, - is_genesis_tx: bool, + is_genesis_or_epoch_change_tx: bool, advance_epoch_gas_summary: Option<(u64, u64)>, ) -> Result<(), ExecutionError> { let mut result: std::result::Result<(), iota_types::error::ExecutionError> = Ok(()); - if !is_genesis_tx && !Mode::skip_conservation_checks() { + if !is_genesis_or_epoch_change_tx && !Mode::skip_conservation_checks() { // ensure that this transaction did not create or destroy IOTA, try to recover // if the check fails let conservation_result = { @@ -718,8 +720,8 @@ mod checked { // Step 2: Advance the epoch. let mut arguments = vec![ builder - .input(CallArg::Pure(bcs::to_bytes(¶ms.validator_target_reward).unwrap())) - .expect("builder input on pure call arg should not fail"), + .pure(params.validator_target_reward) + .expect("bcs encoding a u64 should not fail"), storage_rewards, computation_rewards, ]; @@ -728,8 +730,6 @@ mod checked { CallArg::Pure(bcs::to_bytes(¶ms.epoch).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.next_protocol_version.as_u64()).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.storage_rebate).unwrap()), - CallArg::Pure(bcs::to_bytes(¶ms.non_refundable_storage_fee).unwrap()), - CallArg::Pure(bcs::to_bytes(¶ms.storage_fund_reinvest_rate).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.reward_slashing_rate).unwrap()), CallArg::Pure(bcs::to_bytes(¶ms.epoch_start_timestamp_ms).unwrap()), ] From af217746a875734c35c8c8eb23b6b85fbfe95be7 Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Mon, 1 Jul 2024 15:00:20 +0200 Subject: [PATCH 34/35] fix: Skip the authority conservation checks for now --- crates/iota-core/src/authority.rs | 33 +++++++++++++++++-------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/crates/iota-core/src/authority.rs b/crates/iota-core/src/authority.rs index 44d75f7769f..908a30d1e47 100644 --- a/crates/iota-core/src/authority.rs +++ b/crates/iota-core/src/authority.rs @@ -2981,21 +2981,24 @@ impl AuthorityState { cur_epoch_store.epoch() ); - if let Err(err) = self - .execution_cache - .expensive_check_iota_conservation(cur_epoch_store) - { - if cfg!(debug_assertions) { - panic!("{}", err); - } else { - // We cannot panic in production yet because it is known that there are some - // inconsistencies in testnet. We will enable this once we make it balanced - // again in testnet. - warn!("Iota conservation consistency check failed: {}", err); - } - } else { - info!("Iota conservation consistency check passed"); - } + // Skip the iota conservation check since it will be violated due to inflation/deflation for validator rewards. + // TODO: Investigate whether we can still keep this check for something useful or if it needs to be removed entirely. + + // if let Err(err) = self + // .execution_cache + // .expensive_check_iota_conservation(cur_epoch_store) + // { + // if cfg!(debug_assertions) { + // panic!("{}", err); + // } else { + // // We cannot panic in production yet because it is known that there are some + // // inconsistencies in testnet. We will enable this once we make it balanced + // // again in testnet. + // warn!("Iota conservation consistency check failed: {}", err); + // } + // } else { + // info!("Iota conservation consistency check passed"); + // } // check for root state hash consistency with live object set if expensive_safety_check_config.enable_state_consistency_check() { From 46d16caadd0f54ea4429d30f155ed31f5bcbbeab Mon Sep 17 00:00:00 2001 From: Philipp Gackstatter Date: Tue, 2 Jul 2024 11:46:38 +0200 Subject: [PATCH 35/35] feat: Rework genesis supply minting and burning --- .../docs/iota-framework/iota.md | 31 ++++++++++++ .../packages/iota-framework/sources/iota.move | 11 +++++ crates/iota-genesis-builder/src/lib.rs | 49 ++++--------------- 3 files changed, 51 insertions(+), 40 deletions(-) diff --git a/crates/iota-framework/docs/iota-framework/iota.md b/crates/iota-framework/docs/iota-framework/iota.md index b98484ab93c..ca60e147ef6 100644 --- a/crates/iota-framework/docs/iota-framework/iota.md +++ b/crates/iota-framework/docs/iota-framework/iota.md @@ -9,10 +9,12 @@ It has 9 decimals, and the smallest unit (10^-9) is called "nano". - [Struct `IOTA`](#0x2_iota_IOTA) - [Constants](#@Constants_0) - [Function `new`](#0x2_iota_new) +- [Function `mint_genesis_supply`](#0x2_iota_mint_genesis_supply) - [Function `transfer`](#0x2_iota_transfer)
use 0x1::option;
+use 0x2::balance;
 use 0x2::coin;
 use 0x2::transfer;
 use 0x2::tx_context;
@@ -133,6 +135,35 @@ This should be called only once during genesis creation.
 
 
 
+
+
+
+
+## Function `mint_genesis_supply`
+
+Increase the IOTA supply.
+This should be called only once during genesis creation.
+
+
+
fun mint_genesis_supply(cap: &mut coin::TreasuryCap<iota::IOTA>, amount: u64, ctx: &tx_context::TxContext): balance::Balance<iota::IOTA>
+
+ + + +
+Implementation + + +
fun mint_genesis_supply(cap: &mut TreasuryCap<IOTA>, amount: u64, ctx: &TxContext): Balance<IOTA> {
+    assert!(ctx.sender() == @0x0, ENotSystemAddress);
+    assert!(ctx.epoch() == 0, EAlreadyMinted);
+
+    cap.supply_mut().increase_supply(amount)
+}
+
+ + +
diff --git a/crates/iota-framework/packages/iota-framework/sources/iota.move b/crates/iota-framework/packages/iota-framework/sources/iota.move index bd9ece4a1e4..1c9cea7f8bf 100644 --- a/crates/iota-framework/packages/iota-framework/sources/iota.move +++ b/crates/iota-framework/packages/iota-framework/sources/iota.move @@ -6,6 +6,7 @@ /// It has 9 decimals, and the smallest unit (10^-9) is called "nano". module iota::iota { use iota::coin::{Self, TreasuryCap}; + use iota::balance::Balance; use iota::url; const EAlreadyMinted: u64 = 0; @@ -46,6 +47,16 @@ module iota::iota { treasury } + #[allow(unused_function)] + /// Increase the IOTA supply. + /// This should be called only once during genesis creation. + fun mint_genesis_supply(cap: &mut TreasuryCap, amount: u64, ctx: &TxContext): Balance { + assert!(ctx.sender() == @0x0, ENotSystemAddress); + assert!(ctx.epoch() == 0, EAlreadyMinted); + + cap.supply_mut().increase_supply(amount) + } + public entry fun transfer(c: coin::Coin, recipient: address) { transfer::public_transfer(c, recipient) } diff --git a/crates/iota-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs index a20c5d12a90..4ce25f46ae6 100644 --- a/crates/iota-genesis-builder/src/lib.rs +++ b/crates/iota-genesis-builder/src/lib.rs @@ -1091,53 +1091,22 @@ pub fn generate_genesis_system_object( vec![], ); - let iota_supply = builder.programmable_move_call( - IOTA_FRAMEWORK_PACKAGE_ID, - ident_str!("coin").to_owned(), - ident_str!("supply_mut").to_owned(), - vec![GAS::type_().into()], - vec![iota_treasury_cap], - ); - + // TODO: This is will need to be modified after the timelock staking changes and + // to account for the migration objects with pre-allocated funds. let total_iota_supply = builder - .input(CallArg::Pure( - bcs::to_bytes(&TOTAL_SUPPLY_NANOS).expect("serialization of u64 should succeed"), - )) - .expect("adding the total IOTA supply argument should succeed"); + .pure(&(TOTAL_SUPPLY_NANOS - token_distribution_schedule.funds_to_burn)) + .expect("serialization of u64 should succeed"); let total_iota = builder.programmable_move_call( IOTA_FRAMEWORK_PACKAGE_ID, - ident_str!("balance").to_owned(), - ident_str!("increase_supply").to_owned(), - vec![GAS::type_().into()], - vec![iota_supply, total_iota_supply], - ); - - // Step 5: Burn the tokens that are marked as such, according to the token distribution schedule. - let iotas_to_burn_arg = builder - .input(CallArg::Pure( - bcs::to_bytes(&token_distribution_schedule.funds_to_burn) - .expect("serialization of u64 should succeed"), - )) - .expect("adding the funds to burn argument should succeed"); - let iotas_to_burn_balance = builder.programmable_move_call( - IOTA_FRAMEWORK_PACKAGE_ID, - ident_str!("balance").to_owned(), - ident_str!("split").to_owned(), - vec![GAS::type_().into()], - vec![total_iota, iotas_to_burn_arg], - ); - - builder.programmable_move_call( - IOTA_FRAMEWORK_PACKAGE_ID, - ident_str!("balance").to_owned(), - ident_str!("decrease_supply").to_owned(), - vec![GAS::type_().into()], - vec![iota_supply, iotas_to_burn_balance], + ident_str!("iota").to_owned(), + ident_str!("mint_genesis_supply").to_owned(), + vec![], + vec![iota_treasury_cap, total_iota_supply], ); // TODO: Rename the `destroy_storage_rebates` function or create a specific one. - // Step 6: Run genesis. + // Step 5: Run genesis. // The first argument is the system state uid we got from step 1 and the second // one is the IOTA `TreasuryCap` we got from step 4. let mut arguments = vec![iota_system_state_uid, iota_treasury_cap, total_iota];