Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: lock token transfer and parameter module #3176

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions contribs/gnodev/pkg/dev/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ func NewDevNode(ctx context.Context, cfg *NodeConfig) (*Node, error) {
initialState: cfg.InitialTxs,
currentStateIndex: len(cfg.InitialTxs),
}

// generate genesis state
genesis := gnoland.DefaultGenState()
genesis.Balances = cfg.BalancesList
genesis.Txs = append(pkgsTxs, cfg.InitialTxs...)
Expand Down
1 change: 0 additions & 1 deletion contribs/gnodev/pkg/dev/node_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ func (n *Node) ExportStateAsGenesis(ctx context.Context) (*bft.GenesisDoc, error

// Get current blockstore state
doc := *n.Node.GenesisDoc() // copy doc

genState := doc.AppState.(gnoland.GnoGenesisState)
genState.Balances = n.config.BalancesList
genState.Txs = state
moul marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
31 changes: 31 additions & 0 deletions examples/gno.land/r/sys/params/params.gno
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package params

import (
"std"
prms "sys/params"

"gno.land/p/demo/dao"
"gno.land/r/gov/dao/bridge"
Expand All @@ -44,6 +45,26 @@ func NewBytesPropExecutor(key string, value []byte) dao.Executor {
return newPropExecutor(key, func() { std.SetParamBytes(key, value) })
}

func NewPrefixedStringPropExecutor(keeperPrefix, key string, value string) dao.Executor {
return newPropExecutor(key, func() { prms.SetPrefixedString(keeperPrefix, key, value) })
}

func NewPrefixedInt64PropExecutor(keeperPrefix, key string, value int64) dao.Executor {
return newPropExecutor(key, func() { prms.SetPrefixedInt64(keeperPrefix, key, value) })
}

func NewPrefixedUint64PropExecutor(keeperPrefix, key string, value uint64) dao.Executor {
return newPropExecutor(key, func() { prms.SetPrefixedUint64(keeperPrefix, key, value) })
}

func NewPrefixedBoolPropExecutor(keeperPrefix, key string, value bool) dao.Executor {
return newPropExecutor(key, func() { prms.SetPrefixedBool(keeperPrefix, key, value) })
}

func NewPrefixedBytesPropExecutor(keeperPrefix, key string, value []byte) dao.Executor {
return newPropExecutor(keeperPrefix+key, func() { prms.SetPrefixedBytes(keeperPrefix, key, value) })
}

func newPropExecutor(key string, fn func()) dao.Executor {
callback := func() error {
fn()
Expand All @@ -52,3 +73,13 @@ func newPropExecutor(key string, fn func()) dao.Executor {
}
return bridge.GovDAO().NewGovDAOExecutor(callback)
}
func propose(exec dao.Executor, title, desc string) uint64 {
// The executor's callback function is executed only after the proposal has been voted on
// and approved by the GovDAO.
prop := dao.ProposalRequest{
Title: title,
Description: desc,
Executor: exec,
}
return bridge.GovDAO().Propose(prop)
}
18 changes: 18 additions & 0 deletions examples/gno.land/r/sys/params/unlock.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package params

const (
bankKeeperPrefix = "bank"
lockTransferKey = "lockTransfer.string"
UnlockTransferTitle = "Proposal to unlock the transfer of ugnot."
LockTransferTitle = "Proposal to lock the transfer of ugnot."
)

func ProposeUnlockTransfer() uint64 {
exe := NewPrefixedStringPropExecutor(bankKeeperPrefix, lockTransferKey, "")
return propose(exe, UnlockTransferTitle, "")
}

func ProposeLockTransfer() uint64 {
exe := NewPrefixedStringPropExecutor(bankKeeperPrefix, lockTransferKey, "ugnot")
return propose(exe, LockTransferTitle, "")
}
52 changes: 52 additions & 0 deletions examples/gno.land/r/sys/params/unlock_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package params

import (
"testing"

"gno.land/p/demo/dao"
"gno.land/p/demo/simpledao"
"gno.land/p/demo/urequire"
"gno.land/r/gov/dao/bridge"
)

func TestProUnlockTransfer(t *testing.T) {
govdao := bridge.GovDAO()
id := ProposeUnlockTransfer()
p, err := govdao.GetPropStore().ProposalByID(id)
urequire.NoError(t, err)
urequire.Equal(t, UnlockTransferTitle, p.Title())
}

func TestFailUnlockTransfer(t *testing.T) {
govdao := bridge.GovDAO()
id := ProposeUnlockTransfer()
urequire.PanicsWithMessage(
t,
simpledao.ErrProposalNotAccepted.Error(),
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved
func() {
govdao.ExecuteProposal(id)
},
)
}

func TestExeUnlockTransfer(t *testing.T) {
govdao := bridge.GovDAO()
id := ProposeUnlockTransfer()
p, err := govdao.GetPropStore().ProposalByID(id)
urequire.NoError(t, err)
urequire.True(t, dao.Active == p.Status())

govdao.VoteOnProposal(id, dao.YesVote)

urequire.True(t, dao.Accepted == p.Status())

urequire.NotPanics(
t,
func() {
govdao.ExecuteProposal(id)
},
)

urequire.True(t, dao.ExecutionSuccessful == p.Status())

}
35 changes: 27 additions & 8 deletions gno.land/pkg/gnoland/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,18 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) {
baseApp.MountStoreWithDB(baseKey, dbadapter.StoreConstructor, cfg.DB)

// Construct keepers.
paramsKpr := params.NewParamsKeeper(mainKey, "vm")

paramsKpr := params.NewParamsKeeper(mainKey)
acctKpr := auth.NewAccountKeeper(mainKey, paramsKpr, ProtoGnoAccount)
bankKpr := bank.NewBankKeeper(acctKpr, paramsKpr)
gpKpr := auth.NewGasPriceKeeper(mainKey)
bankKpr := bank.NewBankKeeper(acctKpr)

vmk := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr, paramsKpr)
vmk.Output = cfg.VMOutput

paramsKpr.Register(acctKpr.GetParamfulKey(), acctKpr)
paramsKpr.Register(bankKpr.GetParamfulKey(), bankKpr)
paramsKpr.Register(vmk.GetParamfulKey(), vmk)

// Set InitChainer
icc := cfg.InitChainerConfig
icc.baseApp = baseApp
Expand All @@ -123,7 +127,6 @@ func NewAppWithOptions(cfg *AppOptions) (abci.Application, error) {
) {
// Add last gas price in the context
ctx = ctx.WithValue(auth.GasPriceContextKey{}, gpKpr.LastGasPrice(ctx))

// Override auth params.
ctx = ctx.WithValue(auth.AuthParamsContextKey{}, acctKpr.GetParams(ctx))
// Continue on with default auth ante handler.
Expand Down Expand Up @@ -325,11 +328,8 @@ func (cfg InitChainerConfig) loadAppState(ctx sdk.Context, appState any) ([]abci
if !ok {
return nil, fmt.Errorf("invalid AppState of type %T", appState)
}
cfg.acctKpr.InitGenesis(ctx, state.Auth)
params := cfg.acctKpr.GetParams(ctx)
ctx = ctx.WithValue(auth.AuthParamsContextKey{}, params)
auth.InitChainer(ctx, cfg.gpKpr.(auth.GasPriceKeeper), params.InitialGasPrice)

cfg.bankKpr.InitGenesis(ctx, state.Bank)
// Apply genesis balances.
for _, bal := range state.Balances {
acc := cfg.acctKpr.NewAccountWithAddress(ctx, bal.Address)
Expand All @@ -344,6 +344,25 @@ func (cfg InitChainerConfig) loadAppState(ctx sdk.Context, appState any) ([]abci
for _, param := range state.Params {
param.register(ctx, cfg.paramsKpr)
}
// The account keeper's initial genesis state must be set after genesis
// accounts are created in account keeeper with genesis balances
cfg.acctKpr.InitGenesis(ctx, state.Auth)

// The unrestricted address must have been created as one of the genesis accounts.
// Otherwise, we cannot verify the unrestricted address in the genesis state.

for _, addr := range state.Auth.Params.UnrestrictedAddrs {
acc := cfg.acctKpr.GetAccount(ctx, addr)
accr := acc.(*GnoAccount)
accr.SetUnrestricted()
cfg.acctKpr.SetAccount(ctx, acc)
}

cfg.vmKpr.InitGenesis(ctx, state.VM)

params := cfg.acctKpr.GetParams(ctx)
ctx = ctx.WithValue(auth.AuthParamsContextKey{}, params)
auth.InitChainer(ctx, cfg.gpKpr, params.InitialGasPrice)

// Replay genesis txs.
txResponses := make([]abci.ResponseDeliverTx, 0, len(state.Txs))
Expand Down
20 changes: 14 additions & 6 deletions gno.land/pkg/gnoland/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ func TestNewAppWithOptions(t *testing.T) {
{"params/vm/foo.bool", `true`},
{"params/vm/foo.bytes", `"SGkh"`}, // XXX: make this test more readable
}

for _, tc := range tcs {
qres := bapp.Query(abci.RequestQuery{
Path: tc.path,
Expand Down Expand Up @@ -216,12 +217,17 @@ func testInitChainerLoadStdlib(t *testing.T, cached bool) { //nolint:thelper
cfg := InitChainerConfig{
StdlibDir: stdlibDir,
vmKpr: mock,
acctKpr: &mockAuthKeeper{},
bankKpr: &mockBankKeeper{},
paramsKpr: &mockParamsKeeper{},
gpKpr: &mockGasPriceKeeper{},
CacheStdlibLoad: cached,
}
// Construct keepers.
paramsKpr := params.NewParamsKeeper(iavlCapKey, "")
cfg.acctKpr = auth.NewAccountKeeper(iavlCapKey, paramsKpr, ProtoGnoAccount)
cfg.gpKpr = auth.NewGasPriceKeeper(iavlCapKey)
// paramsKpr := params.NewParamsKeeper(iavlCapKey, params.PrefixKeyMapper{})
// cfg.paramsKpr = &mockParamsKeeper{}
// cfg.acctKpr = auth.NewAccountKeeper(iavlCapKey, paramsKpr, ProtoGnoAccount)
// cfg.gpKpr = auth.NewGasPriceKeeper(iavlCapKey)
cfg.InitChainer(testCtx, abci.RequestInitChain{
AppState: DefaultGenState(),
})
Expand Down Expand Up @@ -822,12 +828,14 @@ func newGasPriceTestApp(t *testing.T) abci.Application {
baseApp.MountStoreWithDB(baseKey, dbadapter.StoreConstructor, cfg.DB)

// Construct keepers.
paramsKpr := params.NewParamsKeeper(mainKey, "")
paramsKpr := params.NewParamsKeeper(mainKey)
acctKpr := auth.NewAccountKeeper(mainKey, paramsKpr, ProtoGnoAccount)
gpKpr := auth.NewGasPriceKeeper(mainKey)
bankKpr := bank.NewBankKeeper(acctKpr)
bankKpr := bank.NewBankKeeper(acctKpr, paramsKpr)
vmk := vm.NewVMKeeper(baseKey, mainKey, acctKpr, bankKpr, paramsKpr)

paramsKpr.Register(acctKpr.GetParamfulKey(), acctKpr)
paramsKpr.Register(bankKpr.GetParamfulKey(), bankKpr)
paramsKpr.Register(vmk.GetParamfulKey(), vmk)
// Set InitChainer
icc := cfg.InitChainerConfig
icc.baseApp = baseApp
Expand Down
4 changes: 3 additions & 1 deletion gno.land/pkg/gnoland/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/gnolang/gno/tm2/pkg/crypto"
osm "github.com/gnolang/gno/tm2/pkg/os"
"github.com/gnolang/gno/tm2/pkg/sdk/auth"
"github.com/gnolang/gno/tm2/pkg/sdk/bank"
"github.com/gnolang/gno/tm2/pkg/std"
"github.com/pelletier/go-toml"
)
Expand Down Expand Up @@ -200,7 +201,8 @@ func DefaultGenState() GnoGenesisState {
Balances: []Balance{},
Txs: []TxWithMetadata{},
Auth: authGen,
Bank: bank.DefaultGenesisState(),
VM: vmm.DefaultGenesisState(),
}

return gs
}
85 changes: 85 additions & 0 deletions gno.land/pkg/gnoland/mock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ import (
"log/slog"

"github.com/gnolang/gno/gno.land/pkg/sdk/vm"
"github.com/gnolang/gno/tm2/pkg/crypto"
"github.com/gnolang/gno/tm2/pkg/events"
"github.com/gnolang/gno/tm2/pkg/log"
"github.com/gnolang/gno/tm2/pkg/sdk"
"github.com/gnolang/gno/tm2/pkg/sdk/auth"
"github.com/gnolang/gno/tm2/pkg/sdk/bank"

"github.com/gnolang/gno/tm2/pkg/service"
"github.com/gnolang/gno/tm2/pkg/std"
)

type (
Expand Down Expand Up @@ -113,6 +118,86 @@ func (m *mockVMKeeper) CommitGnoTransactionStore(ctx sdk.Context) {
}
}

func (m *mockVMKeeper) InitGenesis(ctx sdk.Context, gs vm.GenesisState) {
// TODO:
}

type mockBankKeeper struct{}

func (m *mockBankKeeper) InputOutputCoins(ctx sdk.Context, inputs []bank.Input, outputs []bank.Output) error {
return nil
}

func (m *mockBankKeeper) SendCoins(ctx sdk.Context, fromAddr crypto.Address, toAddr crypto.Address, amt std.Coins) error {
return nil
}

func (m *mockBankKeeper) SendCoinsUnrestricted(ctx sdk.Context, fromAddr crypto.Address, toAddr crypto.Address, amt std.Coins) error {
return nil
}

func (m *mockBankKeeper) SubtractCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) (std.Coins, error) {
return nil, nil
}

func (m *mockBankKeeper) AddCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) (std.Coins, error) {
return nil, nil
}

func (m *mockBankKeeper) InitGenesis(ctx sdk.Context, data bank.GenesisState) {}
func (m *mockBankKeeper) GetParams(ctx sdk.Context) bank.Params { return bank.Params{} }
func (m *mockBankKeeper) GetCoins(ctx sdk.Context, addr crypto.Address) std.Coins { return nil }
func (m *mockBankKeeper) SetCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) error {
return nil
}

func (m *mockBankKeeper) HasCoins(ctx sdk.Context, addr crypto.Address, amt std.Coins) bool {
return true
}

type mockAuthKeeper struct{}

func (m *mockAuthKeeper) NewAccountWithAddress(ctx sdk.Context, addr crypto.Address) std.Account {
return nil
}
func (m *mockAuthKeeper) GetAccount(ctx sdk.Context, addr crypto.Address) std.Account { return nil }
func (m *mockAuthKeeper) GetAllAccounts(ctx sdk.Context) []std.Account { return nil }
func (m *mockAuthKeeper) SetAccount(ctx sdk.Context, acc std.Account) {}
func (m *mockAuthKeeper) IterateAccounts(ctx sdk.Context, process func(std.Account) bool) {}
func (m *mockAuthKeeper) InitGenesis(ctx sdk.Context, data auth.GenesisState) {}
func (m *mockAuthKeeper) GetParams(ctx sdk.Context) auth.Params { return auth.Params{} }

type mockParamsKeeper struct{}

func (m *mockParamsKeeper) GetString(ctx sdk.Context, key string, ptr *string) {}
func (m *mockParamsKeeper) GetInt64(ctx sdk.Context, key string, ptr *int64) {}
func (m *mockParamsKeeper) GetUint64(ctx sdk.Context, key string, ptr *uint64) {}
func (m *mockParamsKeeper) GetBool(ctx sdk.Context, key string, ptr *bool) {}
func (m *mockParamsKeeper) GetBytes(ctx sdk.Context, key string, ptr *[]byte) {}

func (m *mockParamsKeeper) SetString(ctx sdk.Context, key string, value string) {}
func (m *mockParamsKeeper) SetInt64(ctx sdk.Context, key string, value int64) {}
func (m *mockParamsKeeper) SetUint64(ctx sdk.Context, key string, value uint64) {}
func (m *mockParamsKeeper) SetBool(ctx sdk.Context, key string, value bool) {}
func (m *mockParamsKeeper) SetBytes(ctx sdk.Context, key string, value []byte) {}

func (m *mockParamsKeeper) Has(ctx sdk.Context, key string) bool { return false }
func (m *mockParamsKeeper) GetRaw(ctx sdk.Context, key string) []byte { return nil }

func (m *mockParamsKeeper) GetParams(ctx sdk.Context, prefixKey string, key string, target interface{}) (bool, error) {
return true, nil
}

func (m *mockParamsKeeper) SetParams(ctx sdk.Context, prefixKey string, key string, params interface{}) error {
return nil
}

type mockGasPriceKeeper struct{}

func (m *mockGasPriceKeeper) LastGasPrice(ctx sdk.Context) std.GasPrice { return std.GasPrice{} }
func (m *mockGasPriceKeeper) SetGasPrice(ctx sdk.Context, gp std.GasPrice) {}
func (m *mockGasPriceKeeper) UpdateGasPrice(ctx sdk.Context) {}

type (
lastBlockHeightDelegate func() int64
loggerDelegate func() *slog.Logger
Expand Down
Loading
Loading