Skip to content

Commit

Permalink
Handle challenged account status in public state API and ride.
Browse files Browse the repository at this point in the history
  • Loading branch information
nickeskov committed Aug 21, 2024
1 parent 199ada4 commit 99cc150
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 4 deletions.
5 changes: 5 additions & 0 deletions pkg/ride/diff_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type diffBalance struct {
leaseIn int64
leaseOut int64
stateGenerating int64
challenged bool
}

func (db *diffBalance) addBalance(amount int64) error {
Expand Down Expand Up @@ -88,6 +89,9 @@ func (db *diffBalance) checkedSpendableBalance() (uint64, error) {
}

func (db *diffBalance) effectiveBalance() (int64, error) {
if db.challenged {
return 0, nil // challenged account has zero effective balance at the current block
}
v1, err := common.AddInt(db.balance, db.leaseIn)
if err != nil {
return 0, err
Expand Down Expand Up @@ -240,6 +244,7 @@ func (ds *diffState) loadWavesBalance(id proto.AddressID) (diffBalance, error) {
leaseIn: profile.LeaseIn,
leaseOut: profile.LeaseOut,
stateGenerating: int64(profile.Generating),
challenged: profile.Challenged,
}
// Store new diff locally
ds.wavesBalances[id] = diff
Expand Down
41 changes: 39 additions & 2 deletions pkg/state/balances.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,33 @@ type balanceProfile struct {
leaseOut int64
}

func (bp *balanceProfile) effectiveBalance() (uint64, error) {
// effectiveBalanceUnchecked returns effective balance without checking for account challenging.
// The function MUST be used ONLY in the context where account challenging IS CHECKED.
func (bp *balanceProfile) effectiveBalanceUnchecked() (uint64, error) {
val, err := common.AddInt(int64(bp.balance), bp.leaseIn)
if err != nil {
return 0, err
}
return uint64(val - bp.leaseOut), nil
}

type challengedChecker func(proto.AddressID, proto.Height) (bool, error)

func (bp *balanceProfile) effectiveBalance(
challengedCheck challengedChecker, // Function to check if the account is challenged.
addrID proto.AddressID, // Address ID of the current balanceProfile.
currentHeight proto.Height, // Current height.
) (uint64, error) {
challenged, err := challengedCheck(addrID, currentHeight)
if err != nil {
return 0, err
}
if challenged {
return 0, nil // Challenged account has 0 effective balance.
}
return bp.effectiveBalanceUnchecked()
}

func (bp *balanceProfile) spendableBalance() uint64 {
return uint64(int64(bp.balance) - bp.leaseOut)
}
Expand Down Expand Up @@ -577,7 +596,7 @@ func minEffectiveBalanceInRangeCommon(records [][]byte) (uint64, error) {
if err := record.unmarshalBinary(recordBytes); err != nil {
return 0, err
}
effectiveBal, err := record.effectiveBalance()
effectiveBal, err := record.effectiveBalanceUnchecked()
if err != nil {
return 0, err
}
Expand Down Expand Up @@ -701,6 +720,8 @@ func (s *balances) storeChallengeHeightForAddr(

type entryDataGetter func(key []byte) ([]byte, error)

// isChallengedAddressInRangeCommon checks if the address was challenged in the given range of heights.
// startHeight and endHeight are inclusive.
func isChallengedAddressInRangeCommon(
getEntryData entryDataGetter,
addr proto.AddressID,
Expand Down Expand Up @@ -759,13 +780,29 @@ func (s *balances) isChallengedAddressInRange(addr proto.AddressID, startHeight,
return isChallengedAddressInRangeCommon(s.hs.topEntryData, addr, startHeight, endHeight)
}

func (s *balances) isChallengedAddress(addr proto.AddressID, height proto.Height) (bool, error) {
var (
startHeight = height
endHeight = startHeight // we're checking only one height, so the heights are the same
)
return s.isChallengedAddressInRange(addr, startHeight, endHeight)
}

func (s *balances) newestIsChallengedAddressInRange(
addr proto.AddressID,
startHeight, endHeight proto.Height,
) (bool, error) {
return isChallengedAddressInRangeCommon(s.hs.newestTopEntryData, addr, startHeight, endHeight)
}

func (s *balances) newestIsChallengedAddress(addr proto.AddressID, height proto.Height) (bool, error) {
var (
startHeight = height
endHeight = startHeight // we're checking only one height, so the heights are the same
)
return s.newestIsChallengedAddressInRange(addr, startHeight, endHeight)
}

// minEffectiveBalanceInRange returns minimal effective balance in range [startHeight, endHeight].
//
// IMPORTANT NOTE: this method returns saved on disk data, for the newest data use newestMinEffectiveBalanceInRange.
Expand Down
27 changes: 25 additions & 2 deletions pkg/state/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -1001,7 +1001,7 @@ func (s *stateManager) FullWavesBalance(account proto.Recipient) (*proto.FullWav
if err != nil {
return nil, errs.Extend(err, "failed to get waves balance")
}
effective, err := profile.effectiveBalance()
effective, err := profile.effectiveBalanceUnchecked()
if err != nil {
return nil, errs.Extend(err, "failed to get effective balance")
}
Expand All @@ -1013,6 +1013,13 @@ func (s *stateManager) FullWavesBalance(account proto.Recipient) (*proto.FullWav
if err != nil {
return nil, errs.Extend(err, "failed to get generating balance")
}
if generating == 0 { // we need to check for challenged addresses only if generating balance is 0
chEffective, effErr := profile.effectiveBalance(s.stor.balances.isChallengedAddress, addr.ID(), height)
if effErr != nil {
return nil, errs.Extend(effErr, "failed to get checked effective balance")
}
effective = chEffective
}
return &proto.FullWavesBalance{
Regular: profile.balance,
Generating: generating,
Expand All @@ -1032,7 +1039,7 @@ func (s *stateManager) NewestFullWavesBalance(account proto.Recipient) (*proto.F
if err != nil {
return nil, wrapErr(RetrievalError, err)
}
effective, err := profile.effectiveBalance()
effective, err := profile.effectiveBalanceUnchecked()
if err != nil {
return nil, wrapErr(Other, err)
}
Expand All @@ -1044,6 +1051,13 @@ func (s *stateManager) NewestFullWavesBalance(account proto.Recipient) (*proto.F
if gb, gbErr := s.NewestGeneratingBalance(account, height); gbErr == nil {
generating = gb
}
if generating == 0 { // we need to check for challenged addresses only if generating balance is 0
chEffective, effErr := profile.effectiveBalance(s.stor.balances.newestIsChallengedAddress, addr.ID(), height)
if effErr != nil {
return nil, wrapErr(RetrievalError, effErr)
}
effective = chEffective
}
return &proto.FullWavesBalance{
Regular: profile.balance,
Generating: generating,
Expand All @@ -1067,11 +1081,20 @@ func (s *stateManager) WavesBalanceProfile(id proto.AddressID) (*types.WavesBala
if gb, gbErr := s.stor.balances.newestGeneratingBalance(id, height); gbErr == nil {
generating = gb
}
var challenged bool
if generating == 0 { // fast path: we need to check for challenged addresses only if generating balance is 0
ch, chErr := s.stor.balances.newestIsChallengedAddress(id, height)
if chErr != nil {
return nil, wrapErr(RetrievalError, chErr)
}
challenged = ch
}
return &types.WavesBalanceProfile{
Balance: profile.balance,
LeaseIn: profile.leaseIn,
LeaseOut: profile.leaseOut,
Generating: generating,
Challenged: challenged,
}, nil
}

Expand Down
1 change: 1 addition & 0 deletions pkg/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type WavesBalanceProfile struct {
LeaseIn int64
LeaseOut int64
Generating uint64
Challenged bool // if Challenged true, the account considered as challenged at the current height.
}

// SmartState is a part of state used by smart contracts.
Expand Down

0 comments on commit 99cc150

Please sign in to comment.