From 74cfb589ba6fe952e31c554d97d578364cbb534b Mon Sep 17 00:00:00 2001 From: Arad Reder Date: Thu, 19 Mar 2026 15:58:29 +0200 Subject: [PATCH] feat: add peer ids to each staker --- docs/spec.md | 64 +++- src/event_test_utils.cairo | 14 +- src/flow_test/flows.cairo | 184 +++++++++- src/flow_test/fork_test.cairo | 14 + src/flow_test/multi_version_tests.cairo | 14 + src/flow_test/test.cairo | 236 ++++++++++-- src/staking/errors.cairo | 8 + src/staking/interface.cairo | 22 +- src/staking/staking.cairo | 67 +++- src/staking/tests/pause_test.cairo | 14 +- src/staking/tests/test.cairo | 469 +++++++++++++++++++++++- src/test_utils.cairo | 5 + src/types.cairo | 1 + 13 files changed, 1054 insertions(+), 58 deletions(-) diff --git a/docs/spec.md b/docs/spec.md index 65194d26..cff5f4b9 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -59,6 +59,8 @@ - [get\_total\_stake\_for\_token](#get_total_stake_for_token) - [set\_public\_key](#set_public_key) - [get\_current\_public\_key](#get_current_public_key) + - [set\_peer\_id](#set_peer_id) + - [get\_current\_peer\_id](#get_current_peer_id) - [get\_current\_epoch\_data](#get_current_epoch_data) - [update\_rewards](#update_rewards) - [get\_stakers](#get_stakers) @@ -91,6 +93,7 @@ - [Token Enabled](#token-enabled) - [Token Disabled](#token-disabled) - [Public Key Set](#public-key-set) + - [Peer Id Set](#peer-id-set) - [Consensus Rewards First Epoch Set](#consensus-rewards-first-epoch-set) - [Pool contract](#pool-contract) - [Functions](#functions-1) @@ -1571,6 +1574,42 @@ Returns the current public key for the specified staker. Any address. #### logic +### set_peer_id +```rust +fn set_peer_id(ref self: ContractState, peer_id: PeerId) +``` +#### description +Sets the peer ID for the caller. Changes take effect after K epochs. +#### emits +1. [Peer Id Set](#peer-id-set) +#### errors +1. [CONTRACT\_IS\_PAUSED](#contract_is_paused) +2. [CALLER\_IS\_ZERO\_ADDRESS](#caller_is_zero_address) +3. [INVALID\_PEER\_ID](#invalid_peer_id) +4. [STAKER\_NOT\_EXISTS](#staker_not_exists) +5. [UNSTAKE\_IN\_PROGRESS](#unstake_in_progress) +6. [PEER\_ID\_SET\_IN\_PROGRESS](#peer_id_set_in_progress) +7. [PEER\_ID\_MUST\_DIFFER](#peer_id_must_differ) +#### pre-condition +#### access control +Only staker address. +#### logic + +### get_current_peer_id +```rust +fn get_current_peer_id(self: @ContractState, staker_address: ContractAddress) -> PeerId +``` +#### description +Returns the current peer ID for the specified staker. +#### emits +#### errors +1. [STAKER\_NOT\_EXISTS](#staker_not_exists) +2. [PEER\_ID\_NOT\_SET](#peer_id_not_set) +#### pre-condition +#### access control +Any address. +#### logic + ### get_current_epoch_data ```rust fn get_current_epoch_data(self: @ContractState) -> (Epoch, BlockNumber, u32) @@ -1614,10 +1653,10 @@ Only starkware sequencer. ### get_stakers ```rust -fn get_stakers(self: @TContractState, epoch_id: Epoch) -> Span<(ContractAddress, StakingPower, Option)> +fn get_stakers(self: @TContractState, epoch_id: Epoch) -> Span<(ContractAddress, StakingPower, Option, Option)> ``` #### description -Returns a span of (staker_address, staking_power, Option) for all stakers +Returns a span of (staker_address, staking_power, Option, Option) for all stakers for the given `epoch_id`. **Note**: The staking power is the relative weight of the staker's stake out of the total stake, including pooled stake (STRK and BTC), multiplied by @@ -1822,6 +1861,12 @@ Any address. | staker_address | address | ✅ | | public_key | [PublicKey](#publickey) | ❌ | +### Peer Id Set +| data | type | keyed | +| -------------- | -------------------- | ----- | +| staker_address | address | ✅ | +| peer_id | [PeerId](#peerid) | ❌ | + ### Consensus Rewards First Epoch Set | data | type | keyed | | ---------------------- | ------------------------ | ----- | @@ -2819,6 +2864,18 @@ Only token admin. ### PUBLIC_KEY_NOT_SET "Public key is not set" +### PEER_ID_SET_IN_PROGRESS +"Peer ID set is in progress" + +### PEER_ID_MUST_DIFFER +"Peer ID is already set to provided value" + +### INVALID_PEER_ID +"Peer ID is invalid" + +### PEER_ID_NOT_SET +"Peer ID is not set" + ### ATTEST_WITH_ZERO_BALANCE "Cannot attest with zero balance" @@ -2980,5 +3037,8 @@ Epoch: u64 ### PublicKey PublicKey: felt252 +### PeerId +PeerId: u256 + ### BlockNumber BlockNumber: u64 diff --git a/src/event_test_utils.cairo b/src/event_test_utils.cairo index 9703549d..47a80e5b 100644 --- a/src/event_test_utils.cairo +++ b/src/event_test_utils.cairo @@ -7,7 +7,7 @@ use staking::staking::interface::{ ConfigEvents as StakingConfigEvents, Events as StakingEvents, PauseEvents as StakingPauseEvents, TokenManagerEvents as StakingTokenManagerEvents, }; -use staking::types::{Amount, Commission, Epoch, Inflation, PublicKey}; +use staking::types::{Amount, Commission, Epoch, Inflation, PeerId, PublicKey}; use starknet::ContractAddress; use starkware_utils::time::time::{TimeDelta, Timestamp}; use starkware_utils_testing::test_utils::assert_expected_event_emitted; @@ -637,6 +637,18 @@ pub(crate) fn assert_public_key_set_event( ); } +pub(crate) fn assert_peer_id_set_event( + spied_event: @(ContractAddress, Event), staker_address: ContractAddress, peer_id: PeerId, +) { + let expected_event = StakingEvents::PeerIdSet { staker_address, peer_id }; + assert_expected_event_emitted( + :spied_event, + :expected_event, + expected_event_selector: @selector!("PeerIdSet"), + expected_event_name: "PeerIdSet", + ); +} + pub(crate) fn assert_consensus_rewards_first_epoch_set_event( spied_event: @(ContractAddress, Event), consensus_rewards_first_epoch: Epoch, ) { diff --git a/src/flow_test/flows.cairo b/src/flow_test/flows.cairo index 6d989fff..28ff342a 100644 --- a/src/flow_test/flows.cairo +++ b/src/flow_test/flows.cairo @@ -32,8 +32,8 @@ use staking::staking::staking::Staking::V3_PREV_CONTRACT_VERSION; use staking::staking::utils::STRK_WEIGHT_FACTOR; use staking::test_utils::constants::{ AVG_BLOCK_DURATION, BTC_18D_CONFIG, BTC_8D_CONFIG, BTC_DECIMALS_18, BTC_DECIMALS_8, - EPOCH_DURATION, PUBLIC_KEY, STRK_BASE_VALUE, TEST_BTC_DECIMALS, TEST_MIN_BTC_FOR_REWARDS, - TEST_ONE_BTC, + EPOCH_DURATION, PEER_ID, PUBLIC_KEY, STRK_BASE_VALUE, TEST_BTC_DECIMALS, + TEST_MIN_BTC_FOR_REWARDS, TEST_ONE_BTC, }; use staking::test_utils::{ advance_blocks, calculate_pool_member_rewards, calculate_staker_btc_pool_rewards_v2, @@ -7124,7 +7124,9 @@ pub(crate) impl SetPublicKeySameEpochAsUpgradeFlowImpl of FlowTrait< let result = staking_safe.get_current_public_key(staker_address: staker.staker.address); assert_panic_with_error(result, StakingError::PUBLIC_KEY_NOT_SET.describe()); let stakers = staking_consensus.get_stakers(epoch_id: staking.get_current_epoch()); - let expected_stakers = array![(staker.staker.address, STRK_WEIGHT_FACTOR, Option::None)] + let expected_stakers = array![ + (staker.staker.address, STRK_WEIGHT_FACTOR, Option::None, Option::None), + ] .span(); assert!(stakers == expected_stakers); @@ -7135,7 +7137,177 @@ pub(crate) impl SetPublicKeySameEpochAsUpgradeFlowImpl of FlowTrait< assert!(actual_public_key == public_key); let stakers = staking_consensus.get_stakers(epoch_id: staking.get_current_epoch()); let expected_stakers = array![ - (staker.staker.address, STRK_WEIGHT_FACTOR, Option::Some(public_key)), + (staker.staker.address, STRK_WEIGHT_FACTOR, Option::Some(public_key), Option::None), + ] + .span(); + assert!(stakers == expected_stakers); + } +} + +/// Flow: +/// Stake +/// Upgrade +/// Attempt to get peer id +/// Catch PEER_ID_NOT_SET +#[derive(Drop, Copy)] +pub(crate) struct GetPeerIdAfterUpgradeFlow { + pub(crate) staker: Option, +} +pub(crate) impl GetPeerIdAfterUpgradeFlowImpl of FlowTrait { + fn setup(ref self: GetPeerIdAfterUpgradeFlow, ref system: SystemState) { + let amount = system.staking.get_min_stake(); + let staker = system.new_staker(:amount); + let commission = 200; + system.stake(:staker, :amount, pool_enabled: false, :commission); + + system.set_staker_for_migration(staker_address: staker.staker.address); + self.staker = Option::Some(staker); + } + + #[feature("safe_dispatcher")] + fn test(self: GetPeerIdAfterUpgradeFlow, ref system: SystemState) { + let staker = self.staker.unwrap(); + let staker_address = staker.staker.address; + let result = system.staking.safe_dispatcher().get_current_peer_id(:staker_address); + assert_panic_with_error(result, StakingError::PEER_ID_NOT_SET.describe()); + } +} + +/// Flow: +/// Stake +/// Exit +/// Upgrade +/// Attempt to set peer id +#[derive(Drop, Copy)] +pub(crate) struct ExitUpgradeSetPeerIdFlow { + pub(crate) staker: Option, +} +pub(crate) impl ExitUpgradeSetPeerIdFlowImpl of MultiVersionFlowTrait { + fn versions(self: ExitUpgradeSetPeerIdFlow) -> Span { + [V0, V1, V2].span() + } + + fn setup(ref self: ExitUpgradeSetPeerIdFlow, ref system: SystemState, version: ReleaseVersion) { + let amount = system.staking.get_min_stake(); + let staker = system.new_staker(:amount); + let commission = 200; + system.stake(:staker, :amount, pool_enabled: true, :commission); + system.staker_exit_intent(:staker); + system.advance_exit_wait_window(); + system.staker_exit_action(:staker); + + self.staker = Option::Some(staker); + } + + #[feature("safe_dispatcher")] + fn test(self: ExitUpgradeSetPeerIdFlow, ref system: SystemState, version: ReleaseVersion) { + let staker = self.staker.unwrap(); + let peer_id = PEER_ID; + + cheat_caller_address_once( + contract_address: system.staking.address, caller_address: staker.staker.address, + ); + let result = system.staking.safe_dispatcher().set_peer_id(:peer_id); + assert_panic_with_error(result, StakingError::STAKER_NOT_EXISTS.describe()); + } +} + +/// Flow: +/// Stake +/// Exit intent +/// Upgrade +/// Attempt to set peer id +#[derive(Drop, Copy)] +pub(crate) struct IntentUpgradeSetPeerIdFlow { + pub(crate) staker: Option, +} +pub(crate) impl IntentUpgradeSetPeerIdFlowImpl of MultiVersionFlowTrait< + IntentUpgradeSetPeerIdFlow, +> { + fn versions(self: IntentUpgradeSetPeerIdFlow) -> Span { + [V0, V1, V2].span() + } + + fn setup( + ref self: IntentUpgradeSetPeerIdFlow, ref system: SystemState, version: ReleaseVersion, + ) { + let amount = system.staking.get_min_stake(); + let staker = system.new_staker(:amount); + let commission = 200; + system.stake(:staker, :amount, pool_enabled: false, :commission); + system.staker_exit_intent(:staker); + + system.set_staker_for_migration(staker_address: staker.staker.address); + self.staker = Option::Some(staker); + } + + #[feature("safe_dispatcher")] + fn test(self: IntentUpgradeSetPeerIdFlow, ref system: SystemState, version: ReleaseVersion) { + let staker = self.staker.unwrap(); + let peer_id = PEER_ID; + + cheat_caller_address_once( + contract_address: system.staking.address, caller_address: staker.staker.address, + ); + let result = system.staking.safe_dispatcher().set_peer_id(:peer_id); + assert_panic_with_error(result, StakingError::UNSTAKE_IN_PROGRESS.describe()); + } +} + +/// Flow: +/// Stake +/// Upgrade +/// Set peer id (same epoch as upgrade) +/// Test get_peer_id and get_stakers (still same epoch) +/// Advance K epochs +/// Test get_peer_id and get_stakers +#[derive(Drop, Copy)] +pub(crate) struct SetPeerIdSameEpochAsUpgradeFlow { + pub(crate) staker: Option, +} +pub(crate) impl SetPeerIdSameEpochAsUpgradeFlowImpl of FlowTrait { + fn setup_v2(ref self: SetPeerIdSameEpochAsUpgradeFlow, ref system: SystemState) { + let amount = system.staking.get_min_stake(); + let staker = system.new_staker(:amount); + let commission = 200; + system.stake(:staker, :amount, pool_enabled: false, :commission); + system.advance_epoch(); + + system.set_staker_for_migration(staker_address: staker.staker.address); + self.staker = Option::Some(staker); + } + + #[feature("safe_dispatcher")] + fn test(self: SetPeerIdSameEpochAsUpgradeFlow, ref system: SystemState) { + let staker = self.staker.unwrap(); + let staking = system.staking.dispatcher(); + let staking_safe = system.staking.safe_dispatcher(); + let staking_consensus = system.staking.consensus_dispatcher(); + let peer_id = PEER_ID; + + // Set peer id. + cheat_caller_address_once( + contract_address: system.staking.address, caller_address: staker.staker.address, + ); + staking.set_peer_id(:peer_id); + + // Test get_peer_id and get_stakers same epoch. + let result = staking_safe.get_current_peer_id(staker_address: staker.staker.address); + assert_panic_with_error(result, StakingError::PEER_ID_NOT_SET.describe()); + let stakers = staking_consensus.get_stakers(epoch_id: staking.get_current_epoch()); + let expected_stakers = array![ + (staker.staker.address, STRK_WEIGHT_FACTOR, Option::None, Option::None), + ] + .span(); + assert!(stakers == expected_stakers); + + // Test get_peer_id and get_stakers after K epochs. + system.advance_k_epochs(); + let actual_peer_id = staking.get_current_peer_id(staker_address: staker.staker.address); + assert!(actual_peer_id == peer_id); + let stakers = staking_consensus.get_stakers(epoch_id: staking.get_current_epoch()); + let expected_stakers = array![ + (staker.staker.address, STRK_WEIGHT_FACTOR, Option::None, Option::Some(peer_id)), ] .span(); assert!(stakers == expected_stakers); @@ -7179,7 +7351,9 @@ pub(crate) impl GetStakersAfterUpgradeFlowImpl of FlowTrait { Error::PUBLIC_KEY_MUST_DIFFER => "Public key is already set to provided value", Error::INVALID_PUBLIC_KEY => "Public key is invalid", Error::PUBLIC_KEY_NOT_SET => "Public key is not set", + Error::PEER_ID_SET_IN_PROGRESS => "Peer ID set is in progress", + Error::PEER_ID_MUST_DIFFER => "Peer ID is already set to provided value", + Error::INVALID_PEER_ID => "Peer ID is invalid", + Error::PEER_ID_NOT_SET => "Peer ID is not set", Error::ATTEST_WITH_ZERO_BALANCE => "Cannot attest with zero balance", Error::REWARDS_ALREADY_UPDATED => "Rewards were already updated for the current block", Error::INVALID_STAKER => "Staker is invalid for getting rewards", diff --git a/src/staking/interface.cairo b/src/staking/interface.cairo index 53d2c605..ddc14588 100644 --- a/src/staking/interface.cairo +++ b/src/staking/interface.cairo @@ -2,7 +2,8 @@ use core::num::traits::Zero; use staking::staking::errors::Error; use staking::staking::objects::{AttestationInfo, EpochInfo, NormalizedAmount}; use staking::types::{ - Amount, BlockNumber, Commission, Epoch, InternalStakerInfoLatest, PublicKey, StakingPower, + Amount, BlockNumber, Commission, Epoch, InternalStakerInfoLatest, PeerId, PublicKey, + StakingPower, }; use starknet::{ClassHash, ContractAddress}; use starkware_utils::errors::OptionAuxTrait; @@ -98,14 +99,18 @@ pub trait IStaking { fn set_public_key(ref self: TContractState, public_key: PublicKey); /// Get the current public key for the given `staker_address`. fn get_current_public_key(self: @TContractState, staker_address: ContractAddress) -> PublicKey; + /// Set the peer ID for the calling staker. + fn set_peer_id(ref self: TContractState, peer_id: PeerId); + /// Get the current peer ID for the given `staker_address`. + fn get_current_peer_id(self: @TContractState, staker_address: ContractAddress) -> PeerId; } #[starknet::interface] pub trait IStakingConsensus { /// Returns (epoch_id, epoch_starting_block, epoch_length) for the current epoch. fn get_current_epoch_data(self: @TContractState) -> (Epoch, BlockNumber, u32); - /// Returns a span of (staker_address, staking_power, Option) for all stakers - /// for the given `epoch_id` (`curr_epoch <= epoch_id < curr_epoch + K`). + /// Returns a span of (staker_address, staking_power, Option, Option) + /// for all stakers for the given `epoch_id` (`curr_epoch <= epoch_id < curr_epoch + K`). /// **Note**: The staking power is the relative weight of the staker's stake /// out of the total stake, including pooled stake (STRK and BTC), multiplied by /// `STAKING_POWER_BASE_VALUE`. @@ -115,7 +120,7 @@ pub trait IStakingConsensus { /// This will occur if a new staker was added in that epoch before the upgrade. fn get_stakers( self: @TContractState, epoch_id: Epoch, - ) -> Span<(ContractAddress, StakingPower, Option)>; + ) -> Span<(ContractAddress, StakingPower, Option, Option)>; } // **Note**: This trait must be reimplemented in the next version of the contract. @@ -306,7 +311,7 @@ pub trait IStakingRewardsManager { } pub mod Events { - use staking::types::{Amount, Commission, Epoch, PublicKey}; + use staking::types::{Amount, Commission, Epoch, PeerId, PublicKey}; use starknet::ContractAddress; use starkware_utils::time::time::Timestamp; #[derive(Debug, Drop, PartialEq, starknet::Event)] @@ -478,6 +483,13 @@ pub mod Events { pub staker_address: ContractAddress, pub public_key: PublicKey, } + + #[derive(Debug, Drop, PartialEq, starknet::Event)] + pub struct PeerIdSet { + #[key] + pub staker_address: ContractAddress, + pub peer_id: PeerId, + } } pub mod PauseEvents { diff --git a/src/staking/staking.cairo b/src/staking/staking.cairo index e0a16efb..ad0b1a73 100644 --- a/src/staking/staking.cairo +++ b/src/staking/staking.cairo @@ -40,8 +40,8 @@ pub mod Staking { strk_token_dispatcher, }; use staking::types::{ - Amount, BlockNumber, Commission, Epoch, InternalStakerInfoLatest, PublicKey, StakingPower, - Version, + Amount, BlockNumber, Commission, Epoch, InternalStakerInfoLatest, PeerId, PublicKey, + StakingPower, Version, }; use starknet::class_hash::ClassHash; use starknet::storage::{ @@ -174,6 +174,11 @@ pub mod Staking { /// which the `new_public_key` is valid. Up until `activation_epoch`, the /// `old_public_key` is valid. public_key: Map, + /// Map staker address to (activation_epoch, old_peer_id, new_peer_id). + /// Similarly to `public_key`, the `activation_epoch` is the first epoch from + /// which the `new_peer_id` is valid. Up until `activation_epoch`, the + /// `old_peer_id` is valid. + peer_id: Map, /// Map staker address to the epoch when the unstake intent takes effect. /// **Note**: Stakers that called `unstake_intent` before V3 will not have this record. // TODO: Consider view function. @@ -234,6 +239,7 @@ pub mod Staking { TokenEnabled: TokenManagerEvents::TokenEnabled, TokenDisabled: TokenManagerEvents::TokenDisabled, PublicKeySet: Events::PublicKeySet, + PeerIdSet: Events::PeerIdSet, } #[constructor] @@ -854,6 +860,31 @@ pub mod Staking { .get_public_key_at_epoch(:staker_address, epoch_id: self.get_current_epoch()) .expect_with_err(Error::PUBLIC_KEY_NOT_SET) } + + fn set_peer_id(ref self: ContractState, peer_id: PeerId) { + self.general_prerequisites(); + assert!(peer_id.is_non_zero(), "{}", Error::INVALID_PEER_ID); + let staker_address = get_caller_address(); + let staker_info = self.internal_staker_info(:staker_address); + assert!(staker_info.unstake_time.is_none(), "{}", Error::UNSTAKE_IN_PROGRESS); + + let (curr_activation_epoch, _, prev_peer_id) = self.peer_id.read(staker_address); + let curr_epoch = self.get_current_epoch(); + assert!(curr_epoch >= curr_activation_epoch, "{}", Error::PEER_ID_SET_IN_PROGRESS); + assert!(prev_peer_id != peer_id, "{}", Error::PEER_ID_MUST_DIFFER); + + let new_activation_epoch = self.get_epoch_plus_k(); + self.peer_id.write(staker_address, (new_activation_epoch, prev_peer_id, peer_id)); + self.emit(Events::PeerIdSet { staker_address, peer_id }); + } + + fn get_current_peer_id(self: @ContractState, staker_address: ContractAddress) -> PeerId { + // Assert the staker exists. + self.internal_staker_info(:staker_address); + self + .get_peer_id_at_epoch(:staker_address, epoch_id: self.get_current_epoch()) + .expect_with_err(Error::PEER_ID_NOT_SET) + } } #[abi(embed_v0)] @@ -869,7 +900,7 @@ pub mod Staking { fn get_stakers( self: @ContractState, epoch_id: Epoch, - ) -> Span<(ContractAddress, StakingPower, Option)> { + ) -> Span<(ContractAddress, StakingPower, Option, Option)> { let curr_epoch = self.get_current_epoch(); assert!( curr_epoch <= epoch_id && epoch_id < curr_epoch + K.into(), @@ -880,7 +911,10 @@ pub mod Staking { let (strk_total_stake, btc_total_stake) = self .get_total_staking_power_at_epoch(:epoch_id); - let mut stakers: Array<(ContractAddress, StakingPower, Option)> = array![]; + let mut stakers: Array< + (ContractAddress, StakingPower, Option, Option), + > = + array![]; for staker_address_ptr in self.stakers.into_iter_full_range() { let staker_address = staker_address_ptr.read(); if !self.is_staker_active(:staker_address, :epoch_id) { @@ -896,7 +930,8 @@ pub mod Staking { } let public_key = self.get_public_key_at_epoch(:staker_address, :epoch_id); - stakers.append((staker_address, staking_power, public_key)); + let peer_id = self.get_peer_id_at_epoch(:staker_address, :epoch_id); + stakers.append((staker_address, staking_power, public_key, peer_id)); } stakers.span() } @@ -2232,6 +2267,28 @@ pub mod Staking { } } + /// Returns the peer ID for `staker_address` at `epoch_id`, + /// or `None` if the peer ID is not set. + /// + /// Preconditions: + /// 1. The staker exists. + /// 2. `get_current_epoch() <= epoch_id < get_current_epoch() + K`. + fn get_peer_id_at_epoch( + self: @ContractState, staker_address: ContractAddress, epoch_id: Epoch, + ) -> Option { + let (activation_epoch, old_pid, new_pid) = self.peer_id.read(staker_address); + let current_pid = if epoch_id >= activation_epoch { + new_pid + } else { + old_pid + }; + if current_pid.is_non_zero() { + Some(current_pid) + } else { + None + } + } + /// Calculates rewards for the given staker and his pools, updates the staker's /// `unclaimed_rewards`, and updates and transfers rewards to the pools. /// diff --git a/src/staking/tests/pause_test.cairo b/src/staking/tests/pause_test.cairo index 6683bcfb..6e5d5251 100644 --- a/src/staking/tests/pause_test.cairo +++ b/src/staking/tests/pause_test.cairo @@ -9,7 +9,7 @@ use staking::staking::interface::{ IStakingRewardsManagerDispatcherTrait, }; use staking::test_utils::constants::{ - DUMMY_ADDRESS, DUMMY_IDENTIFIER, NON_SECURITY_ADMIN, NON_SECURITY_AGENT, + DUMMY_ADDRESS, DUMMY_IDENTIFIER, NON_SECURITY_ADMIN, NON_SECURITY_AGENT, PEER_ID, }; use staking::test_utils::{ StakingInitConfig, general_contract_system_deployment, load_one_felt, pause_staking_contract, @@ -336,6 +336,18 @@ fn test_set_public_key_when_paused() { staking_dispatcher.set_public_key(public_key: cfg.test_info.public_key); } +#[test] +#[should_panic(expected: "Contract is paused")] +fn test_set_peer_id_when_paused() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + pause_staking_contract(:cfg); + let staking_dispatcher = IStakingDispatcher { + contract_address: cfg.test_info.staking_contract, + }; + staking_dispatcher.set_peer_id(peer_id: PEER_ID); +} + #[test] #[should_panic(expected: "Contract is paused")] fn test_update_rewards_when_paused() { diff --git a/src/staking/tests/test.cairo b/src/staking/tests/test.cairo index d602d099..ee90aac0 100644 --- a/src/staking/tests/test.cairo +++ b/src/staking/tests/test.cairo @@ -5,8 +5,9 @@ use Staking::{ use constants::{ BTC_STAKER_ADDRESS, BTC_TOKEN_ADDRESS, BTC_TOKEN_NAME, BTC_TOKEN_NAME_2, CALLER_ADDRESS, DUMMY_ADDRESS, DUMMY_IDENTIFIER, EPOCH_DURATION, EPOCH_LENGTH, EPOCH_STARTING_BLOCK, - NON_APP_GOVERNOR, NON_STAKER_ADDRESS, NON_TOKEN_ADMIN, OTHER_OPERATIONAL_ADDRESS, - OTHER_REWARD_ADDRESS, OTHER_REWARD_SUPPLIER_CONTRACT_ADDRESS, OTHER_STAKER_ADDRESS, UNPOOL_TIME, + NON_APP_GOVERNOR, NON_STAKER_ADDRESS, NON_TOKEN_ADMIN, OTHER_OPERATIONAL_ADDRESS, OTHER_PEER_ID, + OTHER_REWARD_ADDRESS, OTHER_REWARD_SUPPLIER_CONTRACT_ADDRESS, OTHER_STAKER_ADDRESS, PEER_ID, + UNPOOL_TIME, }; use core::num::traits::Zero; use core::option::OptionTrait; @@ -17,7 +18,8 @@ use event_test_utils::{ assert_declare_operational_address_event, assert_delete_staker_event, assert_epoch_info_changed_event, assert_exit_wait_window_changed_event, assert_minimum_stake_changed_event, assert_new_delegation_pool_event, assert_new_staker_event, - assert_public_key_set_event, assert_remove_from_delegation_pool_action_event, + assert_peer_id_set_event, assert_public_key_set_event, + assert_remove_from_delegation_pool_action_event, assert_remove_from_delegation_pool_intent_event, assert_reward_supplier_changed_event, assert_rewards_supplied_to_delegation_pool_event, assert_stake_delegated_balance_changed_event, assert_stake_own_balance_changed_event, assert_staker_exit_intent_event, @@ -5917,7 +5919,9 @@ fn test_get_stakers() { assert!(stakers.len() == 0); let stakers = staking_consensus_dispatcher.get_stakers(epoch_id: epoch_id + 1); - let expected_stakers = array![(staker_address, STRK_WEIGHT_FACTOR, Option::Some(public_key))] + let expected_stakers = array![ + (staker_address, STRK_WEIGHT_FACTOR, Option::Some(public_key), Option::None), + ] .span(); assert!(stakers == expected_stakers); @@ -5949,7 +5953,8 @@ fn test_get_stakers_before_after_set_public_key() { let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); // TODO: Consider testing with staker amount when the view function is implemented. let (strk_staking_power, _) = staking_dispatcher.get_current_total_staking_power(); - let expected_stakers = array![(staker_address, STRK_WEIGHT_FACTOR, Option::None)].span(); + let expected_stakers = array![(staker_address, STRK_WEIGHT_FACTOR, Option::None, Option::None)] + .span(); assert!(stakers == expected_stakers); assert!(strk_staking_power == NormalizedAmountTrait::from_strk_native_amount(stake_amount)); @@ -5969,7 +5974,9 @@ fn test_get_stakers_before_after_set_public_key() { advance_epoch_global(); let epoch_id = staking_dispatcher.get_current_epoch(); let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); - let expected_stakers = array![(staker_address, STRK_WEIGHT_FACTOR, Option::Some(public_key))] + let expected_stakers = array![ + (staker_address, STRK_WEIGHT_FACTOR, Option::Some(public_key), Option::None), + ] .span(); assert!(stakers == expected_stakers); } @@ -6052,3 +6059,453 @@ fn test_get_stakers_invalid_epoch() { let result = staking_consensus_safe_dispatcher.get_stakers(epoch_id: epoch_id + 2); assert_panic_with_error(:result, expected_error: Error::INVALID_EPOCH.describe()); } + +#[test] +fn test_set_peer_id() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staker_address = cfg.test_info.staker_address; + let peer_id: u256 = PEER_ID; + stake_for_testing_using_dispatcher(:cfg); + let mut spy = snforge_std::spy_events(); + + // Set and test. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(:peer_id); + advance_k_epochs_global(); + let returned_peer_id = staking_dispatcher.get_current_peer_id(:staker_address); + assert!(returned_peer_id == peer_id); + + // Test event. + let events = spy.get_events().emitted_by(staking_contract).events; + assert_number_of_events(actual: events.len(), expected: 1, message: "set_peer_id"); + assert_peer_id_set_event(spied_event: events[0], :staker_address, :peer_id); +} + +#[test] +#[should_panic(expected: "Peer ID is not set")] +fn test_get_current_peer_id_before_set() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staker_address = cfg.test_info.staker_address; + stake_for_testing_using_dispatcher(:cfg); + staking_dispatcher.get_current_peer_id(:staker_address); +} + +#[test] +#[feature("safe_dispatcher")] +fn test_get_current_peer_id() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staking_safe_dispatcher = IStakingSafeDispatcher { contract_address: staking_contract }; + let staker_address = cfg.test_info.staker_address; + let peer_id_1: u256 = PEER_ID; + let peer_id_2: u256 = OTHER_PEER_ID; + stake_for_testing_using_dispatcher(:cfg); + + // Set peer id. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(peer_id: peer_id_1); + + // Test same epoch. + let result = staking_safe_dispatcher.get_current_peer_id(:staker_address); + assert_panic_with_error(:result, expected_error: Error::PEER_ID_NOT_SET.describe()); + + // Test next epoch. + advance_epoch_global(); + let result = staking_safe_dispatcher.get_current_peer_id(:staker_address); + assert_panic_with_error(:result, expected_error: Error::PEER_ID_NOT_SET.describe()); + + // Test next next epoch. + advance_epoch_global(); + let returned_peer_id = staking_dispatcher.get_current_peer_id(:staker_address); + assert!(returned_peer_id == peer_id_1); + + // Change peer id. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(peer_id: peer_id_2); + + // Test same epoch. + let returned_peer_id = staking_dispatcher.get_current_peer_id(:staker_address); + assert!(returned_peer_id == peer_id_1); + + // Test next epoch. + advance_epoch_global(); + let returned_peer_id = staking_dispatcher.get_current_peer_id(:staker_address); + assert!(returned_peer_id == peer_id_1); + + // Test next next epoch. + advance_epoch_global(); + let returned_peer_id = staking_dispatcher.get_current_peer_id(:staker_address); + assert!(returned_peer_id == peer_id_2); +} + +#[test] +#[should_panic(expected: "Peer ID is invalid")] +fn test_set_peer_id_invalid_peer_id() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staker_address = cfg.test_info.staker_address; + let peer_id: u256 = Zero::zero(); + + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(:peer_id); +} + +#[test] +#[should_panic(expected: "Staker does not exist")] +fn test_set_peer_id_staker_does_not_exist() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let peer_id: u256 = PEER_ID; + + staking_dispatcher.set_peer_id(:peer_id); +} + +#[test] +#[feature("safe_dispatcher")] +fn test_set_peer_id_while_peer_id_set_in_progress() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staking_safe_dispatcher = IStakingSafeDispatcher { contract_address: staking_contract }; + let staker_address = cfg.test_info.staker_address; + let peer_id_1: u256 = PEER_ID; + let peer_id_2: u256 = OTHER_PEER_ID; + + stake_for_testing_using_dispatcher(:cfg); + cheat_caller_address( + contract_address: staking_contract, + caller_address: staker_address, + span: CheatSpan::TargetCalls(4), + ); + staking_dispatcher.set_peer_id(peer_id: peer_id_1); + let result = staking_safe_dispatcher.set_peer_id(peer_id: peer_id_2); + assert_panic_with_error(:result, expected_error: Error::PEER_ID_SET_IN_PROGRESS.describe()); + + advance_epoch_global(); + let result = staking_safe_dispatcher.set_peer_id(peer_id: peer_id_2); + assert_panic_with_error(:result, expected_error: Error::PEER_ID_SET_IN_PROGRESS.describe()); + + advance_epoch_global(); + staking_dispatcher.set_peer_id(peer_id: peer_id_2); + advance_k_epochs_global(); + let returned_peer_id = staking_dispatcher.get_current_peer_id(:staker_address); + assert!(returned_peer_id == peer_id_2); +} + +#[test] +#[should_panic(expected: "Peer ID is already set to provided value")] +fn test_set_peer_id_same_peer_id() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staker_address = cfg.test_info.staker_address; + let peer_id: u256 = PEER_ID; + + stake_for_testing_using_dispatcher(:cfg); + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(:peer_id); + + advance_k_epochs_global(); + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(:peer_id); +} + +#[test] +#[feature("safe_dispatcher")] +fn test_set_peer_id_while_unstake_in_progress() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staking_safe_dispatcher = IStakingSafeDispatcher { contract_address: staking_contract }; + let staker_address = cfg.test_info.staker_address; + let peer_id: u256 = PEER_ID; + stake_for_testing_using_dispatcher(:cfg); + + cheat_caller_address( + contract_address: staking_contract, + caller_address: staker_address, + span: CheatSpan::TargetCalls(3), + ); + let unstake_time = staking_dispatcher.unstake_intent(); + + // Test before unstake window ends. + let result = staking_safe_dispatcher.set_peer_id(:peer_id); + assert_panic_with_error(:result, expected_error: Error::UNSTAKE_IN_PROGRESS.describe()); + + // Test after unstake window ends. + start_cheat_block_timestamp_global( + block_timestamp: unstake_time.add(delta: Time::seconds(count: 1)).into(), + ); + let result = staking_safe_dispatcher.set_peer_id(:peer_id); + assert_panic_with_error(:result, expected_error: Error::UNSTAKE_IN_PROGRESS.describe()); +} + +#[test] +#[should_panic(expected: "Staker does not exist")] +fn test_set_peer_id_staker_left() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staker_address = cfg.test_info.staker_address; + let peer_id: u256 = PEER_ID; + stake_for_testing_using_dispatcher(:cfg); + + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + let unstake_time = staking_dispatcher.unstake_intent(); + start_cheat_block_timestamp_global( + block_timestamp: unstake_time.add(delta: Time::seconds(count: 1)).into(), + ); + staking_dispatcher.unstake_action(:staker_address); + + staking_dispatcher.set_peer_id(:peer_id); +} + +#[test] +#[should_panic(expected: "Staker does not exist")] +fn test_get_current_peer_id_staker_does_not_exist() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + staking_dispatcher.get_current_peer_id(staker_address: cfg.test_info.staker_address); +} + +#[test] +fn test_get_stakers_before_after_set_peer_id() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staking_consensus_dispatcher = IStakingConsensusDispatcher { + contract_address: staking_contract, + }; + let staker_address = cfg.test_info.staker_address; + let stake_amount = cfg.test_info.stake_amount; + let peer_id: u256 = PEER_ID; + stake_for_testing_using_dispatcher(:cfg); + + advance_k_epochs_global(); + let epoch_id = staking_dispatcher.get_current_epoch(); + + // Test before peer id is set. + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + let (strk_staking_power, _) = staking_dispatcher.get_current_total_staking_power(); + let expected_stakers = array![(staker_address, STRK_WEIGHT_FACTOR, Option::None, Option::None)] + .span(); + assert!(stakers == expected_stakers); + assert!(strk_staking_power == NormalizedAmountTrait::from_strk_native_amount(stake_amount)); + + // Set peer id. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(:peer_id); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + assert!(stakers == expected_stakers); + + // Advance epoch. + advance_epoch_global(); + let epoch_id = staking_dispatcher.get_current_epoch(); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + assert!(stakers == expected_stakers); + + // Advance epoch. + advance_epoch_global(); + let epoch_id = staking_dispatcher.get_current_epoch(); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + let expected_stakers = array![ + (staker_address, STRK_WEIGHT_FACTOR, Option::None, Option::Some(peer_id)), + ] + .span(); + assert!(stakers == expected_stakers); +} + +#[test] +fn test_get_stakers_with_public_key_and_peer_id() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staking_consensus_dispatcher = IStakingConsensusDispatcher { + contract_address: staking_contract, + }; + let staker_address = cfg.test_info.staker_address; + let public_key = cfg.test_info.public_key; + let peer_id: u256 = PEER_ID; + stake_for_testing_using_dispatcher(:cfg); + + // Advance K epochs so staker has staking power. + advance_k_epochs_global(); + + // Set both public key and peer id in the same epoch. + cheat_caller_address( + contract_address: staking_contract, + caller_address: staker_address, + span: CheatSpan::TargetCalls(2), + ); + staking_dispatcher.set_public_key(:public_key); + staking_dispatcher.set_peer_id(:peer_id); + + // Before activation: staker is active but neither key/id is set yet. + let epoch_id = staking_dispatcher.get_current_epoch(); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + let expected_stakers = array![(staker_address, STRK_WEIGHT_FACTOR, Option::None, Option::None)] + .span(); + assert!(stakers == expected_stakers); + + // After K epochs: both are set. + advance_k_epochs_global(); + let epoch_id = staking_dispatcher.get_current_epoch(); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + let expected_stakers = array![ + (staker_address, STRK_WEIGHT_FACTOR, Option::Some(public_key), Option::Some(peer_id)), + ] + .span(); + assert!(stakers == expected_stakers); +} + +#[test] +fn test_get_stakers_with_only_public_key_no_peer_id() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staking_consensus_dispatcher = IStakingConsensusDispatcher { + contract_address: staking_contract, + }; + let staker_address = cfg.test_info.staker_address; + let public_key = cfg.test_info.public_key; + stake_for_testing_using_dispatcher(:cfg); + + // Set only public key, no peer id. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_public_key(:public_key); + + advance_k_epochs_global(); + let epoch_id = staking_dispatcher.get_current_epoch(); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + let expected_stakers = array![ + (staker_address, STRK_WEIGHT_FACTOR, Option::Some(public_key), Option::None), + ] + .span(); + assert!(stakers == expected_stakers); +} + +#[test] +fn test_get_stakers_with_only_peer_id_no_public_key() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staking_consensus_dispatcher = IStakingConsensusDispatcher { + contract_address: staking_contract, + }; + let staker_address = cfg.test_info.staker_address; + let peer_id: u256 = PEER_ID; + stake_for_testing_using_dispatcher(:cfg); + + // Set only peer id, no public key. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(:peer_id); + + advance_k_epochs_global(); + let epoch_id = staking_dispatcher.get_current_epoch(); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + let expected_stakers = array![ + (staker_address, STRK_WEIGHT_FACTOR, Option::None, Option::Some(peer_id)), + ] + .span(); + assert!(stakers == expected_stakers); +} + +#[test] +fn test_get_stakers_set_public_key_then_peer_id_different_epochs() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staking_consensus_dispatcher = IStakingConsensusDispatcher { + contract_address: staking_contract, + }; + let staker_address = cfg.test_info.staker_address; + let public_key = cfg.test_info.public_key; + let peer_id: u256 = PEER_ID; + stake_for_testing_using_dispatcher(:cfg); + + // Set public key first. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_public_key(:public_key); + + // Advance K epochs so public key is active. + advance_k_epochs_global(); + let epoch_id = staking_dispatcher.get_current_epoch(); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + let expected_stakers = array![ + (staker_address, STRK_WEIGHT_FACTOR, Option::Some(public_key), Option::None), + ] + .span(); + assert!(stakers == expected_stakers); + + // Now set peer id. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(:peer_id); + + // Peer id not yet active, public key still active. + let epoch_id = staking_dispatcher.get_current_epoch(); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + assert!(stakers == expected_stakers); + + // Advance K epochs so peer id is also active. + advance_k_epochs_global(); + let epoch_id = staking_dispatcher.get_current_epoch(); + let stakers = staking_consensus_dispatcher.get_stakers(:epoch_id); + let expected_stakers = array![ + (staker_address, STRK_WEIGHT_FACTOR, Option::Some(public_key), Option::Some(peer_id)), + ] + .span(); + assert!(stakers == expected_stakers); +} + +#[test] +fn test_set_peer_id_cycle_back_to_original() { + let mut cfg: StakingInitConfig = Default::default(); + general_contract_system_deployment(ref :cfg); + let staking_contract = cfg.test_info.staking_contract; + let staking_dispatcher = IStakingDispatcher { contract_address: staking_contract }; + let staker_address = cfg.test_info.staker_address; + let peer_id_a: u256 = PEER_ID; + let peer_id_b: u256 = OTHER_PEER_ID; + stake_for_testing_using_dispatcher(:cfg); + + // Set peer_id to A. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(peer_id: peer_id_a); + advance_k_epochs_global(); + assert!(staking_dispatcher.get_current_peer_id(:staker_address) == peer_id_a); + + // Change to B. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(peer_id: peer_id_b); + advance_k_epochs_global(); + assert!(staking_dispatcher.get_current_peer_id(:staker_address) == peer_id_b); + + // Cycle back to A. + cheat_caller_address_once(contract_address: staking_contract, caller_address: staker_address); + staking_dispatcher.set_peer_id(peer_id: peer_id_a); + advance_k_epochs_global(); + assert!(staking_dispatcher.get_current_peer_id(:staker_address) == peer_id_a); +} diff --git a/src/test_utils.cairo b/src/test_utils.cairo index c70d58ad..124fdbfc 100644 --- a/src/test_utils.cairo +++ b/src/test_utils.cairo @@ -83,6 +83,7 @@ pub(crate) mod constants { use staking::types::{Amount, BlockNumber, Commission, Index, Inflation, PublicKey}; use starknet::class_hash::ClassHash; use starknet::{ContractAddress, get_block_number}; + use starkware_utils::constants::MAX_U128; use starkware_utils::time::time::{Seconds, Timestamp}; /// STRK rewards constants. @@ -213,6 +214,10 @@ pub(crate) mod constants { .unwrap(); pub(crate) const BTC_TOKEN_ADDRESS: ContractAddress = 'BTC_TOKEN_ADDRESS'.try_into().unwrap(); pub(crate) const PUBLIC_KEY: PublicKey = 'PUBLIC_KEY'; + // Peer ID constants use values > u128::MAX to ensure full u256 storage is exercised. + pub(crate) const PEER_ID: u256 = MAX_U128.into() + 1; + pub(crate) const OTHER_PEER_ID: u256 = 2 * PEER_ID + 1; + pub(crate) const THIRD_PEER_ID: u256 = 2 * OTHER_PEER_ID + 1; pub fn DEFAULT_EPOCH_INFO() -> EpochInfo { EpochInfoTrait::new( diff --git a/src/types.cairo b/src/types.cairo index 5750fc57..7f09269e 100644 --- a/src/types.cairo +++ b/src/types.cairo @@ -10,6 +10,7 @@ pub type Epoch = u64; pub type Version = felt252; pub type VecIndex = u64; pub type PublicKey = felt252; +pub type PeerId = u256; pub type BlockNumber = u64; pub type StakingPower = u128;