Skip to content

Conversation

@ipapandinas
Copy link
Contributor

@ipapandinas ipapandinas commented Dec 5, 2025

Pull Request Summary

When a staker claims rewards for a finished period, the ledger's claim_up_to_era function zeros out the staked and staked_future fields once the period end is reached. However, the corresponding StakerInfo entries remain in storage and the ledger's contract_stake_count is never decremented. The next time the user restakes on the same contract (or when the cleanup extrinsic tries to reconcile counts), the pallet treats it as a new entry and bumps contract_stake_count again. Over time, the counter grows out of sync with the actual number of StakerInfo entries and may eventually block further stakes because the ledger appears to have reached MaxNumberOfStakedContracts, even though storage contains far fewer entries.

This PR fixes this bug by syncing the contract_stake_count to the remaining valid entries during a cleanup_expired_entries. A new test scenario ensures the expected behavior.

Check list**

  • added or updated unit tests

@ipapandinas ipapandinas added shiden related to shiden runtime dapps-staking Dapps Staking astar Related to Astar shibuya related to shibuya runtime This PR/Issue is related to the topic “runtime”. labels Dec 5, 2025
@ipapandinas ipapandinas requested a review from Dinonard December 5, 2025 15:46
Copy link
Contributor

@Dinonard Dinonard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work.

The approach with the cleanup during reward claiming is hacky and very inefficient. Also, what if user locks himself out from being able to stake anything - they won't be able to claim any rewards, and thus will remain locked out.

The fix should address claim calls where ledger isn't updated when contract stake entry is removed - or just identify if contract take entry should have been removed but wasn't.

The cleanup extrinsic can also be modified as suggested in the comments. Ideally, we can just use it to do the cleanup.


// Remove expired stake entries from the ledger.
let mut ledger = Ledger::<T>::get(&account);
ledger
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps you should change this to set the stake account to the number of entries that haven't been cleaned up. This should implicitly help cleanup the current mess.


// Find all entries which are from past periods & don't have claimable bonus rewards.
// This is bounded by max allowed number of stake entries per account.
let to_be_deleted: Vec<T::SmartContract> = StakerInfo::<T>::iter_prefix(&account)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remind me why doesn't this function properly cleanup faulty entries?

If it does, please check my next comment.

T::StakingRewardHandler::payout_reward(&account, reward_sum)
.map_err(|_| Error::<T>::RewardPayoutFailed)?;

let stale_contracts: Vec<T::SmartContract> = StakerInfo::<T>::iter_prefix(&account)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should reward claiming extrinsic be responsible for cleaning up everything?

@ipapandinas
Copy link
Contributor Author

@Dinonard I misunderstood the issue, now it should be properly fixed using the cleanup extrinsic as you suggested.

@github-actions
Copy link

github-actions bot commented Dec 5, 2025

Code Coverage

Package Line Rate Branch Rate Health
precompiles/dapp-staking/src/test 0% 0%
pallets/collator-selection/src 88% 0%
pallets/collective-proxy/src 94% 0%
primitives/src 53% 0%
precompiles/dispatch-lockdrop/src 83% 0%
chain-extensions/unified-accounts/src 0% 0%
pallets/dapp-staking/src/test 0% 0%
pallets/astar-xcm-benchmarks/src 86% 0%
pallets/inflation/src 58% 0%
pallets/astar-xcm-benchmarks/src/generic 100% 0%
primitives/src/xcm 60% 0%
pallets/ethereum-checked/src 76% 0%
pallets/xc-asset-config/src 64% 0%
precompiles/sr25519/src 56% 0%
pallets/dapp-staking/src 80% 0%
chain-extensions/types/unified-accounts/src 0% 0%
chain-extensions/pallet-assets/src 54% 0%
pallets/vesting-mbm/src 87% 0%
pallets/dapp-staking/src/benchmarking 95% 0%
precompiles/unified-accounts/src 100% 0%
pallets/astar-xcm-benchmarks/src/fungible 100% 0%
pallets/unified-accounts/src 80% 0%
pallets/democracy-mbm/src 30% 0%
precompiles/assets-erc20/src 77% 0%
chain-extensions/types/assets/src 0% 0%
precompiles/xcm/src 69% 0%
pallets/static-price-provider/src 91% 0%
precompiles/substrate-ecdsa/src 67% 0%
pallets/price-aggregator/src 75% 0%
pallets/dapp-staking/rpc/runtime-api/src 0% 0%
precompiles/dapp-staking/src 89% 0%
pallets/dynamic-evm-base-fee/src 84% 0%
Summary 73% (3891 / 5347) 0% (0 / 0)

Minimum allowed line rate is 50%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

astar Related to Astar dapps-staking Dapps Staking runtime This PR/Issue is related to the topic “runtime”. shibuya related to shibuya shiden related to shiden runtime

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants