diff --git a/crates/iota-config/src/genesis.rs b/crates/iota-config/src/genesis.rs index 032dae25887..581ea1f81be 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, @@ -434,30 +428,27 @@ impl GenesisCeremonyParameters { } fn default_initial_stake_subsidy_distribution_amount() -> u64 { - // 1M Iota - 1_000_000 * iota_types::gas_coin::NANOS_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 { 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_NANOS, validator_low_stake_threshold: @@ -476,16 +467,18 @@ 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 { - pub stake_subsidy_fund_nanos: u64, + pub funds_to_burn: u64, pub allocations: Vec, } impl TokenDistributionSchedule { pub fn validate(&self) { - let mut total_nanos = self.stake_subsidy_fund_nanos; + let mut total_nanos = self.funds_to_burn; for allocation in &self.allocations { total_nanos += allocation.amount_nanos; @@ -532,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 { @@ -551,7 +549,7 @@ impl TokenDistributionSchedule { .collect(); let schedule = Self { - stake_subsidy_fund_nanos: supply, + funds_to_burn: supply, allocations, }; @@ -575,23 +573,21 @@ impl TokenDistributionSchedule { assert_eq!( TOTAL_SUPPLY_NANOS, allocations.iter().map(|a| a.amount_nanos).sum::(), - "Token Distribution Schedule must add up to 10B Iota", + "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 { - stake_subsidy_fund_nanos: stake_subsidy_fund_allocation.amount_nanos, + funds_to_burn: funds_to_burn_allocation.amount_nanos, allocations, }; @@ -608,7 +604,7 @@ impl TokenDistributionSchedule { writer.serialize(TokenAllocation { recipient_address: IotaAddress::default(), - amount_nanos: self.stake_subsidy_fund_nanos, + amount_nanos: self.funds_to_burn, staked_with_validator: None, })?; @@ -629,7 +625,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, } @@ -637,7 +634,8 @@ impl TokenDistributionScheduleBuilder { #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { - pool: TOTAL_SUPPLY_NANOS, + remaining_supply: TOTAL_SUPPLY_NANOS, + funds_to_burn: 0, allocations: vec![], } } @@ -658,13 +656,22 @@ impl TokenDistributionScheduleBuilder { } pub fn add_allocation(&mut self, allocation: TokenAllocation) { - self.pool = self.pool.checked_sub(allocation.amount_nanos).unwrap(); + self.remaining_supply = self + .remaining_supply + .checked_sub(allocation.amount_nanos) + .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_nanos: self.pool, + funds_to_burn: self.remaining_supply, allocations: self.allocations.clone(), }; 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() { diff --git a/crates/iota-framework/docs/iota-framework/iota.md b/crates/iota-framework/docs/iota-framework/iota.md index 882773811f8..ca60e147ef6 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 "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) @@ -99,11 +100,11 @@ The total supply of IOTA denominated in Nano (4.6 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>
 
@@ -112,7 +113,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);
 
@@ -125,11 +126,39 @@ This should be called only once during genesis creation.
         option::some(url::new_unsafe_from_bytes(b"https://iota.org/logo.png")),
         ctx
     );
+
     transfer::public_freeze_object(metadata);
-    let mut supply = treasury.treasury_into_supply();
-    let total_iota = supply.increase_supply(TOTAL_SUPPLY_NANO);
-    supply.destroy_supply();
-    total_iota
+
+    treasury
+}
+
+ + + + + + + +## 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/docs/iota-system/genesis.md b/crates/iota-framework/docs/iota-system/genesis.md index a7d37d69f15..7563da346a3 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_nanos: u64 +funds_to_burn: u64
@@ -340,7 +315,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,7 +326,8 @@ all the information we need in the system.
fun create(
     iota_system_state_id: UID,
-    mut iota_supply: Balance<IOTA>,
+    iota_treasury_cap: TreasuryCap<IOTA>,
+    iota_supply: Balance<IOTA>,
     genesis_chain_parameters: GenesisChainParameters,
     genesis_validators: vector<GenesisValidatorMetadata>,
     token_distribution_schedule: TokenDistributionSchedule,
@@ -361,11 +337,10 @@ all the information we need in the system.
     assert!(ctx.epoch() == 0, ENotCalledAtGenesis);
 
     let TokenDistributionSchedule {
-        stake_subsidy_fund_nanos,
+        funds_to_burn: _,
         allocations,
     } = token_distribution_schedule;
 
-    let subsidy_fund = iota_supply.split(stake_subsidy_fund_nanos);
     let storage_fund = balance::zero();
 
     // Create all the `Validator` structs
@@ -434,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,
@@ -446,22 +420,14 @@ 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,
         validators,
         storage_fund,
         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 cf6ab5c3c8a..3df8bccda4b 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, 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)
 
@@ -178,21 +177,21 @@ 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,
     epoch_start_timestamp_ms: u64,
     parameters: SystemParameters,
-    stake_subsidy: StakeSubsidy,
     ctx: &mut TxContext,
 ) {
     let system_state = iota_system_state_inner::create(
+        iota_treasury_cap,
         validators,
         storage_fund,
         protocol_version,
         epoch_start_timestamp_ms,
         parameters,
-        stake_subsidy,
         ctx,
     );
     let version = iota_system_state_inner::genesis_system_state_version();
@@ -1360,7 +1359,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, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -1370,15 +1369,13 @@ gas coins.
fun advance_epoch(
+    validator_target_reward: u64,
     storage_reward: Balance<IOTA>,
     computation_reward: Balance<IOTA>,
     wrapper: &mut IotaSystemState,
     new_epoch: u64,
     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,
@@ -1389,11 +1386,10 @@ gas coins.
     let storage_rebate = self.advance_epoch(
         new_epoch,
         next_protocol_version,
+        validator_target_reward,
         storage_reward,
         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 457f001f402..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)
@@ -62,6 +63,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;
@@ -77,7 +80,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;
@@ -111,12 +113,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
@@ -186,12 +182,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
@@ -281,6 +271,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
@@ -318,12 +314,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
@@ -413,6 +403,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
@@ -450,12 +446,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
@@ -548,12 +538,6 @@ the epoch advancement transaction.
-
-
-storage_fund_reinvestment: u64 -
-
-
storage_charge: u64 @@ -572,30 +556,12 @@ the epoch advancement transaction.
-
-
-stake_subsidy_amount: u64 -
-
-
total_gas_fees: u64
-
-
-total_stake_rewards_distributed: u64 -
-
- -
-
-leftover_storage_fund_inflow: u64 -
-
-
@@ -741,7 +707,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, ctx: &mut tx_context::TxContext): iota_system_state_inner::IotaSystemStateInner
 
@@ -751,12 +717,12 @@ 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,
     epoch_start_timestamp_ms: u64,
     parameters: SystemParameters,
-    stake_subsidy: StakeSubsidy,
     ctx: &mut TxContext,
 ): IotaSystemStateInner {
     let validators = validator_set::new(validators, ctx);
@@ -766,12 +732,12 @@ 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,
         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(),
@@ -794,7 +760,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
 
@@ -805,7 +771,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,
@@ -817,7 +782,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,
@@ -852,12 +816,12 @@ This function will be called only once in genesis.
         epoch,
         protocol_version,
         system_state_version: _,
+        iota_treasury_cap,
         validators,
         storage_fund,
         parameters,
         reference_gas_price,
         validator_report_records,
-        stake_subsidy,
         safe_mode,
         safe_mode_storage_rewards,
         safe_mode_computation_rewards,
@@ -868,7 +832,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,
@@ -880,11 +843,11 @@ This function will be called only once in genesis.
         epoch,
         protocol_version,
         system_state_version: 2,
+        iota_treasury_cap,
         validators,
         storage_fund,
         parameters: SystemParametersV2 {
             epoch_duration_ms,
-            stake_subsidy_start_epoch,
             min_validator_count: 4,
             max_validator_count,
             min_validator_joining_stake,
@@ -895,7 +858,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,
@@ -2060,7 +2022,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, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut tx_context::TxContext): balance::Balance<iota::IOTA>
 
@@ -2073,31 +2035,19 @@ 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, - 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, ) : 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; // Rates can't be higher than 100%. - assert!( - storage_fund_reinvest_rate <= bps_denominator_u64 - && reward_slashing_rate <= bps_denominator_u64, - EBpsTooLarge, - ); - - // TODO: remove this in later upgrade. - if (self.parameters.stake_subsidy_start_epoch > 0) { - self.parameters.stake_subsidy_start_epoch = 20; - }; + 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(); @@ -2106,52 +2056,22 @@ 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(); - - // 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 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); - 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, + let mut computation_reward = match_iota_supply_to_target_reward( + validator_target_reward, + computation_reward, + &mut self.iota_treasury_cap, ); 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, @@ -2160,33 +2080,22 @@ 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(); - let computation_reward_amount_after_distribution = computation_reward.value(); - 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; - 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`. - // All of these go to the storage fund. - let mut leftover_staking_rewards = storage_fund_reward; - leftover_staking_rewards.join(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, ); + // TODO: Consider emitting the minted or burned tokens from the IOTA supply here for informational purposes. event::emit( SystemEpochInfoEvent { epoch: self.epoch, @@ -2194,14 +2103,10 @@ 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(), - stake_subsidy_amount, 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. @@ -2217,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
+  }
+}
+
+ + +
@@ -2594,4 +2541,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/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())
-}
-
- - - -
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..fe4b2fa8278 --- /dev/null +++ b/crates/iota-framework/docs/iota-system/storage_deposits.md @@ -0,0 +1,141 @@ +--- +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 + + +
+
+refundable_balance: balance::Balance<iota::IOTA> +
+
+ +
+
+non_refundable_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
+        refundable_balance: initial_balance,
+        non_refundable_balance: balance::zero()
+    }
+}
+
+ + + +
+ + + +## 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.refundable_balance.join(storage_charges);
+
+    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);
+    // 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.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..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>, 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>, storage_rebate_amount: u64): balance::Balance<iota::IOTA>
 
@@ -106,24 +106,13 @@ 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);
-    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);
@@ -178,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 98d96d0b20c..872645a8fa3 100644 --- a/crates/iota-framework/docs/iota-system/validator_set.md +++ b/crates/iota-framework/docs/iota-system/validator_set.md @@ -230,12 +230,6 @@ each validator, emitted during epoch advancement.
-
-
-storage_fund_staking_reward: u64 -
-
-
pool_token_exchange_rate: staking_pool::PoolTokenExchangeRate @@ -318,12 +312,6 @@ V2 of ValidatorEpochInfoEvent containing more information about the validator.
-
-
-storage_fund_staking_reward: u64 -
-
-
pool_token_exchange_rate: staking_pool::PoolTokenExchangeRate @@ -992,7 +980,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)
 
@@ -1004,7 +992,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,
@@ -1016,11 +1003,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
@@ -1031,30 +1017,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
@@ -1062,9 +1042,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
     );
 
@@ -1073,8 +1051,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);
@@ -2390,7 +2367,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>)
 
@@ -2403,17 +2380,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(); @@ -2428,19 +2400,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,) }
@@ -2501,7 +2463,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>
 
@@ -2514,12 +2476,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]; @@ -2530,10 +2489,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 }
@@ -2550,7 +2508,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>
 
@@ -2564,18 +2522,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) { @@ -2601,24 +2554,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 }
@@ -2632,7 +2571,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)
 
@@ -2644,9 +2583,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();
@@ -2661,12 +2598,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) {
@@ -2696,7 +2628,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>)
 
@@ -2709,7 +2641,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>, ) { @@ -2736,7 +2667,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-framework/sources/iota.move b/crates/iota-framework/packages/iota-framework/sources/iota.move index 51f5e238991..1c9cea7f8bf 100644 --- a/crates/iota-framework/packages/iota-framework/sources/iota.move +++ b/crates/iota-framework/packages/iota-framework/sources/iota.move @@ -5,8 +5,8 @@ /// 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::coin::{Self, TreasuryCap}; use iota::balance::Balance; - use iota::coin; use iota::url; const EAlreadyMinted: u64 = 0; @@ -18,6 +18,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; @@ -25,9 +26,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); @@ -40,11 +41,20 @@ module iota::iota { option::some(url::new_unsafe_from_bytes(b"https://iota.org/logo.png")), ctx ); + transfer::public_freeze_object(metadata); - let mut supply = treasury.treasury_into_supply(); - let total_iota = supply.increase_supply(TOTAL_SUPPLY_NANO); - supply.destroy_supply(); - total_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) { 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/iota-system/sources/genesis.move b/crates/iota-framework/packages/iota-system/sources/genesis.move index c1c72068ed6..b482b53bc7a 100644 --- a/crates/iota-framework/packages/iota-system/sources/genesis.move +++ b/crates/iota-framework/packages/iota-system/sources/genesis.move @@ -5,12 +5,12 @@ 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}; 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, @@ -40,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, @@ -55,7 +49,7 @@ module iota_system::genesis { } public struct TokenDistributionSchedule { - stake_subsidy_fund_nanos: u64, + funds_to_burn: u64, allocations: vector, } @@ -79,7 +73,8 @@ module iota_system::genesis { /// all the information we need in the system. fun create( iota_system_state_id: UID, - mut iota_supply: Balance, + iota_treasury_cap: TreasuryCap, + iota_supply: Balance, genesis_chain_parameters: GenesisChainParameters, genesis_validators: vector, token_distribution_schedule: TokenDistributionSchedule, @@ -89,11 +84,10 @@ module iota_system::genesis { assert!(ctx.epoch() == 0, ENotCalledAtGenesis); let TokenDistributionSchedule { - stake_subsidy_fund_nanos, + funds_to_burn: _, allocations, } = token_distribution_schedule; - let subsidy_fund = iota_supply.split(stake_subsidy_fund_nanos); let storage_fund = balance::zero(); // Create all the `Validator` structs @@ -162,7 +156,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, @@ -174,22 +167,14 @@ 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, validators, storage_fund, 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 9906271b539..e88ae0cbc78 100644 --- a/crates/iota-framework/packages/iota-system/sources/iota_system.move +++ b/crates/iota-framework/packages/iota-system/sources/iota_system.move @@ -42,14 +42,13 @@ 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; 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; @@ -78,21 +77,21 @@ 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, epoch_start_timestamp_ms: u64, parameters: SystemParameters, - stake_subsidy: StakeSubsidy, ctx: &mut TxContext, ) { let system_state = iota_system_state_inner::create( + iota_treasury_cap, validators, storage_fund, protocol_version, epoch_start_timestamp_ms, parameters, - stake_subsidy, ctx, ); let version = iota_system_state_inner::genesis_system_state_version(); @@ -536,15 +535,13 @@ 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, new_epoch: u64, 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, @@ -555,11 +552,10 @@ 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, - non_refundable_storage_fee, - storage_fund_reinvest_rate, reward_slashing_rate, epoch_start_timestamp_ms, ctx, @@ -691,9 +687,9 @@ module iota_system::iota_system { } #[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() + 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 @@ -744,11 +740,10 @@ 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, - non_refundable_storage_fee: u64, - storage_fund_reinvest_rate: u64, reward_slashing_rate: u64, epoch_start_timestamp_ms: u64, ctx: &mut TxContext, @@ -756,14 +751,13 @@ 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, new_epoch, 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 f4270501b06..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 @@ -4,13 +4,12 @@ module iota_system::iota_system_state_inner { use iota::balance::{Self, Balance}; - use iota::coin::Coin; + 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}; 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, @@ -110,6 +103,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. @@ -127,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. @@ -158,6 +151,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. @@ -175,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. @@ -203,14 +196,10 @@ 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, } // Errors @@ -232,12 +221,12 @@ 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, epoch_start_timestamp_ms: u64, parameters: SystemParameters, - stake_subsidy: StakeSubsidy, ctx: &mut TxContext, ): IotaSystemStateInner { let validators = validator_set::new(validators, ctx); @@ -247,12 +236,12 @@ 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, 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(), @@ -266,7 +255,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, @@ -278,7 +266,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, @@ -293,12 +280,12 @@ module iota_system::iota_system_state_inner { epoch, protocol_version, system_state_version: _, + iota_treasury_cap, validators, storage_fund, parameters, reference_gas_price, validator_report_records, - stake_subsidy, safe_mode, safe_mode_storage_rewards, safe_mode_computation_rewards, @@ -309,7 +296,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, @@ -321,11 +307,11 @@ module iota_system::iota_system_state_inner { epoch, protocol_version, system_state_version: 2, + iota_treasury_cap, validators, storage_fund, parameters: SystemParametersV2 { epoch_duration_ms, - stake_subsidy_start_epoch, min_validator_count: 4, max_validator_count, min_validator_joining_stake, @@ -336,7 +322,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, @@ -808,6 +793,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. @@ -819,31 +805,19 @@ 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, - 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, ) : 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; // Rates can't be higher than 100%. - assert!( - storage_fund_reinvest_rate <= bps_denominator_u64 - && reward_slashing_rate <= bps_denominator_u64, - EBpsTooLarge, - ); - - // TODO: remove this in later upgrade. - if (self.parameters.stake_subsidy_start_epoch > 0) { - self.parameters.stake_subsidy_start_epoch = 20; - }; + 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(); @@ -852,52 +826,22 @@ 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(); - - // 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 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); - 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, + let mut computation_reward = match_iota_supply_to_target_reward( + validator_target_reward, + computation_reward, + &mut self.iota_treasury_cap, ); 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, @@ -906,33 +850,22 @@ 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(); - let computation_reward_amount_after_distribution = computation_reward.value(); - 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; - 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`. - // All of these go to the storage fund. - let mut leftover_staking_rewards = storage_fund_reward; - leftover_staking_rewards.join(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, ); + // TODO: Consider emitting the minted or burned tokens from the IOTA supply here for informational purposes. event::emit( SystemEpochInfoEvent { epoch: self.epoch, @@ -940,14 +873,10 @@ 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(), - stake_subsidy_amount, 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. @@ -960,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 { @@ -1083,8 +1034,8 @@ module iota_system::iota_system_state_inner { } #[test_only] - public(package) fun get_stake_subsidy_distribution_counter(self: &IotaSystemStateInnerV2): u64 { - self.stake_subsidy.get_distribution_counter() + public(package) fun get_total_iota_supply(self: &IotaSystemStateInnerV2): u64 { + self.iota_treasury_cap.total_supply() } #[test_only] @@ -1152,4 +1103,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) + } } 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/sources/storage_deposits.move b/crates/iota-framework/packages/iota-system/sources/storage_deposits.move new file mode 100644 index 00000000000..00a5ae0a89e --- /dev/null +++ b/crates/iota-framework/packages/iota-system/sources/storage_deposits.move @@ -0,0 +1,44 @@ +// 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::{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 { + 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 + refundable_balance: initial_balance, + non_refundable_balance: balance::zero() + } + } + + /// 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.refundable_balance.join(storage_charges); + + 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); + // burn_iota(treasury_cap, storage_rebate_amount, ctx); + storage_rebate + } + + public fun total_balance(self: &StorageDeposits): u64 { + self.refundable_balance.value() + self.non_refundable_balance.value() + } +} 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..d66053dc962 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,24 +32,13 @@ 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); - 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); @@ -66,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 6ef543868b1..968647c488b 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); @@ -976,17 +963,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(); @@ -1000,20 +982,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 @@ -1047,12 +1019,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]; @@ -1063,10 +1032,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. @@ -1077,18 +1045,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) { @@ -1114,32 +1077,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(); @@ -1154,12 +1101,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) { @@ -1182,7 +1124,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
, ) { @@ -1209,7 +1150,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/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 327418973ac..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 @@ -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,22 +71,20 @@ 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); + 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 + iota_treasury_cap, validators, balance::create_for_testing(storage_fund_amount * MICROS_PER_IOTA), // storage_fund 1, // protocol version 0, // chain_start_timestamp_ms system_parameters, - stake_subsidy, ctx, ) } @@ -109,11 +105,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, scenario: &mut Scenario, ): Balance { scenario.next_tx(@0x0); let new_epoch = scenario.ctx().epoch() + 1; @@ -122,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, 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, 0, 0, ctx, ); test_scenario::return_shared(system_state); scenario.next_epoch(@0x0); @@ -130,9 +126,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, scenario); test_utils::destroy(storage_rebate) } @@ -148,8 +144,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, reward_slashing_rate, 0, ctx ); test_utils::destroy(storage_rebate); test_scenario::return_shared(system_state); @@ -340,4 +337,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/iota_system_tests.move b/crates/iota-framework/packages/iota-system/tests/iota_system_tests.move index 0761eab8301..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] @@ -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); - } } 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..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 @@ -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); @@ -327,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, 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(); @@ -353,23 +406,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 +449,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 +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(0, 10000, scenario); + advance_epoch_with_reward_amounts(10000, 0, 10000, scenario); let mut i = 0; scenario.next_tx(@0x0); 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-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" diff --git a/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move b/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move index 9fc4ccdfed5..f2d82bff99b 100644 --- a/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move +++ b/crates/iota-framework/packages/timelock/tests/timelocked_delegation_tests.move @@ -604,7 +604,7 @@ module timelock::timelocked_stake_tests { ); // 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); remove_validator(VALIDATOR_ADDR_1, scenario); @@ -661,7 +661,7 @@ module timelock::timelocked_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. @@ -745,8 +745,8 @@ module timelock::timelocked_stake_tests { stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, 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_timelocked(STAKER_ADDR_1, 0, scenario); @@ -784,7 +784,7 @@ module timelock::timelocked_stake_tests { // Delegate 100 IOTA to the preactive validator stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, 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 @@ -798,7 +798,7 @@ module timelock::timelocked_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 @@ -812,7 +812,7 @@ module timelock::timelocked_stake_tests { assert_eq(total_timelocked_iota_balance(STAKER_ADDR_3, scenario), 100 * MICROS_PER_IOTA); assert_eq(total_iota_balance(STAKER_ADDR_3, scenario), 10_002_000_000); - advance_epoch_with_reward_amounts(0, 85, scenario); + advance_epoch_with_reward_amounts(85, 0, 85, scenario); unstake_timelocked(STAKER_ADDR_2, 0, scenario); // staker 2 earns about 5 IOTA from the previous epoch and 24-ish from this one @@ -840,7 +840,7 @@ module timelock::timelocked_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); @@ -866,7 +866,7 @@ module timelock::timelocked_stake_tests { stake_timelocked_with(STAKER_ADDR_1, NEW_VALIDATOR_ADDR, 100, 10, 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); @@ -896,7 +896,7 @@ module timelock::timelocked_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-genesis-builder/src/lib.rs b/crates/iota-genesis-builder/src/lib.rs index 6acec5e2c6b..4ce25f46ae6 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_NANOS}, governance::StakedIota, in_memory_storage::InMemoryStorage, inner_temporary_store::InnerTemporaryStore, @@ -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; @@ -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_nanos - ); - let mut gas_objects: BTreeMap = unsigned_genesis .objects() .iter() @@ -1060,7 +1036,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 +1045,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 +1056,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 +1065,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 +1074,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 +1082,34 @@ 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![], ); + // 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 + .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!("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 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()), 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-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, - }, + }, } } } 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, diff --git a/crates/iota-protocol-config/src/lib.rs b/crates/iota-protocol-config/src/lib.rs index d7666addc07..e20898d6fe0 100644 --- a/crates/iota-protocol-config/src/lib.rs +++ b/crates/iota-protocol-config/src/lib.rs @@ -659,6 +659,9 @@ pub struct ProtocolConfig { /// Unit gas price, Micros per internal gas unit. storage_gas_price: Option, + /// The number of tokens that the set of validators should receive per epoch. + validator_target_reward: Option, + /// === Core Protocol === /// Max number of transactions per checkpoint. @@ -1362,6 +1365,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/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, diff --git a/crates/iota-types/src/governance.rs b/crates/iota-types/src/governance.rs index d526b21784f..1c6feb40c1e 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_NANOS: u64 = 30_000_000 * NANOS_PER_IOTA; +/// 2 million IOTA +pub const MIN_VALIDATOR_JOINING_STAKE_NANOS: u64 = 2_000_000 * NANOS_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_NANOS: u64 = 20_000_000 * NANOS_PER_IOTA; +/// 1.5 million IOTA +pub const VALIDATOR_LOW_STAKE_THRESHOLD_NANOS: u64 = 1_500_000 * NANOS_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_NANOS: u64 = 15_000_000 * NANOS_PER_IOTA; +/// 1 million IOTA +pub const VALIDATOR_VERY_LOW_STAKE_THRESHOLD_NANOS: u64 = 1_000_000 * NANOS_PER_IOTA; /// A validator can have stake below `validator_low_stake_threshold` /// for this many epochs before being kicked out. 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..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 @@ -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; @@ -43,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, @@ -471,12 +459,12 @@ 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, 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, @@ -487,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 @@ -626,6 +591,7 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { epoch, protocol_version, system_state_version, + iota_treasury_cap, validators: ValidatorSetV1 { total_stake, @@ -663,7 +629,6 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { storage_fund, parameters: SystemParametersV1 { - stake_subsidy_start_epoch, epoch_duration_ms, max_validator_count, min_validator_joining_stake, @@ -677,15 +642,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, @@ -709,11 +665,8 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV1 { safe_mode_storage_rebates, safe_mode_non_refundable_storage_fee, epoch_start_timestamp_ms, - stake_subsidy_start_epoch, + total_iota_supply_nanos: iota_treasury_cap.total_supply.value, epoch_duration_ms, - stake_subsidy_distribution_counter, - stake_subsidy_balance: stake_subsidy_balance.value(), - stake_subsidy_current_distribution_amount, total_stake, active_validators: active_validators .into_iter() @@ -741,8 +694,6 @@ 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, } } } 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..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 @@ -15,13 +15,14 @@ use super::{ use crate::{ balance::Balance, base_types::IotaAddress, + coin::TreasuryCap, collection_types::{Bag, Table, TableVec, VecMap, VecSet}, committee::{Committee, CommitteeWithNetworkMetadata, NetworkMetadata}, error::IotaError, 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, }; @@ -32,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, @@ -69,12 +67,12 @@ 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, 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, @@ -201,6 +199,7 @@ impl IotaSystemStateTrait for IotaSystemStateInnerV2 { epoch, protocol_version, system_state_version, + iota_treasury_cap, validators: ValidatorSetV1 { total_stake, @@ -238,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, @@ -253,15 +251,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, @@ -285,11 +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, - stake_subsidy_distribution_counter, - stake_subsidy_balance: stake_subsidy_balance.value(), - stake_subsidy_current_distribution_amount, + total_iota_supply_nanos: iota_treasury_cap.total_supply.value, total_stake, active_validators: active_validators .into_iter() @@ -317,8 +303,6 @@ 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, } } } 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..4801eba0026 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_NANOS, 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. @@ -92,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")] @@ -128,29 +115,10 @@ pub struct IotaSystemStateSummary { #[serde_as(as = "Readable, _>")] pub validator_low_stake_grace_period: 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. + /// The current total supply of IOTA in nanos. #[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, + pub total_iota_supply_nanos: u64, // Validator set /// Total amount of stake from all active validators at the beginning of the @@ -353,17 +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, - 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_iota_supply_nanos: TOTAL_SUPPLY_NANOS, total_stake: 0, active_validators: vec![], pending_active_validators_id: ObjectID::ZERO, 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/crates/iota/src/genesis_inspector.rs b/crates/iota/src/genesis_inspector.rs index 5b588dfc230..6dd32457a17 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(); diff --git a/iota-execution/latest/iota-adapter/src/execution_engine.rs b/iota-execution/latest/iota-adapter/src/execution_engine.rs index 124863e97ac..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 = { @@ -716,14 +718,18 @@ 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 + .pure(params.validator_target_reward) + .expect("bcs encoding a u64 should not fail"), + storage_rewards, + computation_rewards, + ]; let call_arg_arguments = vec![ CallArg::IOTA_SYSTEM_MUT, 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()), ] @@ -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 124863e97ac..951e406bf0b 100644 --- a/iota-execution/v0/iota-adapter/src/execution_engine.rs +++ b/iota-execution/v0/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,