Closed sherlock-admin3 closed 1 month ago
1 comment(s) were left on this issue during the judging contest.
0xmystery commented:
Errors in
RemoveStakes
/RemoveDelegateStakes
are silently handled inEndBlocker
The protocol team fixed this issue in the following PRs/commits: https://github.com/allora-network/allora-chain/pull/465
zigtur
Medium
Failed stake removals and failed delegate stake removals are not replayable
Summary
Stake removal and delegate stake removal can fail due to several reasons, but there is no mechanism to replay a failing one.
Vulnerability Detail
When a reputer calls
RemoveStake
at block N, a stake removal request is registered. It will be executed after a delay window (X blocks). The stake removal execution will be automatic at block N+X. (The same applies toRemoveDelegateStake
)The stake removals requests are executed at the end of a block in the
RemoveStakes
function. This function will execute all stake removals for the current block.When one of the stake removals fail, this stake removal request is not removed for a potential execution in the future. However, there is no mechanism to execute a stake removal that has failed in a previous block.
Impact
Stake removals and delegate stake removals can be locked after the delay window.
Code Snippet
The
EndBlocker
function allows executing code out of block. It callsRemoveStakes
. See abci.go#L22-L23.Then,
RemoveStakes
retrieves all stake removals for the current block. It executes the stake removal in a for loop. If one is failing, this one is not removed.See stake_removals.go#L13-L63.
The same applies to
RemoveDelegateStakes
which retrieves all delegate stake removals for the current block. If one is failing, this one is not removed.See stake_removals.go#L66-L118.
Once a stake removal or a delegate stake removal has failed once (for example, due to a lack of balance), the failing one will never be replayable because there is no mechanism to do so.
Tool used
Manual Review
Recommendation
New message entrypoints should be added to execute stake removals and delegate stake removals that failed in a previous block. For example,
ExecutePreviousRemoveStake
andExecutePreviousRemoveDelegateStake
.Note: The pattern "transfer tokens then delete stake request" in
RemoveStakes
andRemoveDelegateStakes
is pretty unsafe as if the deletion fails, the tokens are still transfered and the stake removal request is not deleted.Duplicate of #55