Merge PR #5572: ADR 004 Implementation
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
- 2020-01-08: Initial version
|
||||
- 2020-01-09: Alterations to handle vesting accounts
|
||||
- 2020-01-14: Updates from review feedback
|
||||
- 2020-01-30: Updates from implementation
|
||||
|
||||
## Context
|
||||
|
||||
@@ -18,35 +19,74 @@ Balances shall be stored per-account & per-denomination under a denomination- an
|
||||
|
||||
### Account interface (x/auth)
|
||||
|
||||
`GetCoins()` and `SetCoins()` will be removed from the account interface, since coin balances will now be stored in & managed by the bank module.
|
||||
`GetCoins()` and `SetCoins()` will be removed from the account interface, since coin balances will
|
||||
now be stored in & managed by the bank module.
|
||||
|
||||
`SpendableCoinsVestingAccount()` and `TrackDelegation()` will be altered to take a bank keeper and a denomination as two additional arguments, which will be used to lookup the balances from the base account as necessary.
|
||||
The vesting account interface will replace `SpendableCoins` in favor of `LockedCoins` which does
|
||||
not require the account balance anymore. In addition, `TrackDelegation()` will now accept the
|
||||
account balance of all tokens denominated in the vesting balance instead of loading the entire
|
||||
account balance.
|
||||
|
||||
Vesting accounts will continue to store original vesting, delegated free, and delegated vesting coins (which is safe since these cannot contain arbitrary denominations).
|
||||
Vesting accounts will continue to store original vesting, delegated free, and delegated
|
||||
vesting coins (which is safe since these cannot contain arbitrary denominations).
|
||||
|
||||
### Bank keeper (x/bank)
|
||||
|
||||
`GetBalance(addr AccAddress, denom string) sdk.Coin` and `SetBalance(addr AccAddress, coin sdk.Coin)` methods will be added to the bank keeper to retrieve & set balances, respectively.
|
||||
The following APIs will be added to the `x/bank` keeper:
|
||||
|
||||
Balances will be stored first by the address, then by the denomination (the reverse is also possible, but retrieval of all balances for a single account is presumed to be more frequent):
|
||||
- `GetAllBalances(ctx Context, addr AccAddress) Coins`
|
||||
- `GetBalance(ctx Context, addr AccAddress, denom string) Coin`
|
||||
- `SetBalance(ctx Context, addr AccAddress, coin Coin)`
|
||||
- `LockedCoins(ctx Context, addr AccAddress) Coins`
|
||||
- `SpendableCoins(ctx Context, addr AccAddress) Coins`
|
||||
|
||||
Additional APIs may be added to facilitate iteration and auxiliary functionality not essential to
|
||||
core functionality or persistence.
|
||||
|
||||
Balances will be stored first by the address, then by the denomination (the reverse is also possible,
|
||||
but retrieval of all balances for a single account is presumed to be more frequent):
|
||||
|
||||
```golang
|
||||
func BalanceKey(addr sdk.AccAddress, denom string) []byte {
|
||||
return append(append(BalanceKeyPrefix, addr.Bytes()...), []byte(denom)...)
|
||||
var BalancesPrefix = []byte("balances")
|
||||
|
||||
func (k Keeper) SetBalance(ctx Context, addr AccAddress, balance Coin) error {
|
||||
if !balance.IsValid() {
|
||||
return err
|
||||
}
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
balancesStore := prefix.NewStore(store, BalancesPrefix)
|
||||
accountStore := prefix.NewStore(balancesStore, addr.Bytes())
|
||||
|
||||
bz := Marshal(balance)
|
||||
accountStore.Set([]byte(balance.Denom), bz)
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
`DelegateCoins()` and `UndelegateCoins()` will be altered to take a single `sdk.Coin` (one denomination & amount) instead of `sdk.Coins`, since they should only operate on one denomination. They will read balances directly instead of calling `GetCoins()` (which no longer exists).
|
||||
This will result in the balances being indexed by the byte representation of
|
||||
`balances/{address}/{denom}`.
|
||||
|
||||
`SubtractCoins()` and `AddCoins()` will be altered to read & write the balances directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist).
|
||||
`DelegateCoins()` and `UndelegateCoins()` will be altered to only load each individual
|
||||
account balance by denomination found in the (un)delegation amount. As a result,
|
||||
any mutations to the account balance by will made by denomination.
|
||||
|
||||
`trackDelegation()` and `trackUndelegation()` will be altered to read & write the balances directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist).
|
||||
`SubtractCoins()` and `AddCoins()` will be altered to read & write the balances
|
||||
directly instead of calling `GetCoins()` / `SetCoins()` (which no longer exist).
|
||||
|
||||
External APIs will need to scan all balances under an account to retain backwards-compatibility - additional methods should be added to fetch a balance for a single denomination only.
|
||||
`trackDelegation()` and `trackUndelegation()` will be altered to no longer update
|
||||
account balances.
|
||||
|
||||
External APIs will need to scan all balances under an account to retain backwards-compatibility. It
|
||||
is advised that these APIs use `GetBalance` and `SetBalance` instead of `GetAllBalances` when
|
||||
possible as to not load the entire account balance.
|
||||
|
||||
### Supply module
|
||||
|
||||
The supply module, in order to implement the total supply invariant, will now need to scan all accounts & call `GetBalance` using the `x/bank` Keeper for the denomination in question, then sum the balances and check that they match the expected total supply.
|
||||
The supply module, in order to implement the total supply invariant, will now need
|
||||
to scan all accounts & call `GetAllBalances` using the `x/bank` Keeper, then sum
|
||||
the balances and check that they match the expected total supply.
|
||||
|
||||
## Status
|
||||
|
||||
@@ -56,11 +96,14 @@ Proposed.
|
||||
|
||||
### Positive
|
||||
|
||||
- O(1) reads & writes of balances (with respect to the number of denominations for which an account has non-zero balances)
|
||||
- O(1) reads & writes of balances (with respect to the number of denominations for
|
||||
which an account has non-zero balances). Note, this does not relate to the actual
|
||||
I/O cost, rather the total number of direct reads needed.
|
||||
|
||||
### Negative
|
||||
|
||||
- Slighly less efficient reads/writes when reading & writing all balances of a single account in a transaction.
|
||||
- Slightly less efficient reads/writes when reading & writing all balances of a
|
||||
single account in a transaction.
|
||||
|
||||
### Neutral
|
||||
|
||||
@@ -68,6 +111,6 @@ None in particular.
|
||||
|
||||
## References
|
||||
|
||||
Ref https://github.com/cosmos/cosmos-sdk/issues/4982
|
||||
Ref https://github.com/cosmos/cosmos-sdk/issues/5467
|
||||
Ref https://github.com/cosmos/cosmos-sdk/issues/5492
|
||||
- Ref: https://github.com/cosmos/cosmos-sdk/issues/4982
|
||||
- Ref: https://github.com/cosmos/cosmos-sdk/issues/5467
|
||||
- Ref: https://github.com/cosmos/cosmos-sdk/issues/5492
|
||||
|
||||
Reference in New Issue
Block a user