forked from algorand/indexer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add account min balance field (algorand#1596)
* Add account min balance field * Update test resource boxes.json to expect min_balance field to be present/set. * Add unit test for minBalance calculation inspired by go-algorand. --------- Co-authored-by: Gary Malouf <[email protected]>
- Loading branch information
1 parent
5fdba20
commit b019536
Showing
11 changed files
with
657 additions
and
343 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
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, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
package types | ||
|
||
import ( | ||
"github.com/algorand/go-algorand-sdk/v2/protocol/config" | ||
sdk "github.com/algorand/go-algorand-sdk/v2/types" | ||
"github.com/stretchr/testify/assert" | ||
"testing" | ||
) | ||
|
||
func TestMinBalance(t *testing.T) { | ||
testConsensusParams := &config.ConsensusParams{ | ||
MinBalance: 100000, | ||
AppFlatParamsMinBalance: 100000, | ||
AppFlatOptInMinBalance: 100000, | ||
SchemaMinBalancePerEntry: 25000, | ||
SchemaUintMinBalance: 3500, | ||
SchemaBytesMinBalance: 25000, | ||
BoxFlatMinBalance: 2500, | ||
BoxByteMinBalance: 400, | ||
} | ||
|
||
tests := []struct { | ||
name string | ||
expectedResult uint64 | ||
proto *config.ConsensusParams | ||
totalAssets uint64 | ||
totalAppSchema sdk.StateSchema | ||
totalAppParams uint64 | ||
totalAppLocalStates uint64 | ||
totalExtraAppPages uint64 | ||
totalBoxes uint64 | ||
totalBoxBytes uint64 | ||
}{ | ||
{ | ||
"Passing all 0s/empties to minBalance", | ||
0, | ||
&config.ConsensusParams{}, | ||
0, | ||
sdk.StateSchema{}, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
}, | ||
{ | ||
"Base Case: Use non-zero consensus minBalance with otherwise 0s/empties", | ||
100000, | ||
testConsensusParams, | ||
0, | ||
sdk.StateSchema{}, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
}, | ||
{ | ||
"Base Case with non-zero totalAssets", | ||
testConsensusParams.MinBalance + (testConsensusParams.MinBalance * 20), | ||
testConsensusParams, | ||
20, | ||
sdk.StateSchema{}, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
}, | ||
{ | ||
"Layering in created applications", | ||
testConsensusParams.MinBalance + (testConsensusParams.MinBalance * 20) + | ||
(testConsensusParams.AppFlatParamsMinBalance * 30), | ||
testConsensusParams, | ||
20, | ||
sdk.StateSchema{}, | ||
30, | ||
0, | ||
0, | ||
0, | ||
0, | ||
}, | ||
{ | ||
"Layering in opted in applications", | ||
testConsensusParams.MinBalance + (testConsensusParams.MinBalance * 20) + | ||
(testConsensusParams.AppFlatParamsMinBalance * 30) + (testConsensusParams.AppFlatOptInMinBalance * 5), | ||
testConsensusParams, | ||
20, | ||
sdk.StateSchema{}, | ||
30, | ||
5, | ||
0, | ||
0, | ||
0, | ||
}, | ||
{ | ||
"Including State Usage Costs", | ||
testConsensusParams.MinBalance + (testConsensusParams.MinBalance * 20) + | ||
(testConsensusParams.AppFlatParamsMinBalance * 30) + (testConsensusParams.AppFlatOptInMinBalance * 5) + | ||
(testConsensusParams.SchemaMinBalancePerEntry * (500 + 1000)) + | ||
(testConsensusParams.SchemaUintMinBalance * 500) + | ||
(testConsensusParams.SchemaBytesMinBalance * 1000), | ||
testConsensusParams, | ||
20, | ||
sdk.StateSchema{ | ||
NumUint: 500, | ||
NumByteSlice: 1000, | ||
}, | ||
30, | ||
5, | ||
0, | ||
0, | ||
0, | ||
}, | ||
{ | ||
"Including Extra App Pages", | ||
testConsensusParams.MinBalance + (testConsensusParams.MinBalance * 20) + | ||
(testConsensusParams.AppFlatParamsMinBalance * 30) + (testConsensusParams.AppFlatOptInMinBalance * 5) + | ||
(testConsensusParams.SchemaMinBalancePerEntry * (500 + 1000)) + | ||
(testConsensusParams.SchemaUintMinBalance * 500) + | ||
(testConsensusParams.SchemaBytesMinBalance * 1000) + | ||
(testConsensusParams.AppFlatParamsMinBalance * 300), | ||
testConsensusParams, | ||
20, | ||
sdk.StateSchema{ | ||
NumUint: 500, | ||
NumByteSlice: 1000, | ||
}, | ||
30, | ||
5, | ||
300, | ||
0, | ||
0, | ||
}, | ||
{ | ||
"Add in Total Boxes and Bytes", | ||
testConsensusParams.MinBalance + (testConsensusParams.MinBalance * 20) + | ||
(testConsensusParams.AppFlatParamsMinBalance * 30) + (testConsensusParams.AppFlatOptInMinBalance * 5) + | ||
(testConsensusParams.SchemaMinBalancePerEntry * (500 + 1000)) + | ||
(testConsensusParams.SchemaUintMinBalance * 500) + | ||
(testConsensusParams.SchemaBytesMinBalance * 1000) + | ||
(testConsensusParams.AppFlatParamsMinBalance * 300) + | ||
(testConsensusParams.BoxFlatMinBalance * 8) + | ||
(testConsensusParams.BoxByteMinBalance * 7500), | ||
testConsensusParams, | ||
20, | ||
sdk.StateSchema{ | ||
NumUint: 500, | ||
NumByteSlice: 1000, | ||
}, | ||
30, | ||
5, | ||
300, | ||
8, | ||
7500, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
result := minBalance( | ||
test.proto, | ||
test.totalAssets, | ||
test.totalAppSchema, | ||
test.totalAppParams, | ||
test.totalAppLocalStates, | ||
test.totalExtraAppPages, | ||
test.totalBoxes, | ||
test.totalBoxBytes, | ||
) | ||
|
||
assert.Equal(t, test.expectedResult, result) | ||
}) | ||
} | ||
} |