From 6188e0c36a709faedf186898ada1dcace57a0b11 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Tue, 30 Mar 2021 10:49:49 +0200 Subject: [PATCH 1/3] Extract interfaces for genesis state in CLI --- cmd/wasmd/genwasm.go | 11 +-- x/wasm/client/cli/genesis_msg.go | 98 +++++++++++++++++---------- x/wasm/client/cli/genesis_msg_test.go | 6 +- 3 files changed, 72 insertions(+), 43 deletions(-) diff --git a/cmd/wasmd/genwasm.go b/cmd/wasmd/genwasm.go index 87f05cdf4d..3b3a6acd2c 100644 --- a/cmd/wasmd/genwasm.go +++ b/cmd/wasmd/genwasm.go @@ -14,12 +14,13 @@ func AddGenesisWasmMsgCmd(defaultNodeHome string) *cobra.Command { SuggestionsMinimumDistance: 2, RunE: client.ValidateCmd, } + genesisIO := wasmcli.NewDefaultGenesisIO() txCmd.AddCommand( - wasmcli.GenesisStoreCodeCmd(defaultNodeHome), - wasmcli.GenesisInstantiateContractCmd(defaultNodeHome), - wasmcli.GenesisExecuteContractCmd(defaultNodeHome), - wasmcli.GenesisListContractsCmd(defaultNodeHome), - wasmcli.GenesisListCodesCmd(defaultNodeHome), + wasmcli.GenesisStoreCodeCmd(defaultNodeHome, genesisIO), + wasmcli.GenesisInstantiateContractCmd(defaultNodeHome, genesisIO), + wasmcli.GenesisExecuteContractCmd(defaultNodeHome, genesisIO), + wasmcli.GenesisListContractsCmd(defaultNodeHome, genesisIO), + wasmcli.GenesisListCodesCmd(defaultNodeHome, genesisIO), ) return txCmd diff --git a/x/wasm/client/cli/genesis_msg.go b/x/wasm/client/cli/genesis_msg.go index b881d90372..c57a0beae4 100644 --- a/x/wasm/client/cli/genesis_msg.go +++ b/x/wasm/client/cli/genesis_msg.go @@ -24,9 +24,23 @@ import ( tmtypes "github.com/tendermint/tendermint/types" ) +// GenesisReader reads genesis data. Extension point for custom genesis state readers. +type GenesisReader interface { + ReadWasmGenesis(cmd *cobra.Command) (*GenesisData, error) +} + +// GenesisMutator extension point to modify the wasm module genesis state +type GenesisMutator interface { + // AlterModuleState loads the genesis from the default or set home dir, + // unmarshalls the wasm module section into the object representation + // calls the callback function to modify it + // and marshals the modified state back into the genesis file + AlterWasmModuleState(cmd *cobra.Command, callback func(state *types.GenesisState, appState map[string]json.RawMessage) error) error +} + // GenesisStoreCodeCmd cli command to add a `MsgStoreCode` to the wasm section of the genesis // that is executed on block 0. -func GenesisStoreCodeCmd(defaultNodeHome string) *cobra.Command { +func GenesisStoreCodeCmd(defaultNodeHome string, genesisMutator GenesisMutator) *cobra.Command { cmd := &cobra.Command{ Use: "store [wasm file] --source [source] --builder [builder] --run-as [owner_address_or_key_name]\",", Short: "Upload a wasm binary", @@ -45,7 +59,7 @@ func GenesisStoreCodeCmd(defaultNodeHome string) *cobra.Command { return err } - return alterModuleState(cmd, func(state *types.GenesisState, _ map[string]json.RawMessage) error { + return genesisMutator.AlterWasmModuleState(cmd, func(state *types.GenesisState, _ map[string]json.RawMessage) error { state.GenMsgs = append(state.GenMsgs, types.GenesisState_GenMsgs{ Sum: &types.GenesisState_GenMsgs_StoreCode{StoreCode: &msg}, }) @@ -67,7 +81,7 @@ func GenesisStoreCodeCmd(defaultNodeHome string) *cobra.Command { // GenesisInstantiateContractCmd cli command to add a `MsgInstantiateContract` to the wasm section of the genesis // that is executed on block 0. -func GenesisInstantiateContractCmd(defaultNodeHome string) *cobra.Command { +func GenesisInstantiateContractCmd(defaultNodeHome string, genesisMutator GenesisMutator) *cobra.Command { cmd := &cobra.Command{ Use: "instantiate-contract [code_id_int64] [json_encoded_init_args] --label [text] --run-as [address] --admin [address,optional] --amount [coins,optional]", Short: "Instantiate a wasm contract", @@ -86,7 +100,7 @@ func GenesisInstantiateContractCmd(defaultNodeHome string) *cobra.Command { return err } - return alterModuleState(cmd, func(state *types.GenesisState, appState map[string]json.RawMessage) error { + return genesisMutator.AlterWasmModuleState(cmd, func(state *types.GenesisState, appState map[string]json.RawMessage) error { // simple sanity check that sender has some balance although it may be consumed by appState previous message already switch ok, err := hasAccountBalance(cmd, appState, senderAddr, msg.Funds); { case err != nil: @@ -134,7 +148,7 @@ func GenesisInstantiateContractCmd(defaultNodeHome string) *cobra.Command { // GenesisInstantiateContractCmd cli command to add a `MsgExecuteContract` to the wasm section of the genesis // that is executed on block 0. -func GenesisExecuteContractCmd(defaultNodeHome string) *cobra.Command { +func GenesisExecuteContractCmd(defaultNodeHome string, genesisMutator GenesisMutator) *cobra.Command { cmd := &cobra.Command{ Use: "execute [contract_addr_bech32] [json_encoded_send_args] --run-as [address] --amount [coins,optional]", Short: "Execute a command on a wasm contract", @@ -153,7 +167,7 @@ func GenesisExecuteContractCmd(defaultNodeHome string) *cobra.Command { return err } - return alterModuleState(cmd, func(state *types.GenesisState, appState map[string]json.RawMessage) error { + return genesisMutator.AlterWasmModuleState(cmd, func(state *types.GenesisState, appState map[string]json.RawMessage) error { // simple sanity check that sender has some balance although it may be consumed by appState previous message already switch ok, err := hasAccountBalance(cmd, appState, senderAddr, msg.Funds); { case err != nil: @@ -184,17 +198,17 @@ func GenesisExecuteContractCmd(defaultNodeHome string) *cobra.Command { // GenesisListCodesCmd cli command to list all codes stored in the genesis wasm.code section // as well as from messages that are queued in the wasm.genMsgs section. -func GenesisListCodesCmd(defaultNodeHome string) *cobra.Command { +func GenesisListCodesCmd(defaultNodeHome string, genReader GenesisReader) *cobra.Command { cmd := &cobra.Command{ Use: "list-codes ", Short: "Lists all codes from genesis code dump and queued messages", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - g, err := readGenesis(cmd) + g, err := genReader.ReadWasmGenesis(cmd) if err != nil { return err } - all, err := getAllCodes(g.wasmModuleState) + all, err := getAllCodes(g.WasmModuleState) if err != nil { return err } @@ -209,17 +223,17 @@ func GenesisListCodesCmd(defaultNodeHome string) *cobra.Command { // GenesisListContractsCmd cli command to list all contracts stored in the genesis wasm.contract section // as well as from messages that are queued in the wasm.genMsgs section. -func GenesisListContractsCmd(defaultNodeHome string) *cobra.Command { +func GenesisListContractsCmd(defaultNodeHome string, genReader GenesisReader) *cobra.Command { cmd := &cobra.Command{ Use: "list-contracts ", Short: "Lists all contracts from genesis contract dump and queued messages", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - g, err := readGenesis(cmd) + g, err := genReader.ReadWasmGenesis(cmd) if err != nil { return err } - state := g.wasmModuleState + state := g.WasmModuleState all := getAllContracts(state) return printJsonOutput(cmd, all) }, @@ -352,15 +366,21 @@ func hasContract(state *types.GenesisState, contractAddr string) bool { return false } -// genesisData contains raw and unmarshalled data from the genesis file -type genesisData struct { - genesisFile string - genDoc *tmtypes.GenesisDoc - appState map[string]json.RawMessage - wasmModuleState *types.GenesisState +// GenesisData contains raw and unmarshalled data from the genesis file +type GenesisData struct { + GenesisFile string + GenDoc *tmtypes.GenesisDoc + AppState map[string]json.RawMessage + WasmModuleState *types.GenesisState +} + +func NewGenesisData(genesisFile string, genDoc *tmtypes.GenesisDoc, appState map[string]json.RawMessage, wasmModuleState *types.GenesisState) *GenesisData { + return &GenesisData{GenesisFile: genesisFile, GenDoc: genDoc, AppState: appState, WasmModuleState: wasmModuleState} } -func readGenesis(cmd *cobra.Command) (*genesisData, error) { +type DefaultGenesisReader struct{} + +func (d DefaultGenesisReader) ReadWasmGenesis(cmd *cobra.Command) (*GenesisData, error) { clientCtx := client.GetClientContextFromCmd(cmd) serverCtx := server.GetServerContextFromCmd(cmd) config := serverCtx.Config @@ -377,44 +397,52 @@ func readGenesis(cmd *cobra.Command) (*genesisData, error) { clientCtx.JSONMarshaler.MustUnmarshalJSON(appState[types.ModuleName], &wasmGenesisState) } - return &genesisData{ - genesisFile: genFile, - genDoc: genDoc, - appState: appState, - wasmModuleState: &wasmGenesisState, - }, nil + return NewGenesisData( + genFile, + genDoc, + appState, + &wasmGenesisState, + ), nil +} + +type DefaultGenesisIO struct { + GenesisReader +} + +func NewDefaultGenesisIO() *DefaultGenesisIO { + return &DefaultGenesisIO{GenesisReader: DefaultGenesisReader{}} } -// alterModuleState loads the genesis from the default or set home dir, +// AlterModuleState loads the genesis from the default or set home dir, // unmarshalls the wasm module section into the object representation // calls the callback function to modify it // and marshals the modified state back into the genesis file -func alterModuleState(cmd *cobra.Command, callback func(state *types.GenesisState, appState map[string]json.RawMessage) error) error { - g, err := readGenesis(cmd) +func (x DefaultGenesisIO) AlterWasmModuleState(cmd *cobra.Command, callback func(state *types.GenesisState, appState map[string]json.RawMessage) error) error { + g, err := x.ReadWasmGenesis(cmd) if err != nil { return err } - if err := callback(g.wasmModuleState, g.appState); err != nil { + if err := callback(g.WasmModuleState, g.AppState); err != nil { return err } // and store update - if err := g.wasmModuleState.ValidateBasic(); err != nil { + if err := g.WasmModuleState.ValidateBasic(); err != nil { return err } clientCtx := client.GetClientContextFromCmd(cmd) - wasmGenStateBz, err := clientCtx.JSONMarshaler.MarshalJSON(g.wasmModuleState) + wasmGenStateBz, err := clientCtx.JSONMarshaler.MarshalJSON(g.WasmModuleState) if err != nil { return sdkerrors.Wrap(err, "marshal wasm genesis state") } - g.appState[types.ModuleName] = wasmGenStateBz - appStateJSON, err := json.Marshal(g.appState) + g.AppState[types.ModuleName] = wasmGenStateBz + appStateJSON, err := json.Marshal(g.AppState) if err != nil { return sdkerrors.Wrap(err, "marshal application genesis state") } - g.genDoc.AppState = appStateJSON - return genutil.ExportGenesisFile(g.genDoc, g.genesisFile) + g.GenDoc.AppState = appStateJSON + return genutil.ExportGenesisFile(g.GenDoc, g.GenesisFile) } // contractSeqValue reads the contract sequence from the genesis or diff --git a/x/wasm/client/cli/genesis_msg_test.go b/x/wasm/client/cli/genesis_msg_test.go index 5f88bf6575..af78717dad 100644 --- a/x/wasm/client/cli/genesis_msg_test.go +++ b/x/wasm/client/cli/genesis_msg_test.go @@ -101,7 +101,7 @@ func TestGenesisStoreCodeCmd(t *testing.T) { homeDir := setupGenesis(t, spec.srcGenesis) // when - cmd := GenesisStoreCodeCmd(homeDir) + cmd := GenesisStoreCodeCmd(homeDir, NewDefaultGenesisIO()) spec.mutator(cmd) err := executeCmdWithContext(t, homeDir, cmd) if spec.expError { @@ -299,7 +299,7 @@ func TestInstantiateContractCmd(t *testing.T) { homeDir := setupGenesis(t, spec.srcGenesis) // when - cmd := GenesisInstantiateContractCmd(homeDir) + cmd := GenesisInstantiateContractCmd(homeDir, NewDefaultGenesisIO()) spec.mutator(cmd) err := executeCmdWithContext(t, homeDir, cmd) if spec.expError { @@ -498,7 +498,7 @@ func TestExecuteContractCmd(t *testing.T) { for msg, spec := range specs { t.Run(msg, func(t *testing.T) { homeDir := setupGenesis(t, spec.srcGenesis) - cmd := GenesisExecuteContractCmd(homeDir) + cmd := GenesisExecuteContractCmd(homeDir, NewDefaultGenesisIO()) spec.mutator(cmd) // when From 183e9aaa6a80b5affb02cad93a9d6a1ec9e3e173 Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 31 Mar 2021 09:12:15 +0200 Subject: [PATCH 2/3] Add more godoc --- x/wasm/client/cli/genesis_msg.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/x/wasm/client/cli/genesis_msg.go b/x/wasm/client/cli/genesis_msg.go index c57a0beae4..8ae5f88eff 100644 --- a/x/wasm/client/cli/genesis_msg.go +++ b/x/wasm/client/cli/genesis_msg.go @@ -29,7 +29,8 @@ type GenesisReader interface { ReadWasmGenesis(cmd *cobra.Command) (*GenesisData, error) } -// GenesisMutator extension point to modify the wasm module genesis state +// GenesisMutator extension point to modify the wasm module genesis state. +// This gives flexibility to customize the data structure in the genesis file a bit. type GenesisMutator interface { // AlterModuleState loads the genesis from the default or set home dir, // unmarshalls the wasm module section into the object representation @@ -405,10 +406,16 @@ func (d DefaultGenesisReader) ReadWasmGenesis(cmd *cobra.Command) (*GenesisData, ), nil } +var _ GenesisReader = DefaultGenesisIO{} +var _ GenesisMutator = DefaultGenesisIO{} + +// DefaultGenesisIO implements both interfaces to read and modify the genesis state for this module. +// This implementation uses the default data structure that is used by the module.go genesis import/ export. type DefaultGenesisIO struct { GenesisReader } +// NewDefaultGenesisIO constructor to create a new instance func NewDefaultGenesisIO() *DefaultGenesisIO { return &DefaultGenesisIO{GenesisReader: DefaultGenesisReader{}} } From 6c89f4f1b0f8a1c22fcac16e412b4682ee506bff Mon Sep 17 00:00:00 2001 From: Alex Peters Date: Wed, 31 Mar 2021 13:10:15 +0200 Subject: [PATCH 3/3] Review feedback --- x/wasm/client/cli/genesis_msg.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/wasm/client/cli/genesis_msg.go b/x/wasm/client/cli/genesis_msg.go index 8ae5f88eff..dcee5acecf 100644 --- a/x/wasm/client/cli/genesis_msg.go +++ b/x/wasm/client/cli/genesis_msg.go @@ -412,12 +412,12 @@ var _ GenesisMutator = DefaultGenesisIO{} // DefaultGenesisIO implements both interfaces to read and modify the genesis state for this module. // This implementation uses the default data structure that is used by the module.go genesis import/ export. type DefaultGenesisIO struct { - GenesisReader + DefaultGenesisReader } // NewDefaultGenesisIO constructor to create a new instance func NewDefaultGenesisIO() *DefaultGenesisIO { - return &DefaultGenesisIO{GenesisReader: DefaultGenesisReader{}} + return &DefaultGenesisIO{DefaultGenesisReader: DefaultGenesisReader{}} } // AlterModuleState loads the genesis from the default or set home dir,