Skip to content

Commit

Permalink
Implement total coins (#8)
Browse files Browse the repository at this point in the history
implementation of totalCoin
---------

Co-authored-by: ThinhNX <168700277+thinhnx-var@users.noreply.github.com>
  • Loading branch information
linhpn99 and thinhnx-var committed Aug 9, 2024
1 parent bbcb2f6 commit 4593a4c
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 15 deletions.
3 changes: 2 additions & 1 deletion gno.land/pkg/gnoland/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) {

// Construct keepers.
acctKpr := auth.NewAccountKeeper(mainKey, ProtoGnoAccount)
bankKpr := bank.NewBankKeeper(acctKpr)
tckpr := bank.NewTotalCoinKeeper(mainKey)
bankKpr := bank.NewBankKeeper(acctKpr, tckpr)

// XXX: Embed this ?
stdlibsDir := filepath.Join(cfg.GnoRootDir, "gnovm", "stdlibs")
Expand Down
2 changes: 1 addition & 1 deletion gno.land/pkg/sdk/vm/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (bnk *SDKBanker) SendCoins(b32from, b32to crypto.Bech32Address, amt std.Coi
}

func (bnk *SDKBanker) TotalCoin(denom string) int64 {
panic("not yet implemented")
return bnk.vmk.bank.TotalCoin(bnk.ctx, denom)
}

func (bnk *SDKBanker) IssueCoin(b32addr crypto.Bech32Address, denom string, amount int64) {
Expand Down
3 changes: 2 additions & 1 deletion gno.land/pkg/sdk/vm/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ func _setupTestEnv(cacheStdlibs bool) testEnv {

ctx := sdk.NewContext(sdk.RunTxModeDeliver, ms, &bft.Header{ChainID: "test-chain-id"}, log.NewNoopLogger())
acck := authm.NewAccountKeeper(iavlCapKey, std.ProtoBaseAccount)
bank := bankm.NewBankKeeper(acck)
tck := bankm.NewTotalCoinKeeper(iavlCapKey)
bank := bankm.NewBankKeeper(acck, tck)
stdlibsDir := filepath.Join("..", "..", "..", "..", "gnovm", "stdlibs")
vmk := NewVMKeeper(baseCapKey, iavlCapKey, acck, bank, stdlibsDir, 100_000_000)

Expand Down
15 changes: 12 additions & 3 deletions gnovm/tests/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -547,17 +547,24 @@ func trimTrailingSpaces(result string) string {

type testBanker struct {
coinTable map[crypto.Bech32Address]std.Coins
totalCoin map[string]int64
}

func newTestBanker(args ...interface{}) *testBanker {
coinTable := make(map[crypto.Bech32Address]std.Coins)
totalCoin := make(map[string]int64)
if len(args)%2 != 0 {
panic("newTestBanker requires even number of arguments; addr followed by coins")
}
for i := 0; i < len(args); i += 2 {
addr := args[i].(crypto.Bech32Address)
amount := args[i+1].(std.Coins)
coinTable[addr] = amount
coins := args[i+1].(std.Coins)
coinTable[addr] = coins
for _, coin := range coins {
if coin.IsValid() {
totalCoin[coin.Denom] += coin.Amount
}
}
}
return &testBanker{
coinTable: coinTable,
Expand Down Expand Up @@ -591,17 +598,19 @@ func (tb *testBanker) SendCoins(from, to crypto.Bech32Address, amt std.Coins) {
}

func (tb *testBanker) TotalCoin(denom string) int64 {
panic("not yet implemented")
return tb.totalCoin[denom]
}

func (tb *testBanker) IssueCoin(addr crypto.Bech32Address, denom string, amt int64) {
coins, _ := tb.coinTable[addr]
sum := coins.Add(std.Coins{{denom, amt}})
tb.coinTable[addr] = sum
tb.totalCoin[denom] += amt
}

func (tb *testBanker) RemoveCoin(addr crypto.Bech32Address, denom string, amt int64) {
coins, _ := tb.coinTable[addr]
rest := coins.Sub(std.Coins{{denom, amt}})
tb.coinTable[addr] = rest
tb.totalCoin[denom] -= amt
}
5 changes: 4 additions & 1 deletion tm2/pkg/sdk/bank/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/gnolang/gno/tm2/pkg/sdk"
"github.com/gnolang/gno/tm2/pkg/sdk/auth"

"github.com/gnolang/gno/tm2/pkg/std"
"github.com/gnolang/gno/tm2/pkg/store"
"github.com/gnolang/gno/tm2/pkg/store/iavl"
Expand All @@ -18,6 +19,7 @@ type testEnv struct {
ctx sdk.Context
bank BankKeeper
acck auth.AccountKeeper
tck TotalCoinKeeper
}

func setupTestEnv() testEnv {
Expand All @@ -34,7 +36,8 @@ func setupTestEnv() testEnv {
authCapKey, std.ProtoBaseAccount,
)

bank := NewBankKeeper(acck)
tck := NewTotalCoinKeeper(authCapKey)
bank := NewBankKeeper(acck, tck)

return testEnv{ctx: ctx, bank: bank, acck: acck}
}
8 changes: 8 additions & 0 deletions tm2/pkg/sdk/bank/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,12 @@ package bank

const (
ModuleName = "bank"

// TotalCoinStoreKeyPrefix prefix for total-coin-by-denom store
TotalCoinStoreKeyPrefix = "/tc/"
)

// TotalCoinStoreKey turn an denom to key used to get it from the total coin store
func TotalCoinStoreKey(denom string) []byte {
return []byte(TotalCoinStoreKeyPrefix + denom)
}
137 changes: 131 additions & 6 deletions tm2/pkg/sdk/bank/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"fmt"
"log/slog"

"github.com/gnolang/gno/tm2/pkg/amino"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/sdk"
"github.com/gnolang/gno/tm2/pkg/sdk/auth"
"github.com/gnolang/gno/tm2/pkg/std"
"github.com/gnolang/gno/tm2/pkg/store"
)

// bank.Keeper defines a module interface that facilitates the transfer of
Expand All @@ -31,13 +33,15 @@ type BankKeeper struct {
ViewKeeper

acck auth.AccountKeeper
tck TotalCoinKeeper
}

// NewBankKeeper returns a new BankKeeper.
func NewBankKeeper(acck auth.AccountKeeper) BankKeeper {
func NewBankKeeper(acck auth.AccountKeeper, tck TotalCoinKeeper) BankKeeper {
return BankKeeper{
ViewKeeper: NewViewKeeper(acck),
ViewKeeper: NewViewKeeper(acck, tck),
acck: acck,
tck: tck,
}
}

Expand Down Expand Up @@ -134,9 +138,18 @@ func (bank BankKeeper) SubtractCoins(ctx sdk.Context, addr crypto.Address, amt s
)
return nil, err
}

err := bank.SetCoins(ctx, addr, newCoins)
if err != nil {
return nil, err
}

return newCoins, err
err = bank.tck.decreaseTotalCoin(ctx, newCoins)
if err != nil {
return nil, err
}

return newCoins, nil
}

// AddCoins adds amt to the coins at the addr.
Expand All @@ -155,7 +168,16 @@ func (bank BankKeeper) AddCoins(ctx sdk.Context, addr crypto.Address, amt std.Co
}

err := bank.SetCoins(ctx, addr, newCoins)
return newCoins, err
if err != nil {
return nil, err
}

err = bank.tck.increaseTotalCoin(ctx, newCoins)
if err != nil {
return nil, err
}

return newCoins, nil
}

// SetCoins sets the coins at the addr.
Expand All @@ -175,6 +197,7 @@ func (bank BankKeeper) SetCoins(ctx sdk.Context, addr crypto.Address, amt std.Co
}

bank.acck.SetAccount(ctx, acc)

return nil
}

Expand All @@ -186,18 +209,20 @@ func (bank BankKeeper) SetCoins(ctx sdk.Context, addr crypto.Address, amt std.Co
type ViewKeeperI interface {
GetCoins(ctx sdk.Context, addr crypto.Address) std.Coins
HasCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) bool
TotalCoin(ctx sdk.Context, denom string) int64
}

var _ ViewKeeperI = ViewKeeper{}

// ViewKeeper implements a read only keeper implementation of ViewKeeperI.
type ViewKeeper struct {
acck auth.AccountKeeper
tck TotalCoinKeeper
}

// NewViewKeeper returns a new ViewKeeper.
func NewViewKeeper(acck auth.AccountKeeper) ViewKeeper {
return ViewKeeper{acck: acck}
func NewViewKeeper(acck auth.AccountKeeper, tck TotalCoinKeeper) ViewKeeper {
return ViewKeeper{acck: acck, tck: tck}
}

// Logger returns a module-specific logger.
Expand All @@ -218,3 +243,103 @@ func (view ViewKeeper) GetCoins(ctx sdk.Context, addr crypto.Address) std.Coins
func (view ViewKeeper) HasCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) bool {
return view.GetCoins(ctx, addr).IsAllGTE(amt)
}

func (view ViewKeeper) TotalCoin(ctx sdk.Context, denom string) int64 {
return view.tck.totalCoin(ctx, denom)
}

// TotalCoinKeeper manages the total amount of coins for various denominations.
type TotalCoinKeeper struct {
key store.StoreKey
}

// NewTotalCoinKeeper returns a new TotalCoinKeeper.
func NewTotalCoinKeeper(key store.StoreKey) TotalCoinKeeper {
return TotalCoinKeeper{
key: key,
}
}

// increaseTotalCoin increases the total coin amounts for the specified denominations.
func (tck TotalCoinKeeper) increaseTotalCoin(ctx sdk.Context, coins std.Coins) error {
stor := ctx.Store(tck.key)

for _, coin := range coins {
bz := stor.Get(TotalCoinStoreKey(coin.Denom))
if bz == nil {
continue
}

oldTotalCoin := tck.decodeTotalCoin(bz)

newTotalCoin := oldTotalCoin.Add(coin)
err := tck.setTotalCoin(ctx, newTotalCoin)
if err != nil {
return err
}
}

return nil
}

// decreaseTotalCoin decreases the total coin amounts for the specified denominations.
func (tck TotalCoinKeeper) decreaseTotalCoin(ctx sdk.Context, coins std.Coins) error {
stor := ctx.Store(tck.key)

for _, coin := range coins {
bz := stor.Get(TotalCoinStoreKey(coin.Denom))
if bz == nil {
return fmt.Errorf("denomination %s not found", coin.Denom)
}

oldTotalCoin := tck.decodeTotalCoin(bz)
newTotalCoin := oldTotalCoin.SubUnsafe(coin)
if !newTotalCoin.IsValid() {
err := std.ErrInsufficientCoins(
fmt.Sprintf("insufficient account funds; %s < %s", oldTotalCoin, coin),
)
return err
}

err := tck.setTotalCoin(ctx, newTotalCoin)
if err != nil {
return err
}
}

return nil
}

// GetTotalCoin returns the total coin for a given denomination.
func (tck TotalCoinKeeper) totalCoin(ctx sdk.Context, denom string) int64 {
stor := ctx.Store(tck.key)
bz := stor.Get(TotalCoinStoreKey(denom))
if bz == nil {
return 0
}

totalCoin := tck.decodeTotalCoin(bz)

return totalCoin.Amount
}

// SetTotalCoin sets the total coin amount for a given denomination.
func (tck TotalCoinKeeper) setTotalCoin(ctx sdk.Context, totalCoin std.Coin) error {
stor := ctx.Store(tck.key)
bz, err := amino.MarshalAny(totalCoin)
if err != nil {
return err
}
stor.Set(TotalCoinStoreKey(totalCoin.Denom), bz)
return nil
}

// decodeTotalCoin decodes the total coin from a byte slice.
func (tck TotalCoinKeeper) decodeTotalCoin(bz []byte) std.Coin {
var coin std.Coin
err := amino.Unmarshal(bz, &coin)
if err != nil {
panic(err)
}
return coin
}
4 changes: 2 additions & 2 deletions tm2/pkg/sdk/bank/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestBankKeeper(t *testing.T) {
env := setupTestEnv()
ctx := env.ctx

bank := NewBankKeeper(env.acck)
bank := NewBankKeeper(env.acck, env.tck)

addr := crypto.AddressFromPreimage([]byte("addr1"))
addr2 := crypto.AddressFromPreimage([]byte("addr2"))
Expand Down Expand Up @@ -142,7 +142,7 @@ func TestViewKeeper(t *testing.T) {

env := setupTestEnv()
ctx := env.ctx
view := NewViewKeeper(env.acck)
view := NewViewKeeper(env.acck, env.tck)

addr := crypto.AddressFromPreimage([]byte("addr1"))
acc := env.acck.NewAccountWithAddress(ctx, addr)
Expand Down

0 comments on commit 4593a4c

Please sign in to comment.