Skip to content

Commit

Permalink
Add account min balance field
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonpaulos authored and gmalouf committed May 14, 2024
1 parent dcf3a3b commit bfac431
Show file tree
Hide file tree
Showing 9 changed files with 438 additions and 323 deletions.
3 changes: 3 additions & 0 deletions accounting/rewind.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ func AccountAtRound(ctx context.Context, account models.Account, round uint64, d
acct.PendingRewards = 0
acct.Amount = acct.AmountWithoutPendingRewards

// MinBalance is not supported.
acct.MinBalance = 0

// TODO: Clear out the closed-at field as well. Like Rewards we cannot know this value for all accounts.
//acct.ClosedAt = 0

Expand Down
275 changes: 138 additions & 137 deletions api/generated/common/routes.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions api/generated/common/types.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

357 changes: 179 additions & 178 deletions api/generated/v2/routes.go

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions api/generated/v2/types.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions api/indexer.oas2.json
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,7 @@
"amount-without-pending-rewards",
"rewards",
"status",
"min-balance",
"total-apps-opted-in",
"total-assets-opted-in",
"total-box-bytes",
Expand All @@ -1044,6 +1045,10 @@
"description": "total number of MicroAlgos in the account",
"type": "integer"
},
"min-balance": {
"description": "MicroAlgo balance required by the account.\n\nThe requirement grows based on asset and application usage.",
"type": "integer"
},
"amount-without-pending-rewards": {
"description": "specifies the amount of MicroAlgos in the account, without the pending rewards.",
"type": "integer"
Expand Down
5 changes: 5 additions & 0 deletions api/indexer.oas3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,10 @@
"description": "The round in which this account last proposed the block.",
"type": "integer"
},
"min-balance": {
"description": "MicroAlgo balance required by the account.\n\nThe requirement grows based on asset and application usage.",
"type": "integer"
},
"participation": {
"$ref": "#/components/schemas/AccountParticipation"
},
Expand Down Expand Up @@ -828,6 +832,7 @@
"address",
"amount",
"amount-without-pending-rewards",
"min-balance",
"pending-rewards",
"rewards",
"round",
Expand Down
21 changes: 13 additions & 8 deletions idb/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,17 @@ func (db *IndexerDb) yieldAccountsThread(req *getAccountsRequest) {
db.log.Warnf("long query %fs: %s", dt.Seconds(), req.query)
}
}()
var proto config.ConsensusParams
{
var ok bool
// temporarily cast req.blockheader.CurrentProtocol(string) to protocol.ConsensusVersion
proto, ok = config.Consensus[protocol.ConsensusVersion(req.blockheader.CurrentProtocol)]
if !ok {
err := fmt.Errorf("get protocol err (%s)", req.blockheader.CurrentProtocol)
req.out <- idb.AccountRow{Error: err}
return
}
}
for req.rows.Next() {
var addr []byte
var microalgos uint64
Expand Down Expand Up @@ -1131,20 +1142,14 @@ func (db *IndexerDb) yieldAccountsThread(req *getAccountsRequest) {
account.IncentiveEligible = omitEmpty(accountData.IncentiveEligible)
account.LastHeartbeat = omitEmpty(uint64(accountData.LastHeartbeat))
account.LastProposed = omitEmpty(uint64(accountData.LastProposed))

account.MinBalance = itypes.AccountMinBalance(accountData, &proto)
}

if account.Status == "NotParticipating" {
account.PendingRewards = 0
} else {
// TODO: pending rewards calculation doesn't belong in database layer (this is just the most covenient place which has all the data)
// TODO: replace config.Consensus. config.Consensus map[protocol.ConsensusVersion]ConsensusParams
// temporarily cast req.blockheader.CurrentProtocol(string) to protocol.ConsensusVersion
proto, ok := config.Consensus[protocol.ConsensusVersion(req.blockheader.CurrentProtocol)]
if !ok {
err = fmt.Errorf("get protocol err (%s)", req.blockheader.CurrentProtocol)
req.out <- idb.AccountRow{Error: err}
break
}
rewardsUnits := uint64(0)
if proto.RewardUnit != 0 {
rewardsUnits = microalgos / proto.RewardUnit
Expand Down
85 changes: 85 additions & 0 deletions types/min_balance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package types

import (
"github.com/algorand/go-algorand-sdk/v2/protocol/config"

sdk "github.com/algorand/go-algorand-sdk/v2/types"
)

// stateSchemaMinBalance computes the MinBalance requirements for a StateSchema
// based on the consensus parameters
func stateSchemaMinBalance(sm sdk.StateSchema, proto *config.ConsensusParams) uint64 {
// Flat cost for each key/value pair
flatCost := proto.SchemaMinBalancePerEntry * (sm.NumUint + sm.NumByteSlice)

// Cost for uints
uintCost := proto.SchemaUintMinBalance * sm.NumUint

// Cost for byte slices
bytesCost := proto.SchemaBytesMinBalance * sm.NumByteSlice

// Sum the separate costs
return flatCost + uintCost + bytesCost
}

// minBalance computes the minimum balance requirements for an account based on
// some consensus parameters. MinBalance should correspond roughly to how much
// storage the account is allowed to store on disk.
func minBalance(
proto *config.ConsensusParams,
totalAssets uint64,
totalAppSchema sdk.StateSchema,
totalAppParams uint64, totalAppLocalStates uint64,
totalExtraAppPages uint64,
totalBoxes uint64, totalBoxBytes uint64,
) uint64 {
var min uint64

// First, base MinBalance
min = proto.MinBalance

// MinBalance for each Asset
assetCost := proto.MinBalance * totalAssets
min += assetCost

// Base MinBalance for each created application
appCreationCost := proto.AppFlatParamsMinBalance * totalAppParams
min += appCreationCost

// Base MinBalance for each opted in application
appOptInCost := proto.AppFlatOptInMinBalance * totalAppLocalStates
min += appOptInCost

// MinBalance for state usage measured by LocalStateSchemas and
// GlobalStateSchemas
schemaCost := stateSchemaMinBalance(totalAppSchema, proto)
min += schemaCost

// MinBalance for each extra app program page
extraAppProgramLenCost := proto.AppFlatParamsMinBalance * totalExtraAppPages
min += extraAppProgramLenCost

// Base MinBalance for each created box
boxBaseCost := proto.BoxFlatMinBalance * totalBoxes
min += boxBaseCost

// Per byte MinBalance for boxes
boxByteCost := proto.BoxByteMinBalance * totalBoxBytes
min += boxByteCost

return min
}

// AccountMinBalance computes the minimum balance requirements for an account
// based on some consensus parameters. MinBalance should correspond roughly to
// how much storage the account is allowed to store on disk.
func AccountMinBalance(account sdk.AccountData, proto *config.ConsensusParams) uint64 {
return minBalance(
proto,
account.TotalAssets,
account.TotalAppSchema,
account.TotalAppParams, account.TotalAppLocalStates,
uint64(account.TotalExtraAppPages),
account.TotalBoxes, account.TotalBoxBytes,
)
}

0 comments on commit bfac431

Please sign in to comment.