Submitted by rayn, also found by IllIllI and Czar102
HolyPaladinToken.sol#L466
HolyPaladinToken.sol#L492
HolyPaladinToken.sol#L644
HolyPaladinToken.sol#L663
HolyPaladinToken.sol#L917
HolyPaladinToken.sol#L961
HolyPaladinToken.sol#L993
HolyPaladinToken.sol#L1148
HolyPaladinToken.sol#L1164
HolyPaladinToken.sol#L1184
HolyPaladinToken.sol#L1199
HolyPaladinToken.sol#L1225
HolyPaladinToken.sol#L1250
HolyPaladinToken.sol#L1260
HolyPaladinToken.sol#L1287
HolyPaladinToken.sol#L1293
HolyPaladinToken.sol#L1324
HolyPaladinToken.sol#L1352
HolyPaladinToken.sol#L1357
4 kinds of states (UserLock, TotalLock, Checkpoint, DelegateCheckpoint) are maintained in the protocol to keep record of history. For functions that query history states, target block number is used as an index to search for the corresponding state.
However, 3 (DelegateCheckpoint, TotalLock, UserLocks) out of the 4 states are allowed to have multiple entries with same fromBlock, resulting in a one-to-many mapping between block number and history entry. This makes queried results at best imprecise, and at worst manipulatable by malicious users to present an incorrect history.
Functions that query history states including _getPastLock, getPastTotalLock, _getPastDelegate perform a binary search through the array of history states to find entry matching queried block number. However, the searched arrays can contain multiple entries with the same fromBlock.
For example the _lock function pushes a new UserLock to userLocks[user] regardless of previous lock block number.
This makes the history searches imprecise at best. Additionally, if a user intends to shadow his past states from queries through public search functions, it is possible to control the number of entries precisely such that binsearch returns the entry he wants to show.
vim, ganache-cli
Adopt the same strategy as checkpoint, and modify last entry in array instead of pushing new one if it fromBlock == block.number.
Kogaroshi (Paladin) confirmed, resolved, and commented:
0xean (judge) commented:
