Introduce Wasmgovd (#189)
* Introduce wasmgovd; disable wasm proposals with wasmd * Update changelog * Setup wasmgov with permission Nobody * Review feedback
This commit is contained in:
@@ -37,6 +37,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
## [Unreleased]
|
||||
|
||||
### Features
|
||||
* (wasmd) [\#187](https://github.com/CosmWasm/wasmd/issues/187) Introduce wasmgovd binary
|
||||
* (wasmd) [\#178](https://github.com/CosmWasm/wasmd/issues/178) Add cli support for wasm gov proposals
|
||||
* (wasmd) [\#163](https://github.com/CosmWasm/wasmd/issues/163) Control who can instantiate code
|
||||
* (wasmd) [\#164](https://github.com/CosmWasm/wasmd/issues/164) Control who can upload code
|
||||
|
||||
@@ -39,6 +39,7 @@ RUN BUILD_TAGS=muslc make build
|
||||
FROM alpine:3.12
|
||||
|
||||
COPY --from=go-builder /code/build/wasmd /usr/bin/wasmd
|
||||
COPY --from=go-builder /code/build/wasmgovd /usr/bin/wasmgovd
|
||||
COPY --from=go-builder /code/build/wasmcli /usr/bin/wasmcli
|
||||
|
||||
COPY docker/* /opt/
|
||||
|
||||
2
Makefile
2
Makefile
@@ -70,9 +70,11 @@ all: install lint test
|
||||
build: go.sum
|
||||
ifeq ($(OS),Windows_NT)
|
||||
go build -mod=readonly $(BUILD_FLAGS) -o build/wasmd.exe ./cmd/wasmd
|
||||
go build -mod=readonly $(BUILD_FLAGS) -o build/wasmgovd.exe ./cmd/wasmgovd
|
||||
go build -mod=readonly $(BUILD_FLAGS) -o build/wasmcli.exe ./cmd/wasmcli
|
||||
else
|
||||
go build -mod=readonly $(BUILD_FLAGS) -o build/wasmd ./cmd/wasmd
|
||||
go build -mod=readonly $(BUILD_FLAGS) -o build/wasmgovd ./cmd/wasmgovd
|
||||
go build -mod=readonly $(BUILD_FLAGS) -o build/wasmcli ./cmd/wasmcli
|
||||
endif
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ func main() {
|
||||
cobra.EnableCommandSorting = false
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "wasmd",
|
||||
Short: "Wasm Daemon (server)",
|
||||
Short: "Wasm Daemon (server) with wasm gov proposals disabled\",",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application
|
||||
}
|
||||
|
||||
return app.NewWasmApp(logger, db, traceStore, true, invCheckPeriod,
|
||||
wasm.EnableAllProposals, skipUpgradeHeights,
|
||||
wasm.DisableAllProposals, skipUpgradeHeights,
|
||||
baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))),
|
||||
baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)),
|
||||
baseapp.SetHaltHeight(viper.GetUint64(server.FlagHaltHeight)),
|
||||
@@ -99,7 +99,7 @@ func exportAppStateAndTMValidators(
|
||||
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
|
||||
if height != -1 {
|
||||
gapp := app.NewWasmApp(logger, db, traceStore, false, uint(1), wasm.EnableAllProposals, nil)
|
||||
gapp := app.NewWasmApp(logger, db, traceStore, false, uint(1), wasm.DisableAllProposals, nil)
|
||||
err := gapp.LoadHeight(height)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -107,6 +107,6 @@ func exportAppStateAndTMValidators(
|
||||
return gapp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
||||
}
|
||||
|
||||
gapp := app.NewWasmApp(logger, db, traceStore, true, uint(1), wasm.EnableAllProposals, nil)
|
||||
gapp := app.NewWasmApp(logger, db, traceStore, true, uint(1), wasm.DisableAllProposals, nil)
|
||||
return gapp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func replayTxs(rootDir string) error {
|
||||
fmt.Fprintln(os.Stderr, "Creating application")
|
||||
gapp := app.NewWasmApp(
|
||||
// TODO: do we want to set skipUpgradeHieghts here?
|
||||
ctx.Logger, appDB, traceStoreWriter, true, uint(1), wasm.EnableAllProposals, nil,
|
||||
ctx.Logger, appDB, traceStoreWriter, true, uint(1), wasm.DisableAllProposals, nil,
|
||||
baseapp.SetPruning(store.PruneEverything))
|
||||
|
||||
// Genesis
|
||||
|
||||
153
cmd/wasmgovd/genaccounts.go
Normal file
153
cmd/wasmgovd/genaccounts.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
)
|
||||
|
||||
const (
|
||||
flagClientHome = "home-client"
|
||||
flagVestingStart = "vesting-start-time"
|
||||
flagVestingEnd = "vesting-end-time"
|
||||
flagVestingAmt = "vesting-amount"
|
||||
)
|
||||
|
||||
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
|
||||
func AddGenesisAccountCmd(
|
||||
ctx *server.Context, cdc *codec.Codec, defaultNodeHome, defaultClientHome string,
|
||||
) *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]",
|
||||
Short: "Add a genesis account to genesis.json",
|
||||
Long: `Add a genesis account to genesis.json. The provided account must specify
|
||||
the account address or key name and a list of initial coins. If a key name is given,
|
||||
the address will be looked up in the local Keybase. The list of initial tokens must
|
||||
contain valid denominations. Accounts may optionally be supplied with vesting parameters.
|
||||
`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
|
||||
addr, err := sdk.AccAddressFromBech32(args[0])
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
if err != nil {
|
||||
// attempt to lookup address from Keybase if no address was provided
|
||||
kb, err := keys.NewKeyring(
|
||||
sdk.KeyringServiceName(),
|
||||
viper.GetString(flags.FlagKeyringBackend),
|
||||
viper.GetString(flagClientHome),
|
||||
inBuf,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := kb.Get(args[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get address from Keybase: %w", err)
|
||||
}
|
||||
|
||||
addr = info.GetAddress()
|
||||
}
|
||||
|
||||
coins, err := sdk.ParseCoins(args[1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse coins: %w", err)
|
||||
}
|
||||
|
||||
vestingStart := viper.GetInt64(flagVestingStart)
|
||||
vestingEnd := viper.GetInt64(flagVestingEnd)
|
||||
vestingAmt, err := sdk.ParseCoins(viper.GetString(flagVestingAmt))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse vesting amount: %w", err)
|
||||
}
|
||||
|
||||
// create concrete account type based on input parameters
|
||||
var genAccount authexported.GenesisAccount
|
||||
|
||||
baseAccount := auth.NewBaseAccount(addr, coins.Sort(), nil, 0, 0)
|
||||
if !vestingAmt.IsZero() {
|
||||
baseVestingAccount, err := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create base vesting account: %w", err)
|
||||
}
|
||||
|
||||
switch {
|
||||
case vestingStart != 0 && vestingEnd != 0:
|
||||
genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart)
|
||||
|
||||
case vestingEnd != 0:
|
||||
genAccount = authvesting.NewDelayedVestingAccountRaw(baseVestingAccount)
|
||||
|
||||
default:
|
||||
return errors.New("invalid vesting parameters; must supply start and end time or end time")
|
||||
}
|
||||
} else {
|
||||
genAccount = baseAccount
|
||||
}
|
||||
|
||||
if err := genAccount.Validate(); err != nil {
|
||||
return fmt.Errorf("failed to validate new genesis account: %w", err)
|
||||
}
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
appState, genDoc, err := genutil.GenesisStateFromGenFile(cdc, genFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to unmarshal genesis state: %w", err)
|
||||
}
|
||||
|
||||
authGenState := auth.GetGenesisStateFromAppState(cdc, appState)
|
||||
|
||||
if authGenState.Accounts.Contains(addr) {
|
||||
return fmt.Errorf("cannot add account at existing address %s", addr)
|
||||
}
|
||||
|
||||
// Add the new account to the set of genesis accounts and sanitize the
|
||||
// accounts afterwards.
|
||||
authGenState.Accounts = append(authGenState.Accounts, genAccount)
|
||||
authGenState.Accounts = auth.SanitizeGenesisAccounts(authGenState.Accounts)
|
||||
|
||||
authGenStateBz, err := cdc.MarshalJSON(authGenState)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal auth genesis state: %w", err)
|
||||
}
|
||||
|
||||
appState[auth.ModuleName] = authGenStateBz
|
||||
|
||||
appStateJSON, err := cdc.MarshalJSON(appState)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal application genesis state: %w", err)
|
||||
}
|
||||
|
||||
genDoc.AppState = appStateJSON
|
||||
return genutil.ExportGenesisFile(genDoc, genFile)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, defaultNodeHome, "node's home directory")
|
||||
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
|
||||
cmd.Flags().String(flagClientHome, defaultClientHome, "client's home directory")
|
||||
cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts")
|
||||
cmd.Flags().Uint64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts")
|
||||
cmd.Flags().Uint64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts")
|
||||
|
||||
return cmd
|
||||
}
|
||||
114
cmd/wasmgovd/main.go
Normal file
114
cmd/wasmgovd/main.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/CosmWasm/wasmd/app"
|
||||
"github.com/CosmWasm/wasmd/x/wasm"
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client/debug"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
)
|
||||
|
||||
const flagInvCheckPeriod = "inv-check-period"
|
||||
|
||||
var invCheckPeriod uint
|
||||
|
||||
func main() {
|
||||
cdc := app.MakeCodec()
|
||||
|
||||
config := sdk.GetConfig()
|
||||
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
|
||||
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
|
||||
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
|
||||
config.Seal()
|
||||
|
||||
homeDir := os.ExpandEnv("$HOME/.wasmgovd")
|
||||
|
||||
ctx := server.NewDefaultContext()
|
||||
cobra.EnableCommandSorting = false
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "wasmgovd",
|
||||
Short: "Wasm Daemon (server) with wasm gov proposals enabled\",",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||
}
|
||||
rootCmd.AddCommand(genutilcli.InitCmd(ctx, cdc, app.ModuleBasics, homeDir))
|
||||
rootCmd.AddCommand(genutilcli.CollectGenTxsCmd(ctx, cdc, auth.GenesisAccountIterator{}, homeDir))
|
||||
rootCmd.AddCommand(genutilcli.MigrateGenesisCmd(ctx, cdc))
|
||||
rootCmd.AddCommand(
|
||||
genutilcli.GenTxCmd(
|
||||
ctx, cdc, app.ModuleBasics, staking.AppModuleBasic{},
|
||||
auth.GenesisAccountIterator{}, homeDir, app.DefaultCLIHome,
|
||||
),
|
||||
)
|
||||
rootCmd.AddCommand(genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics))
|
||||
rootCmd.AddCommand(AddGenesisAccountCmd(ctx, cdc, homeDir, app.DefaultCLIHome))
|
||||
rootCmd.AddCommand(flags.NewCompletionCmd(rootCmd, true))
|
||||
// rootCmd.AddCommand(testnetCmd(ctx, cdc, app.ModuleBasics, auth.GenesisAccountIterator{}))
|
||||
rootCmd.AddCommand(replayCmd())
|
||||
rootCmd.AddCommand(debug.Cmd(cdc))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "WM", homeDir)
|
||||
rootCmd.PersistentFlags().UintVar(&invCheckPeriod, flagInvCheckPeriod,
|
||||
0, "Assert registered invariants every N blocks")
|
||||
err := executor.Execute()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application {
|
||||
var cache sdk.MultiStorePersistentCache
|
||||
|
||||
if viper.GetBool(server.FlagInterBlockCache) {
|
||||
cache = store.NewCommitKVStoreCacheManager()
|
||||
}
|
||||
|
||||
skipUpgradeHeights := make(map[int64]bool)
|
||||
for _, h := range viper.GetIntSlice(server.FlagUnsafeSkipUpgrades) {
|
||||
skipUpgradeHeights[int64(h)] = true
|
||||
}
|
||||
|
||||
return app.NewWasmApp(logger, db, traceStore, true, invCheckPeriod,
|
||||
wasm.EnableAllProposals, skipUpgradeHeights,
|
||||
baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))),
|
||||
baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)),
|
||||
baseapp.SetHaltHeight(viper.GetUint64(server.FlagHaltHeight)),
|
||||
baseapp.SetHaltTime(viper.GetUint64(server.FlagHaltTime)),
|
||||
baseapp.SetInterBlockCache(cache))
|
||||
}
|
||||
|
||||
func exportAppStateAndTMValidators(
|
||||
logger log.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailWhiteList []string,
|
||||
) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
|
||||
if height != -1 {
|
||||
gapp := app.NewWasmApp(logger, db, traceStore, false, uint(1), wasm.EnableAllProposals, nil)
|
||||
err := gapp.LoadHeight(height)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return gapp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
||||
}
|
||||
|
||||
gapp := app.NewWasmApp(logger, db, traceStore, true, uint(1), wasm.EnableAllProposals, nil)
|
||||
return gapp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
|
||||
}
|
||||
191
cmd/wasmgovd/replay.go
Normal file
191
cmd/wasmgovd/replay.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/CosmWasm/wasmd/app"
|
||||
"github.com/CosmWasm/wasmd/x/wasm"
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
cpm "github.com/otiai10/copy"
|
||||
"github.com/spf13/cobra"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
tmsm "github.com/tendermint/tendermint/state"
|
||||
tmstore "github.com/tendermint/tendermint/store"
|
||||
tm "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func replayCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "replay <root-dir>",
|
||||
Short: "Replay gaia transactions",
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
return replayTxs(args[0])
|
||||
},
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
}
|
||||
|
||||
func replayTxs(rootDir string) error {
|
||||
|
||||
if false {
|
||||
// Copy the rootDir to a new directory, to preserve the old one.
|
||||
fmt.Fprintln(os.Stderr, "Copying rootdir over")
|
||||
oldRootDir := rootDir
|
||||
rootDir = oldRootDir + "_replay"
|
||||
if tmos.FileExists(rootDir) {
|
||||
tmos.Exit(fmt.Sprintf("temporary copy dir %v already exists", rootDir))
|
||||
}
|
||||
if err := cpm.Copy(oldRootDir, rootDir); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
configDir := filepath.Join(rootDir, "config")
|
||||
dataDir := filepath.Join(rootDir, "data")
|
||||
ctx := server.NewDefaultContext()
|
||||
|
||||
// App DB
|
||||
// appDB := dbm.NewMemDB()
|
||||
fmt.Fprintln(os.Stderr, "Opening app database")
|
||||
appDB, err := sdk.NewLevelDB("application", dataDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TM DB
|
||||
// tmDB := dbm.NewMemDB()
|
||||
fmt.Fprintln(os.Stderr, "Opening tendermint state database")
|
||||
tmDB, err := sdk.NewLevelDB("state", dataDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Blockchain DB
|
||||
fmt.Fprintln(os.Stderr, "Opening blockstore database")
|
||||
bcDB, err := sdk.NewLevelDB("blockstore", dataDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TraceStore
|
||||
var traceStoreWriter io.Writer
|
||||
var traceStoreDir = filepath.Join(dataDir, "trace.log")
|
||||
traceStoreWriter, err = os.OpenFile(
|
||||
traceStoreDir,
|
||||
os.O_WRONLY|os.O_APPEND|os.O_CREATE,
|
||||
0666,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Application
|
||||
fmt.Fprintln(os.Stderr, "Creating application")
|
||||
gapp := app.NewWasmApp(
|
||||
// TODO: do we want to set skipUpgradeHieghts here?
|
||||
ctx.Logger, appDB, traceStoreWriter, true, uint(1), wasm.EnableAllProposals, nil,
|
||||
baseapp.SetPruning(store.PruneEverything))
|
||||
|
||||
// Genesis
|
||||
var genDocPath = filepath.Join(configDir, "genesis.json")
|
||||
genDoc, err := tm.GenesisDocFromFile(genDocPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genState, err := tmsm.MakeGenesisState(genDoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// tmsm.SaveState(tmDB, genState)
|
||||
|
||||
cc := proxy.NewLocalClientCreator(gapp)
|
||||
proxyApp := proxy.NewAppConns(cc)
|
||||
err = proxyApp.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
err = proxyApp.Stop()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
state := tmsm.LoadState(tmDB)
|
||||
if state.LastBlockHeight == 0 {
|
||||
// Send InitChain msg
|
||||
fmt.Fprintln(os.Stderr, "Sending InitChain msg")
|
||||
validators := tm.TM2PB.ValidatorUpdates(genState.Validators)
|
||||
csParams := tm.TM2PB.ConsensusParams(genDoc.ConsensusParams)
|
||||
req := abci.RequestInitChain{
|
||||
Time: genDoc.GenesisTime,
|
||||
ChainId: genDoc.ChainID,
|
||||
ConsensusParams: csParams,
|
||||
Validators: validators,
|
||||
AppStateBytes: genDoc.AppState,
|
||||
}
|
||||
res, err := proxyApp.Consensus().InitChainSync(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newValidatorz, err := tm.PB2TM.ValidatorUpdates(res.Validators)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newValidators := tm.NewValidatorSet(newValidatorz)
|
||||
|
||||
// Take the genesis state.
|
||||
state = genState
|
||||
state.Validators = newValidators
|
||||
state.NextValidators = newValidators
|
||||
}
|
||||
|
||||
// Create executor
|
||||
fmt.Fprintln(os.Stderr, "Creating block executor")
|
||||
blockExec := tmsm.NewBlockExecutor(tmDB, ctx.Logger, proxyApp.Consensus(), nil, tmsm.MockEvidencePool{})
|
||||
|
||||
// Create block store
|
||||
fmt.Fprintln(os.Stderr, "Creating block store")
|
||||
blockStore := tmstore.NewBlockStore(bcDB)
|
||||
|
||||
tz := []time.Duration{0, 0, 0}
|
||||
for i := int(state.LastBlockHeight) + 1; ; i++ {
|
||||
fmt.Fprintln(os.Stderr, "Running block ", i)
|
||||
t1 := time.Now()
|
||||
|
||||
// Apply block
|
||||
fmt.Printf("loading and applying block %d\n", i)
|
||||
blockmeta := blockStore.LoadBlockMeta(int64(i))
|
||||
if blockmeta == nil {
|
||||
fmt.Printf("Couldn't find block meta %d... done?\n", i)
|
||||
return nil
|
||||
}
|
||||
block := blockStore.LoadBlock(int64(i))
|
||||
if block == nil {
|
||||
return fmt.Errorf("couldn't find block %d", i)
|
||||
}
|
||||
|
||||
t2 := time.Now()
|
||||
|
||||
state, err = blockExec.ApplyBlock(state, blockmeta.BlockID, block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t3 := time.Now()
|
||||
tz[0] += t2.Sub(t1)
|
||||
tz[1] += t3.Sub(t2)
|
||||
|
||||
fmt.Fprintf(os.Stderr, "new app hash: %X\n", state.AppHash)
|
||||
fmt.Fprintln(os.Stderr, tz)
|
||||
}
|
||||
}
|
||||
374
cmd/wasmgovd/testnet.go
Normal file
374
cmd/wasmgovd/testnet.go
Normal file
@@ -0,0 +1,374 @@
|
||||
package main
|
||||
|
||||
// DONTCOVER
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
tmconfig "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
tmrand "github.com/tendermint/tendermint/libs/rand"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
)
|
||||
|
||||
var (
|
||||
flagNodeDirPrefix = "node-dir-prefix"
|
||||
flagNumValidators = "v"
|
||||
flagOutputDir = "output-dir"
|
||||
flagNodeDaemonHome = "node-daemon-home"
|
||||
flagNodeCLIHome = "node-cli-home"
|
||||
flagStartingIPAddress = "starting-ip-address"
|
||||
)
|
||||
|
||||
// get cmd to initialize all files for tendermint testnet and application
|
||||
func testnetCmd(ctx *server.Context, cdc *codec.Codec,
|
||||
mbm module.BasicManager, genAccIterator genutiltypes.GenesisAccountsIterator,
|
||||
) *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "testnet",
|
||||
Short: "Initialize files for a Wasmd testnet",
|
||||
Long: `testnet will create "v" number of directories and populate each with
|
||||
necessary files (private validator, genesis, config, etc.).
|
||||
|
||||
Note, strict routability for addresses is turned off in the config file.
|
||||
|
||||
Example:
|
||||
wasmd testnet --v 4 --output-dir ./output --starting-ip-address 192.168.10.2
|
||||
`,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
config := ctx.Config
|
||||
|
||||
outputDir := viper.GetString(flagOutputDir)
|
||||
chainID := viper.GetString(flags.FlagChainID)
|
||||
minGasPrices := viper.GetString(server.FlagMinGasPrices)
|
||||
nodeDirPrefix := viper.GetString(flagNodeDirPrefix)
|
||||
nodeDaemonHome := viper.GetString(flagNodeDaemonHome)
|
||||
nodeCLIHome := viper.GetString(flagNodeCLIHome)
|
||||
startingIPAddress := viper.GetString(flagStartingIPAddress)
|
||||
numValidators := viper.GetInt(flagNumValidators)
|
||||
|
||||
return InitTestnet(cmd, config, cdc, mbm, genAccIterator, outputDir, chainID,
|
||||
minGasPrices, nodeDirPrefix, nodeDaemonHome, nodeCLIHome, startingIPAddress, numValidators)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Int(flagNumValidators, 4,
|
||||
"Number of validators to initialize the testnet with")
|
||||
cmd.Flags().StringP(flagOutputDir, "o", "./mytestnet",
|
||||
"Directory to store initialization data for the testnet")
|
||||
cmd.Flags().String(flagNodeDirPrefix, "node",
|
||||
"Prefix the directory name for each node with (node results in node0, node1, ...)")
|
||||
cmd.Flags().String(flagNodeDaemonHome, "wasmd",
|
||||
"Home directory of the node's daemon configuration")
|
||||
cmd.Flags().String(flagNodeCLIHome, "wasmcli",
|
||||
"Home directory of the node's cli configuration")
|
||||
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1",
|
||||
"Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
|
||||
cmd.Flags().String(
|
||||
flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(
|
||||
server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom),
|
||||
"Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)")
|
||||
cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
|
||||
return cmd
|
||||
}
|
||||
|
||||
const nodeDirPerm = 0755
|
||||
|
||||
// Initialize the testnet
|
||||
func InitTestnet(cmd *cobra.Command, config *tmconfig.Config, cdc *codec.Codec,
|
||||
mbm module.BasicManager, genAccIterator genutiltypes.GenesisAccountsIterator,
|
||||
outputDir, chainID, minGasPrices, nodeDirPrefix, nodeDaemonHome,
|
||||
nodeCLIHome, startingIPAddress string, numValidators int) error {
|
||||
|
||||
if chainID == "" {
|
||||
chainID = "chain-" + tmrand.Str(6)
|
||||
}
|
||||
|
||||
monikers := make([]string, numValidators)
|
||||
nodeIDs := make([]string, numValidators)
|
||||
valPubKeys := make([]crypto.PubKey, numValidators)
|
||||
|
||||
wasmConfig := srvconfig.DefaultConfig()
|
||||
wasmConfig.MinGasPrices = minGasPrices
|
||||
|
||||
//nolint:prealloc
|
||||
var (
|
||||
genAccounts []authexported.GenesisAccount
|
||||
genFiles []string
|
||||
)
|
||||
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
// generate private keys, node IDs, and initial transactions
|
||||
for i := 0; i < numValidators; i++ {
|
||||
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
|
||||
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome)
|
||||
clientDir := filepath.Join(outputDir, nodeDirName, nodeCLIHome)
|
||||
gentxsDir := filepath.Join(outputDir, "gentxs")
|
||||
|
||||
config.SetRoot(nodeDir)
|
||||
config.RPC.ListenAddress = "tcp://0.0.0.0:26657"
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm); err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(clientDir, nodeDirPerm); err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
monikers = append(monikers, nodeDirName)
|
||||
config.Moniker = nodeDirName
|
||||
|
||||
ip, err := getIP(i, startingIPAddress)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
nodeIDs[i], valPubKeys[i], err = genutil.InitializeNodeValidatorFiles(config)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip)
|
||||
genFiles = append(genFiles, config.GenesisFile())
|
||||
|
||||
kb, err := keys.NewKeyring(
|
||||
sdk.KeyringServiceName(),
|
||||
viper.GetString(flags.FlagKeyringBackend),
|
||||
viper.GetString(flagClientHome),
|
||||
inBuf,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keyPass := clientkeys.DefaultKeyPass
|
||||
addr, secret, err := server.GenerateSaveCoinKey(kb, nodeDirName, keyPass, true)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
info := map[string]string{"secret": secret}
|
||||
|
||||
cliPrint, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// save private key seed words
|
||||
if err := writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, cliPrint); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accTokens := sdk.TokensFromConsensusPower(1000)
|
||||
accStakingTokens := sdk.TokensFromConsensusPower(500)
|
||||
coins := sdk.Coins{
|
||||
sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), accTokens),
|
||||
sdk.NewCoin(sdk.DefaultBondDenom, accStakingTokens),
|
||||
}
|
||||
genAccounts = append(genAccounts, auth.NewBaseAccount(addr, coins.Sort(), nil, 0, 0))
|
||||
|
||||
valTokens := sdk.TokensFromConsensusPower(100)
|
||||
msg := staking.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr),
|
||||
valPubKeys[i],
|
||||
sdk.NewCoin(sdk.DefaultBondDenom, valTokens),
|
||||
staking.NewDescription(nodeDirName, "", "", "", ""),
|
||||
staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
sdk.OneInt(),
|
||||
)
|
||||
|
||||
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo)
|
||||
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithChainID(chainID).WithMemo(memo).WithKeybase(kb)
|
||||
|
||||
signedTx, err := txBldr.SignStdTx(nodeDirName, clientkeys.DefaultKeyPass, tx, false)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
txBytes, err := cdc.MarshalJSON(signedTx)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
// gather gentxs folder
|
||||
if err := writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBytes); err != nil {
|
||||
_ = os.RemoveAll(outputDir)
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: Rename config file to server.toml as it's not particular to Gaia
|
||||
// (REF: https://github.com/cosmos/cosmos-sdk/issues/4125).
|
||||
wasmConfigFilePath := filepath.Join(nodeDir, "config/wasmd.toml")
|
||||
srvconfig.WriteConfigFile(wasmConfigFilePath, wasmConfig)
|
||||
}
|
||||
|
||||
if err := initGenFiles(cdc, mbm, chainID, genAccounts, genFiles, numValidators); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := collectGenFiles(
|
||||
cdc, config, chainID, monikers, nodeIDs, valPubKeys, numValidators,
|
||||
outputDir, nodeDirPrefix, nodeDaemonHome, genAccIterator,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.PrintErrf("Successfully initialized %d node directories\n", numValidators)
|
||||
return nil
|
||||
}
|
||||
|
||||
func initGenFiles(
|
||||
cdc *codec.Codec, mbm module.BasicManager, chainID string,
|
||||
genAccounts []authexported.GenesisAccount, genFiles []string, numValidators int,
|
||||
) error {
|
||||
|
||||
appGenState := mbm.DefaultGenesis()
|
||||
|
||||
// set the accounts in the genesis state
|
||||
authDataBz := appGenState[auth.ModuleName]
|
||||
var authGenState auth.GenesisState
|
||||
cdc.MustUnmarshalJSON(authDataBz, &authGenState)
|
||||
authGenState.Accounts = genAccounts
|
||||
appGenState[auth.ModuleName] = cdc.MustMarshalJSON(authGenState)
|
||||
|
||||
appGenStateJSON, err := codec.MarshalJSONIndent(cdc, appGenState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genDoc := types.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
AppState: appGenStateJSON,
|
||||
Validators: nil,
|
||||
}
|
||||
|
||||
// generate empty genesis files for each validator and save
|
||||
for i := 0; i < numValidators; i++ {
|
||||
if err := genDoc.SaveAs(genFiles[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func collectGenFiles(
|
||||
cdc *codec.Codec, config *tmconfig.Config, chainID string,
|
||||
monikers, nodeIDs []string, valPubKeys []crypto.PubKey,
|
||||
numValidators int, outputDir, nodeDirPrefix, nodeDaemonHome string,
|
||||
genAccIterator genutiltypes.GenesisAccountsIterator) error {
|
||||
|
||||
var appState json.RawMessage
|
||||
genTime := tmtime.Now()
|
||||
|
||||
for i := 0; i < numValidators; i++ {
|
||||
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
|
||||
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome)
|
||||
gentxsDir := filepath.Join(outputDir, "gentxs")
|
||||
moniker := monikers[i]
|
||||
config.Moniker = nodeDirName
|
||||
|
||||
config.SetRoot(nodeDir)
|
||||
|
||||
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
|
||||
initCfg := genutil.NewInitConfig(chainID, gentxsDir, moniker, nodeID, valPubKey)
|
||||
|
||||
genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeAppState, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genAccIterator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if appState == nil {
|
||||
// set the canonical application state (they should not differ)
|
||||
appState = nodeAppState
|
||||
}
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
|
||||
// overwrite each validator's genesis file to have a canonical genesis time
|
||||
if err := genutil.ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getIP(i int, startingIPAddr string) (ip string, err error) {
|
||||
if len(startingIPAddr) == 0 {
|
||||
ip, err = server.ExternalIP()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
return calculateIP(startingIPAddr, i)
|
||||
}
|
||||
|
||||
func calculateIP(ip string, i int) (string, error) {
|
||||
ipv4 := net.ParseIP(ip).To4()
|
||||
if ipv4 == nil {
|
||||
return "", fmt.Errorf("%v: non ipv4 address", ip)
|
||||
}
|
||||
|
||||
for j := 0; j < i; j++ {
|
||||
ipv4[3]++
|
||||
}
|
||||
|
||||
return ipv4.String(), nil
|
||||
}
|
||||
|
||||
func writeFile(name string, dir string, contents []byte) error {
|
||||
writePath := filepath.Join(dir)
|
||||
file := filepath.Join(writePath, name)
|
||||
|
||||
err := tmos.EnsureDir(writePath, 0700)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tmos.WriteFile(file, contents, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
10
docker/run_wasmgovd.sh
Executable file
10
docker/run_wasmgovd.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
if test -n "$1"; then
|
||||
# need -R not -r to copy hidden files
|
||||
cp -R "$1/.wasmd" /root
|
||||
cp -R "$1/.wasmcli" /root
|
||||
fi
|
||||
|
||||
mkdir -p /root/log
|
||||
wasmgovd start --rpc.laddr tcp://0.0.0.0:26657 --trace
|
||||
24
docker/setup_wasmgovd.sh
Executable file
24
docker/setup_wasmgovd.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
#set -o errexit -o nounset -o pipefail
|
||||
|
||||
PASSWORD=${PASSWORD:-1234567890}
|
||||
STAKE=${STAKE_TOKEN:-ustake}
|
||||
FEE=${FEE_TOKEN:-ucosm}
|
||||
|
||||
wasmgovd init --chain-id=testing testing
|
||||
sed -i 's/permission": "Everybody"/permission": "Nobody"/' "$HOME"/.wasmgovd/config/genesis.json
|
||||
# staking/governance token is hardcoded in config, change this
|
||||
sed -i "s/\"stake\"/\"$STAKE\"/" "$HOME"/.wasmgovd/config/genesis.json
|
||||
if ! wasmcli keys show validator; then
|
||||
(echo "$PASSWORD"; echo "$PASSWORD") | wasmcli keys add validator
|
||||
fi
|
||||
# hardcode the validator account for this instance
|
||||
echo "$PASSWORD" | wasmgovd add-genesis-account validator "1000000000$STAKE,1000000000$FEE"
|
||||
# (optionally) add a few more genesis accounts
|
||||
for addr in "$@"; do
|
||||
echo $addr
|
||||
wasmgovd add-genesis-account "$addr" "1000000000$STAKE,1000000000$FEE"
|
||||
done
|
||||
# submit a genesis validator tx
|
||||
(echo "$PASSWORD"; echo "$PASSWORD"; echo "$PASSWORD") | wasmgovd gentx --name validator --amount "250000000$STAKE"
|
||||
wasmgovd collect-gentxs
|
||||
File diff suppressed because one or more lines are too long
@@ -306,7 +306,7 @@ func TestInstantiate(t *testing.T) {
|
||||
require.Equal(t, "cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5", addr.String())
|
||||
|
||||
gasAfter := ctx.GasMeter().GasConsumed()
|
||||
require.Equal(t, uint64(0x11542), gasAfter-gasBefore)
|
||||
require.Equal(t, uint64(0x1155d), gasAfter-gasBefore)
|
||||
|
||||
// ensure it is stored properly
|
||||
info := keeper.GetContractInfo(ctx, addr)
|
||||
@@ -527,7 +527,7 @@ func TestExecute(t *testing.T) {
|
||||
|
||||
// make sure gas is properly deducted from ctx
|
||||
gasAfter := ctx.GasMeter().GasConsumed()
|
||||
require.Equal(t, uint64(0x11bfb), gasAfter-gasBefore)
|
||||
require.Equal(t, uint64(0x11c16), gasAfter-gasBefore)
|
||||
|
||||
// ensure bob now exists and got both payments released
|
||||
bobAcct = accKeeper.GetAccount(ctx, bob)
|
||||
|
||||
@@ -36,7 +36,14 @@ func FuzzStateModel(m *types.Model, c fuzz.Continue) {
|
||||
}
|
||||
|
||||
func FuzzAccessType(m *types.AccessType, c fuzz.Continue) {
|
||||
*m = types.AllAccessTypes[c.Int()%len(types.AllAccessTypes)]
|
||||
pos := c.Int() % len(types.AllAccessTypes)
|
||||
for k, _ := range types.AllAccessTypes {
|
||||
if pos == 0 {
|
||||
*m = k
|
||||
return
|
||||
}
|
||||
pos--
|
||||
}
|
||||
}
|
||||
func FuzzAccessConfig(m *types.AccessConfig, c fuzz.Continue) {
|
||||
FuzzAccessType(&m.Type, c)
|
||||
|
||||
@@ -21,9 +21,9 @@ func (s Sequence) ValidateBasic() error {
|
||||
// GenesisState is the struct representation of the export genesis
|
||||
type GenesisState struct {
|
||||
Params Params `json:"params"`
|
||||
Codes []Code `json:"codes"`
|
||||
Contracts []Contract `json:"contracts"`
|
||||
Sequences []Sequence `json:"sequences"`
|
||||
Codes []Code `json:"codes,omitempty"`
|
||||
Contracts []Contract `json:"contracts,omitempty"`
|
||||
Sequences []Sequence `json:"sequences,omitempty"`
|
||||
}
|
||||
|
||||
func (s GenesisState) ValidateBasic() error {
|
||||
|
||||
@@ -18,16 +18,20 @@ const (
|
||||
var ParamStoreKeyUploadAccess = []byte("uploadAccess")
|
||||
var ParamStoreKeyInstantiateAccess = []byte("instantiateAccess")
|
||||
|
||||
type AccessType uint8
|
||||
type AccessType string
|
||||
|
||||
const (
|
||||
Undefined AccessType = 0
|
||||
Nobody AccessType = 1
|
||||
OnlyAddress AccessType = 2
|
||||
Everybody AccessType = 3
|
||||
Undefined AccessType = "Undefined"
|
||||
Nobody AccessType = "Nobody"
|
||||
OnlyAddress AccessType = "OnlyAddress"
|
||||
Everybody AccessType = "Everybody"
|
||||
)
|
||||
|
||||
var AllAccessTypes = []AccessType{Nobody, OnlyAddress, Everybody}
|
||||
var AllAccessTypes = map[AccessType]struct{}{
|
||||
Nobody: {},
|
||||
OnlyAddress: {},
|
||||
Everybody: {},
|
||||
}
|
||||
|
||||
func (a AccessType) With(addr sdk.AccAddress) AccessConfig {
|
||||
switch a {
|
||||
@@ -44,9 +48,26 @@ func (a AccessType) With(addr sdk.AccAddress) AccessConfig {
|
||||
panic("unsupported access type")
|
||||
}
|
||||
|
||||
func (a *AccessType) UnmarshalText(text []byte) error {
|
||||
s := AccessType(text)
|
||||
if _, ok := AllAccessTypes[s]; ok {
|
||||
*a = s
|
||||
return nil
|
||||
}
|
||||
*a = Undefined
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AccessType) MarshalText() ([]byte, error) {
|
||||
if _, ok := AllAccessTypes[a]; ok {
|
||||
return []byte(a), nil
|
||||
}
|
||||
return []byte(Undefined), nil
|
||||
}
|
||||
|
||||
type AccessConfig struct {
|
||||
Type AccessType `json:"type" yaml:"type"`
|
||||
Address sdk.AccAddress `json:"address" yaml:"address"`
|
||||
Type AccessType `json:"permission" yaml:"permission"`
|
||||
Address sdk.AccAddress `json:"address,omitempty" yaml:"address"`
|
||||
}
|
||||
|
||||
func (a AccessConfig) Equals(o AccessConfig) bool {
|
||||
@@ -61,7 +82,7 @@ var (
|
||||
|
||||
// Params defines the set of wasm parameters.
|
||||
type Params struct {
|
||||
UploadAccess AccessConfig `json:"upload_access" yaml:"upload_access"`
|
||||
UploadAccess AccessConfig `json:"code_upload_access" yaml:"code_upload_access"`
|
||||
DefaultInstantiatePermission AccessType `json:"instantiate_default_permission" yaml:"instantiate_default_permission"`
|
||||
}
|
||||
|
||||
@@ -118,12 +139,10 @@ func validateAccessType(i interface{}) error {
|
||||
if v == Undefined {
|
||||
return sdkerrors.Wrap(ErrEmpty, "type")
|
||||
}
|
||||
for i := range AllAccessTypes {
|
||||
if AllAccessTypes[i] == v {
|
||||
return nil
|
||||
}
|
||||
if _, ok := AllAccessTypes[v]; !ok {
|
||||
return sdkerrors.Wrapf(ErrInvalid, "unknown type: %q", v)
|
||||
}
|
||||
return sdkerrors.Wrapf(ErrInvalid, "unknown type: %d", v)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v AccessConfig) ValidateBasic() error {
|
||||
@@ -138,7 +157,7 @@ func (v AccessConfig) ValidateBasic() error {
|
||||
case OnlyAddress:
|
||||
return sdk.VerifyAddressFormat(v.Address)
|
||||
}
|
||||
return sdkerrors.Wrapf(ErrInvalid, "unknown type: %d", v.Type)
|
||||
return sdkerrors.Wrapf(ErrInvalid, "unknown type: %q", v.Type)
|
||||
}
|
||||
|
||||
func (v AccessConfig) Allowed(actor sdk.AccAddress) bool {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -41,14 +43,14 @@ func TestValidateParams(t *testing.T) {
|
||||
"reject empty type in instantiate permission": {
|
||||
src: Params{
|
||||
UploadAccess: AllowNobody,
|
||||
DefaultInstantiatePermission: 0,
|
||||
DefaultInstantiatePermission: "",
|
||||
},
|
||||
expErr: true,
|
||||
},
|
||||
"reject unknown type in instantiate": {
|
||||
src: Params{
|
||||
UploadAccess: AllowNobody,
|
||||
DefaultInstantiatePermission: 4,
|
||||
DefaultInstantiatePermission: "Undefined",
|
||||
},
|
||||
expErr: true,
|
||||
},
|
||||
@@ -84,5 +86,44 @@ func TestValidateParams(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestAccessTypeMarshalJson(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
src AccessType
|
||||
exp string
|
||||
}{
|
||||
"Undefined": {src: Undefined, exp: `"Undefined"`},
|
||||
"Nobody": {src: Nobody, exp: `"Nobody"`},
|
||||
"OnlyAddress": {src: OnlyAddress, exp: `"OnlyAddress"`},
|
||||
"Everybody": {src: Everybody, exp: `"Everybody"`},
|
||||
"unknown": {src: "", exp: `"Undefined"`},
|
||||
}
|
||||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
got, err := json.Marshal(spec.src)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []byte(spec.exp), got)
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestAccessTypeUnMarshalJson(t *testing.T) {
|
||||
specs := map[string]struct {
|
||||
src string
|
||||
exp AccessType
|
||||
}{
|
||||
"Undefined": {src: `"Undefined"`, exp: Undefined},
|
||||
"Nobody": {src: `"Nobody"`, exp: Nobody},
|
||||
"OnlyAddress": {src: `"OnlyAddress"`, exp: OnlyAddress},
|
||||
"Everybody": {src: `"Everybody"`, exp: Everybody},
|
||||
"unknown": {src: `""`, exp: Undefined},
|
||||
}
|
||||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
var got AccessType
|
||||
err := json.Unmarshal([]byte(spec.src), &got)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, spec.exp, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user