Merge branch 'dev/lock_tools' of github.com:cosmos/cosmos-sdk into dev/lock_tools
This commit is contained in:
commit
586c191422
|
@ -2,6 +2,9 @@
|
|||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
*.swl
|
||||
*.swm
|
||||
*.swn
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
|
|
|
@ -87,8 +87,14 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *
|
|||
}
|
||||
|
||||
// PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
|
||||
func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (err error) {
|
||||
stdTx, err := buildUnsignedStdTx(txBldr, cliCtx, msgs)
|
||||
// Don't perform online validation or lookups if offline is true.
|
||||
func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg, offline bool) (err error) {
|
||||
var stdTx auth.StdTx
|
||||
if offline {
|
||||
stdTx, err = buildUnsignedStdTxOffline(txBldr, cliCtx, msgs)
|
||||
} else {
|
||||
stdTx, err = buildUnsignedStdTx(txBldr, cliCtx, msgs)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -204,6 +210,10 @@ func buildUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
return buildUnsignedStdTxOffline(txBldr, cliCtx, msgs)
|
||||
}
|
||||
|
||||
func buildUnsignedStdTxOffline(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg) (stdTx auth.StdTx, err error) {
|
||||
if txBldr.SimulateGas {
|
||||
var name string
|
||||
name, err = cliCtx.GetFromName()
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
)
|
||||
|
||||
|
@ -28,10 +29,12 @@ func main() {
|
|||
Short: "Gaia Daemon (server)",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||
}
|
||||
appInit := app.GaiaAppInit()
|
||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(),
|
||||
server.ConstructAppCreator(newApp, "gaia"),
|
||||
server.ConstructAppExporter(exportAppStateAndTMValidators, "gaia"))
|
||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||
newApp, exportAppStateAndTMValidators)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
|
||||
|
|
|
@ -0,0 +1,321 @@
|
|||
package init
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
servercfg "github.com/cosmos/cosmos-sdk/server/config"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
func GenTxCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "gen-tx",
|
||||
Short: "Create genesis transaction file (under [--home]/config/gentx/gentx-[nodeID].json)",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
|
||||
ip := viper.GetString(server.FlagIP)
|
||||
if len(ip) == 0 {
|
||||
eip, err := server.ExternalIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip = eip
|
||||
}
|
||||
|
||||
genTxConfig := servercfg.GenTx{
|
||||
viper.GetString(server.FlagName),
|
||||
viper.GetString(server.FlagClientHome),
|
||||
viper.GetBool(server.FlagOWK),
|
||||
ip,
|
||||
}
|
||||
cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toPrint := struct {
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
GenTxFile json.RawMessage `json:"gen_tx_file"`
|
||||
}{
|
||||
cliPrint,
|
||||
genTxFile,
|
||||
}
|
||||
out, err := codec.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().String(server.FlagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine")
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// NOTE: This will update (write) the config file with
|
||||
// updated name (moniker) for node.
|
||||
func gentxWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, genTxConfig servercfg.GenTx) (
|
||||
cliPrint json.RawMessage, genTxFile json.RawMessage, err error) {
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nodeID := string(nodeKey.ID())
|
||||
pubKey := readOrCreatePrivValidator(config)
|
||||
|
||||
appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tx := server.GenesisTx{
|
||||
NodeID: nodeID,
|
||||
IP: genTxConfig.IP,
|
||||
Validator: validator,
|
||||
AppGenTx: appGenTx,
|
||||
}
|
||||
bz, err := codec.MarshalJSONIndent(cdc, tx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxFile = json.RawMessage(bz)
|
||||
name := fmt.Sprintf("gentx-%v.json", nodeID)
|
||||
writePath := filepath.Join(config.RootDir, "config", "gentx")
|
||||
file := filepath.Join(writePath, name)
|
||||
err = common.EnsureDir(writePath, 0700)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = common.WriteFile(file, bz, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Write updated config with moniker
|
||||
config.Moniker = genTxConfig.Name
|
||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
// nolint: golint
|
||||
func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
initConfig := server.InitConfig{
|
||||
viper.GetString(server.FlagChainID),
|
||||
viper.GetBool(server.FlagWithTxs),
|
||||
filepath.Join(config.RootDir, "config", "gentx"),
|
||||
viper.GetBool(server.FlagOverwrite),
|
||||
}
|
||||
|
||||
chainID, nodeID, appMessage, err := initWithConfig(cdc, appInit, config, initConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// print out some key information
|
||||
toPrint := struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
NodeID string `json:"node_id"`
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
}{
|
||||
chainID,
|
||||
nodeID,
|
||||
appMessage,
|
||||
}
|
||||
out, err := codec.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().BoolP(server.FlagOverwrite, "o", false, "overwrite the genesis.json file")
|
||||
cmd.Flags().String(server.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().Bool(server.FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/")
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenState)
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided
|
||||
cmd.AddCommand(GenTxCmd(ctx, cdc, appInit))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func initWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, initConfig server.InitConfig) (
|
||||
chainID string, nodeID string, appMessage json.RawMessage, err error) {
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nodeID = string(nodeKey.ID())
|
||||
pubKey := readOrCreatePrivValidator(config)
|
||||
|
||||
if initConfig.ChainID == "" {
|
||||
initConfig.ChainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
|
||||
}
|
||||
chainID = initConfig.ChainID
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
if !initConfig.Overwrite && common.FileExists(genFile) {
|
||||
err = fmt.Errorf("genesis.json file already exists: %v", genFile)
|
||||
return
|
||||
}
|
||||
|
||||
// process genesis transactions, or otherwise create one for defaults
|
||||
var appGenTxs []json.RawMessage
|
||||
var validators []types.GenesisValidator
|
||||
var persistentPeers string
|
||||
|
||||
if initConfig.GenTxs {
|
||||
validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config.P2P.PersistentPeers = persistentPeers
|
||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
} else {
|
||||
genTxConfig := servercfg.GenTx{
|
||||
viper.GetString(server.FlagName),
|
||||
viper.GetString(server.FlagClientHome),
|
||||
viper.GetBool(server.FlagOWK),
|
||||
"127.0.0.1",
|
||||
}
|
||||
|
||||
// Write updated config with moniker
|
||||
config.Moniker = genTxConfig.Name
|
||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig)
|
||||
appMessage = am
|
||||
if err != nil {
|
||||
return "", "", nil, err
|
||||
}
|
||||
validators = []types.GenesisValidator{validator}
|
||||
appGenTxs = []json.RawMessage{appGenTx}
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, appGenTxs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = writeGenesisFile(cdc, genFile, initConfig.ChainID, validators, appState)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// append a genesis-piece
|
||||
func processGenTxs(genTxsDir string, cdc *codec.Codec) (
|
||||
validators []types.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) {
|
||||
|
||||
var fos []os.FileInfo
|
||||
fos, err = ioutil.ReadDir(genTxsDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
genTxs := make(map[string]server.GenesisTx)
|
||||
var nodeIDs []string
|
||||
for _, fo := range fos {
|
||||
filename := path.Join(genTxsDir, fo.Name())
|
||||
if !fo.IsDir() && (path.Ext(filename) != ".json") {
|
||||
continue
|
||||
}
|
||||
|
||||
// get the genTx
|
||||
var bz []byte
|
||||
bz, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var genTx server.GenesisTx
|
||||
err = cdc.UnmarshalJSON(bz, &genTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
genTxs[genTx.NodeID] = genTx
|
||||
nodeIDs = append(nodeIDs, genTx.NodeID)
|
||||
}
|
||||
|
||||
sort.Strings(nodeIDs)
|
||||
|
||||
for _, nodeID := range nodeIDs {
|
||||
genTx := genTxs[nodeID]
|
||||
|
||||
// combine some stuff
|
||||
validators = append(validators, genTx.Validator)
|
||||
appGenTxs = append(appGenTxs, genTx.AppGenTx)
|
||||
|
||||
// Add a persistent peer
|
||||
comma := ","
|
||||
if len(persistentPeers) == 0 {
|
||||
comma = ""
|
||||
}
|
||||
persistentPeers += fmt.Sprintf("%s%s@%s:26656", comma, genTx.NodeID, genTx.IP)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// read of create the private key file for this config
|
||||
func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
|
||||
// private validator
|
||||
privValFile := tmConfig.PrivValidatorFile()
|
||||
var privValidator *privval.FilePV
|
||||
if common.FileExists(privValFile) {
|
||||
privValidator = privval.LoadFilePV(privValFile)
|
||||
} else {
|
||||
privValidator = privval.GenFilePV(privValFile)
|
||||
privValidator.Save()
|
||||
}
|
||||
return privValidator.GetPubKey()
|
||||
}
|
||||
|
||||
// writeGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// error is returned if building or writing the configuration to file fails.
|
||||
// nolint: unparam
|
||||
func writeGenesisFile(cdc *codec.Codec, genesisFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage) error {
|
||||
genDoc := types.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
Validators: validators,
|
||||
AppState: appState,
|
||||
}
|
||||
|
||||
if err := genDoc.ValidateAndComplete(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return genDoc.SaveAs(genesisFile)
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package init
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
abciServer "github.com/tendermint/tendermint/abci/server"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
)
|
||||
|
||||
func TestInitCmd(t *testing.T) {
|
||||
defer server.SetupViper(t)()
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := server.NewContext(cfg, logger)
|
||||
cdc := codec.New()
|
||||
appInit := server.AppInit{
|
||||
AppGenState: mock.AppGenState,
|
||||
AppGenTx: mock.AppGenTx,
|
||||
}
|
||||
cmd := InitCmd(ctx, cdc, appInit)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestEmptyState(t *testing.T) {
|
||||
defer server.SetupViper(t)()
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := server.NewContext(cfg, logger)
|
||||
cdc := codec.New()
|
||||
appInit := server.AppInit{
|
||||
AppGenTx: mock.AppGenTx,
|
||||
AppGenState: mock.AppGenStateEmpty,
|
||||
}
|
||||
cmd := InitCmd(ctx, cdc, appInit)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
cmd = server.ExportCmd(ctx, cdc, nil)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
outC := make(chan string)
|
||||
go func() {
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
outC <- buf.String()
|
||||
}()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
out := <-outC
|
||||
require.Contains(t, out, "WARNING: State is not initialized")
|
||||
require.Contains(t, out, "genesis_time")
|
||||
require.Contains(t, out, "chain_id")
|
||||
require.Contains(t, out, "consensus_params")
|
||||
require.Contains(t, out, "validators")
|
||||
require.Contains(t, out, "app_hash")
|
||||
}
|
||||
|
||||
func TestStartStandAlone(t *testing.T) {
|
||||
home, err := ioutil.TempDir("", "mock-sdk-cmd")
|
||||
require.Nil(t, err)
|
||||
defer func() {
|
||||
os.RemoveAll(home)
|
||||
}()
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := server.NewContext(cfg, logger)
|
||||
cdc := codec.New()
|
||||
appInit := server.AppInit{
|
||||
AppGenState: mock.AppGenState,
|
||||
AppGenTx: mock.AppGenTx,
|
||||
}
|
||||
initCmd := InitCmd(ctx, cdc, appInit)
|
||||
err = initCmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
app, err := mock.NewApp(home, logger)
|
||||
require.Nil(t, err)
|
||||
svrAddr, _, err := server.FreeTCPAddr()
|
||||
require.Nil(t, err)
|
||||
svr, err := abciServer.NewServer(svrAddr, "socket", app)
|
||||
require.Nil(t, err, "error creating listener")
|
||||
svr.SetLogger(logger.With("module", "abci-server"))
|
||||
svr.Start()
|
||||
|
||||
timer := time.NewTimer(time.Duration(2) * time.Second)
|
||||
select {
|
||||
case <-timer.C:
|
||||
svr.Stop()
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
package server
|
||||
package init
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"net"
|
||||
"path/filepath"
|
||||
|
||||
|
@ -30,7 +31,7 @@ var (
|
|||
const nodeDirPerm = 0755
|
||||
|
||||
// get cmd to initialize all files for tendermint testnet and application
|
||||
func TestnetFilesCmd(ctx *Context, cdc *codec.Codec, appInit AppInit) *cobra.Command {
|
||||
func TestnetFilesCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "testnet",
|
||||
Short: "Initialize files for a Gaiad testnet",
|
||||
|
@ -65,7 +66,7 @@ Example:
|
|||
return cmd
|
||||
}
|
||||
|
||||
func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit AppInit) error {
|
||||
func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppInit) error {
|
||||
outDir := viper.GetString(outputDir)
|
||||
numValidators := viper.GetInt(nValidators)
|
||||
|
||||
|
@ -133,7 +134,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit AppInit) er
|
|||
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
|
||||
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
|
||||
gentxsDir := filepath.Join(outDir, "gentxs")
|
||||
initConfig := InitConfig{
|
||||
initConfig := server.InitConfig{
|
||||
chainID,
|
||||
true,
|
||||
gentxsDir,
|
||||
|
@ -156,7 +157,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit AppInit) er
|
|||
func getIP(i int) (ip string, err error) {
|
||||
ip = viper.GetString(startingIPAddress)
|
||||
if len(ip) == 0 {
|
||||
ip, err = externalIP()
|
||||
ip, err = server.ExternalIP()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
|
@ -8,7 +8,7 @@ The core IBC protocol is payload-agnostic. On top of IBC, developers can impleme
|
|||
|
||||
IBC requires two blockchains with cheaply verifiable rapid finality and Merkle tree substate proofs. The protocol makes no assumptions of block confirmation times or maximum network latency of packet transmissions, and the two consensus algorithms remain completely independent. Each chain maintains a local partial order and inter-chain message sequencing ensures cross-chain linearity. Once the two chains have registered a trust relationship, cryptographically verifiable packets can be sent between them.
|
||||
|
||||
IBC was first outlined in the [Cosmos Whitepaper](https://github.com/cosmos/cosmos/blob/master/WHITEPAPER.md#inter-blockchain-communication-ibc), and later described in more detail by the [IBC specification paper](https://github.com/cosmos/ibc/raw/master/CosmosIBCSpecification.pdf). This document supersedes both. It explains the requirements and structure of the protocol and provides sufficient detail for both analysis and implementation.
|
||||
IBC was first outlined in the [Cosmos Whitepaper](https://github.com/cosmos/cosmos/blob/master/WHITEPAPER.md#inter-blockchain-communication-ibc), and later described in more detail by the [IBC specification paper](https://github.com/cosmos/ibc/blob/master/CosmosIBCSpecification.pdf). This document supersedes both. It explains the requirements and structure of the protocol and provides sufficient detail for both analysis and implementation.
|
||||
|
||||
## Contents
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
|
@ -28,9 +29,12 @@ func main() {
|
|||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||
}
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit,
|
||||
server.ConstructAppCreator(newApp, "basecoin"),
|
||||
server.ConstructAppExporter(exportAppStateAndTMValidators, "basecoin"))
|
||||
appInit := server.DefaultAppInit
|
||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||
newApp, exportAppStateAndTMValidators)
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.basecoind")
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
|
@ -70,9 +71,11 @@ func main() {
|
|||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||
}
|
||||
|
||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, CoolAppInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, CoolAppInit))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
|
||||
server.ConstructAppCreator(newApp, "democoin"),
|
||||
server.ConstructAppExporter(exportAppStateAndTMValidators, "democoin"))
|
||||
newApp, exportAppStateAndTMValidators)
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.democoind")
|
||||
|
|
|
@ -13,72 +13,29 @@ import (
|
|||
)
|
||||
|
||||
type (
|
||||
// AppCreator reflects a function that allows us to lazily initialize an
|
||||
// AppCreator is a function that allows us to lazily initialize an
|
||||
// application using various configurations.
|
||||
AppCreator func(home string, logger log.Logger, traceStore string) (abci.Application, error)
|
||||
AppCreator func(log.Logger, dbm.DB, io.Writer) abci.Application
|
||||
|
||||
// AppExporter reflects a function that dumps all app state to
|
||||
// AppExporter is a function that dumps all app state to
|
||||
// JSON-serializable structure and returns the current validator set.
|
||||
AppExporter func(home string, logger log.Logger, traceStore string) (json.RawMessage, []tmtypes.GenesisValidator, error)
|
||||
|
||||
// AppCreatorInit reflects a function that performs initialization of an
|
||||
// AppCreator.
|
||||
AppCreatorInit func(log.Logger, dbm.DB, io.Writer) abci.Application
|
||||
|
||||
// AppExporterInit reflects a function that performs initialization of an
|
||||
// AppExporter.
|
||||
AppExporterInit func(log.Logger, dbm.DB, io.Writer) (json.RawMessage, []tmtypes.GenesisValidator, error)
|
||||
AppExporter func(log.Logger, dbm.DB, io.Writer) (json.RawMessage, []tmtypes.GenesisValidator, error)
|
||||
)
|
||||
|
||||
// ConstructAppCreator returns an application generation function.
|
||||
func ConstructAppCreator(appFn AppCreatorInit, name string) AppCreator {
|
||||
return func(rootDir string, logger log.Logger, traceStore string) (abci.Application, error) {
|
||||
func openDB(rootDir string) (dbm.DB, error) {
|
||||
dataDir := filepath.Join(rootDir, "data")
|
||||
db, err := dbm.NewGoLevelDB("application", dataDir)
|
||||
return db, err
|
||||
}
|
||||
|
||||
db, err := dbm.NewGoLevelDB(name, dataDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var traceStoreWriter io.Writer
|
||||
if traceStore != "" {
|
||||
traceStoreWriter, err = os.OpenFile(
|
||||
traceStore,
|
||||
func openTraceWriter(traceWriterFile string) (w io.Writer, err error) {
|
||||
if traceWriterFile != "" {
|
||||
w, err = os.OpenFile(
|
||||
traceWriterFile,
|
||||
os.O_WRONLY|os.O_APPEND|os.O_CREATE,
|
||||
0666,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
app := appFn(logger, db, traceStoreWriter)
|
||||
return app, nil
|
||||
}
|
||||
}
|
||||
|
||||
// ConstructAppExporter returns an application export function.
|
||||
func ConstructAppExporter(appFn AppExporterInit, name string) AppExporter {
|
||||
return func(rootDir string, logger log.Logger, traceStore string) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
dataDir := filepath.Join(rootDir, "data")
|
||||
|
||||
db, err := dbm.NewGoLevelDB(name, dataDir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var traceStoreWriter io.Writer
|
||||
if traceStore != "" {
|
||||
traceStoreWriter, err = os.OpenFile(
|
||||
traceStore,
|
||||
os.O_WRONLY|os.O_APPEND|os.O_CREATE,
|
||||
0666,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return appFn(logger, db, traceStoreWriter)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ func ExportCmd(ctx *Context, cdc *codec.Codec, appExporter AppExporter) *cobra.C
|
|||
Short: "Export state to JSON",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
home := viper.GetString("home")
|
||||
traceStore := viper.GetString(flagTraceStore)
|
||||
traceWriterFile := viper.GetString(flagTraceStore)
|
||||
emptyState, err := isEmptyState(home)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -37,7 +37,15 @@ func ExportCmd(ctx *Context, cdc *codec.Codec, appExporter AppExporter) *cobra.C
|
|||
return nil
|
||||
}
|
||||
|
||||
appState, validators, err := appExporter(home, ctx.Logger, traceStore)
|
||||
db, err := openDB(home)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
traceWriter, err := openTraceWriter(traceWriterFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appState, validators, err := appExporter(ctx.Logger, db, traceWriter)
|
||||
if err != nil {
|
||||
return errors.Errorf("error exporting state: %v\n", err)
|
||||
}
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEmptyState(t *testing.T) {
|
||||
defer setupViper(t)()
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
cdc := codec.New()
|
||||
appInit := AppInit{
|
||||
AppGenTx: mock.AppGenTx,
|
||||
AppGenState: mock.AppGenStateEmpty,
|
||||
}
|
||||
cmd := InitCmd(ctx, cdc, appInit)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
old := os.Stdout
|
||||
r, w, _ := os.Pipe()
|
||||
os.Stdout = w
|
||||
cmd = ExportCmd(ctx, cdc, nil)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
outC := make(chan string)
|
||||
go func() {
|
||||
var buf bytes.Buffer
|
||||
io.Copy(&buf, r)
|
||||
outC <- buf.String()
|
||||
}()
|
||||
|
||||
w.Close()
|
||||
os.Stdout = old
|
||||
out := <-outC
|
||||
require.Contains(t, out, "WARNING: State is not initialized")
|
||||
require.Contains(t, out, "genesis_time")
|
||||
require.Contains(t, out, "chain_id")
|
||||
require.Contains(t, out, "consensus_params")
|
||||
require.Contains(t, out, "validators")
|
||||
require.Contains(t, out, "app_hash")
|
||||
}
|
313
server/init.go
313
server/init.go
|
@ -3,26 +3,12 @@ package server
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
pvm "github.com/tendermint/tendermint/privval"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
clkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
|
@ -62,303 +48,8 @@ type InitConfig struct {
|
|||
Overwrite bool
|
||||
}
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
func GenTxCmd(ctx *Context, cdc *codec.Codec, appInit AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "gen-tx",
|
||||
Short: "Create genesis transaction file (under [--home]/config/gentx/gentx-[nodeID].json)",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(tmcli.HomeFlag))
|
||||
|
||||
ip := viper.GetString(FlagIP)
|
||||
if len(ip) == 0 {
|
||||
eip, err := externalIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip = eip
|
||||
}
|
||||
|
||||
genTxConfig := serverconfig.GenTx{
|
||||
viper.GetString(FlagName),
|
||||
viper.GetString(FlagClientHome),
|
||||
viper.GetBool(FlagOWK),
|
||||
ip,
|
||||
}
|
||||
cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toPrint := struct {
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
GenTxFile json.RawMessage `json:"gen_tx_file"`
|
||||
}{
|
||||
cliPrint,
|
||||
genTxFile,
|
||||
}
|
||||
out, err := codec.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().String(FlagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine")
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func gentxWithConfig(cdc *codec.Codec, appInit AppInit, config *cfg.Config, genTxConfig serverconfig.GenTx) (
|
||||
cliPrint json.RawMessage, genTxFile json.RawMessage, err error) {
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nodeID := string(nodeKey.ID())
|
||||
pubKey := readOrCreatePrivValidator(config)
|
||||
|
||||
appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tx := GenesisTx{
|
||||
NodeID: nodeID,
|
||||
IP: genTxConfig.IP,
|
||||
Validator: validator,
|
||||
AppGenTx: appGenTx,
|
||||
}
|
||||
bz, err := codec.MarshalJSONIndent(cdc, tx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxFile = json.RawMessage(bz)
|
||||
name := fmt.Sprintf("gentx-%v.json", nodeID)
|
||||
writePath := filepath.Join(config.RootDir, "config", "gentx")
|
||||
file := filepath.Join(writePath, name)
|
||||
err = cmn.EnsureDir(writePath, 0700)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = cmn.WriteFile(file, bz, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Write updated config with moniker
|
||||
config.Moniker = genTxConfig.Name
|
||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
func InitCmd(ctx *Context, cdc *codec.Codec, appInit AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(tmcli.HomeFlag))
|
||||
initConfig := InitConfig{
|
||||
viper.GetString(FlagChainID),
|
||||
viper.GetBool(FlagWithTxs),
|
||||
filepath.Join(config.RootDir, "config", "gentx"),
|
||||
viper.GetBool(FlagOverwrite),
|
||||
}
|
||||
|
||||
chainID, nodeID, appMessage, err := initWithConfig(cdc, appInit, config, initConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// print out some key information
|
||||
toPrint := struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
NodeID string `json:"node_id"`
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
}{
|
||||
chainID,
|
||||
nodeID,
|
||||
appMessage,
|
||||
}
|
||||
out, err := codec.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().BoolP(FlagOverwrite, "o", false, "overwrite the genesis.json file")
|
||||
cmd.Flags().String(FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().Bool(FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/")
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenState)
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided
|
||||
cmd.AddCommand(GenTxCmd(ctx, cdc, appInit))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func initWithConfig(cdc *codec.Codec, appInit AppInit, config *cfg.Config, initConfig InitConfig) (
|
||||
chainID string, nodeID string, appMessage json.RawMessage, err error) {
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nodeID = string(nodeKey.ID())
|
||||
pubKey := readOrCreatePrivValidator(config)
|
||||
|
||||
if initConfig.ChainID == "" {
|
||||
initConfig.ChainID = fmt.Sprintf("test-chain-%v", cmn.RandStr(6))
|
||||
}
|
||||
chainID = initConfig.ChainID
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
if !initConfig.Overwrite && cmn.FileExists(genFile) {
|
||||
err = fmt.Errorf("genesis.json file already exists: %v", genFile)
|
||||
return
|
||||
}
|
||||
|
||||
// process genesis transactions, or otherwise create one for defaults
|
||||
var appGenTxs []json.RawMessage
|
||||
var validators []tmtypes.GenesisValidator
|
||||
var persistentPeers string
|
||||
|
||||
if initConfig.GenTxs {
|
||||
validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config.P2P.PersistentPeers = persistentPeers
|
||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
} else {
|
||||
genTxConfig := serverconfig.GenTx{
|
||||
viper.GetString(FlagName),
|
||||
viper.GetString(FlagClientHome),
|
||||
viper.GetBool(FlagOWK),
|
||||
"127.0.0.1",
|
||||
}
|
||||
|
||||
// Write updated config with moniker
|
||||
config.Moniker = genTxConfig.Name
|
||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig)
|
||||
appMessage = am
|
||||
if err != nil {
|
||||
return "", "", nil, err
|
||||
}
|
||||
validators = []tmtypes.GenesisValidator{validator}
|
||||
appGenTxs = []json.RawMessage{appGenTx}
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, appGenTxs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = writeGenesisFile(cdc, genFile, initConfig.ChainID, validators, appState)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// append a genesis-piece
|
||||
func processGenTxs(genTxsDir string, cdc *codec.Codec) (
|
||||
validators []tmtypes.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) {
|
||||
|
||||
var fos []os.FileInfo
|
||||
fos, err = ioutil.ReadDir(genTxsDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
genTxs := make(map[string]GenesisTx)
|
||||
var nodeIDs []string
|
||||
for _, fo := range fos {
|
||||
filename := path.Join(genTxsDir, fo.Name())
|
||||
if !fo.IsDir() && (path.Ext(filename) != ".json") {
|
||||
continue
|
||||
}
|
||||
|
||||
// get the genTx
|
||||
var bz []byte
|
||||
bz, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var genTx GenesisTx
|
||||
err = cdc.UnmarshalJSON(bz, &genTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
genTxs[genTx.NodeID] = genTx
|
||||
nodeIDs = append(nodeIDs, genTx.NodeID)
|
||||
}
|
||||
|
||||
sort.Strings(nodeIDs)
|
||||
|
||||
for _, nodeID := range nodeIDs {
|
||||
genTx := genTxs[nodeID]
|
||||
|
||||
// combine some stuff
|
||||
validators = append(validators, genTx.Validator)
|
||||
appGenTxs = append(appGenTxs, genTx.AppGenTx)
|
||||
|
||||
// Add a persistent peer
|
||||
comma := ","
|
||||
if len(persistentPeers) == 0 {
|
||||
comma = ""
|
||||
}
|
||||
persistentPeers += fmt.Sprintf("%s%s@%s:26656", comma, genTx.NodeID, genTx.IP)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
|
||||
// read of create the private key file for this config
|
||||
func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
|
||||
// private validator
|
||||
privValFile := tmConfig.PrivValidatorFile()
|
||||
var privValidator *pvm.FilePV
|
||||
if cmn.FileExists(privValFile) {
|
||||
privValidator = pvm.LoadFilePV(privValFile)
|
||||
} else {
|
||||
privValidator = pvm.GenFilePV(privValFile)
|
||||
privValidator.Save()
|
||||
}
|
||||
return privValidator.GetPubKey()
|
||||
}
|
||||
|
||||
// writeGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// error is returned if building or writing the configuration to file fails.
|
||||
// nolint: unparam
|
||||
func writeGenesisFile(cdc *codec.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error {
|
||||
genDoc := tmtypes.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
Validators: validators,
|
||||
AppState: appState,
|
||||
}
|
||||
|
||||
if err := genDoc.ValidateAndComplete(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return genDoc.SaveAs(genesisFile)
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
|
||||
// Core functionality passed from the application to the server init command
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
)
|
||||
|
||||
// TODO update
|
||||
func TestInitCmd(t *testing.T) {
|
||||
defer setupViper(t)()
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
cdc := codec.New()
|
||||
appInit := AppInit{
|
||||
AppGenState: mock.AppGenState,
|
||||
AppGenTx: mock.AppGenTx,
|
||||
}
|
||||
cmd := InitCmd(ctx, cdc, appInit)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGenTxCmd(t *testing.T) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func TestTestnetFilesCmd(t *testing.T) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func TestSimpleAppGenTx(t *testing.T) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func TestSimpleAppGenState(t *testing.T) {
|
||||
// TODO
|
||||
}
|
|
@ -57,12 +57,18 @@ func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command {
|
|||
func startStandAlone(ctx *Context, appCreator AppCreator) error {
|
||||
addr := viper.GetString(flagAddress)
|
||||
home := viper.GetString("home")
|
||||
traceStore := viper.GetString(flagTraceStore)
|
||||
traceWriterFile := viper.GetString(flagTraceStore)
|
||||
|
||||
app, err := appCreator(home, ctx.Logger, traceStore)
|
||||
db, err := openDB(home)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
traceWriter, err := openTraceWriter(traceWriterFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
app := appCreator(ctx.Logger, db, traceWriter)
|
||||
|
||||
svr, err := server.NewServer(addr, "socket", app)
|
||||
if err != nil {
|
||||
|
@ -91,12 +97,18 @@ func startStandAlone(ctx *Context, appCreator AppCreator) error {
|
|||
func startInProcess(ctx *Context, appCreator AppCreator) (*node.Node, error) {
|
||||
cfg := ctx.Config
|
||||
home := cfg.RootDir
|
||||
traceStore := viper.GetString(flagTraceStore)
|
||||
traceWriterFile := viper.GetString(flagTraceStore)
|
||||
|
||||
app, err := appCreator(home, ctx.Logger, traceStore)
|
||||
db, err := openDB(home)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
traceWriter, err := openTraceWriter(traceWriterFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
app := appCreator(ctx.Logger, db, traceWriter)
|
||||
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile())
|
||||
if err != nil {
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||
"github.com/tendermint/tendermint/abci/server"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
)
|
||||
|
||||
func TestStartStandAlone(t *testing.T) {
|
||||
home, err := ioutil.TempDir("", "mock-sdk-cmd")
|
||||
require.Nil(t, err)
|
||||
defer func() {
|
||||
os.RemoveAll(home)
|
||||
}()
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
cdc := codec.New()
|
||||
appInit := AppInit{
|
||||
AppGenState: mock.AppGenState,
|
||||
AppGenTx: mock.AppGenTx,
|
||||
}
|
||||
initCmd := InitCmd(ctx, cdc, appInit)
|
||||
err = initCmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
app, err := mock.NewApp(home, logger)
|
||||
require.Nil(t, err)
|
||||
svrAddr, _, err := FreeTCPAddr()
|
||||
require.Nil(t, err)
|
||||
svr, err := server.NewServer(svrAddr, "socket", app)
|
||||
require.Nil(t, err, "error creating listener")
|
||||
svr.SetLogger(logger.With("module", "abci-server"))
|
||||
svr.Start()
|
||||
|
||||
timer := time.NewTimer(time.Duration(2) * time.Second)
|
||||
select {
|
||||
case <-timer.C:
|
||||
svr.Stop()
|
||||
}
|
||||
}
|
|
@ -36,9 +36,9 @@ func FreeTCPAddr() (addr, port string, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
// setupViper creates a homedir to run inside,
|
||||
// SetupViper creates a homedir to run inside,
|
||||
// and returns a cleanup function to defer
|
||||
func setupViper(t *testing.T) func() {
|
||||
func SetupViper(t *testing.T) func() {
|
||||
rootDir, err := ioutil.TempDir("", "mock-sdk-cmd")
|
||||
require.Nil(t, err)
|
||||
viper.Set(cli.HomeFlag, rootDir)
|
||||
|
|
|
@ -42,7 +42,7 @@ func NewContext(config *cfg.Config, logger log.Logger) *Context {
|
|||
|
||||
// PersistentPreRunEFn returns a PersistentPreRunE function for cobra
|
||||
// that initailizes the passed in context with a properly configured
|
||||
// logger and config objecy
|
||||
// logger and config object.
|
||||
func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error {
|
||||
return func(cmd *cobra.Command, args []string) error {
|
||||
if cmd.Name() == version.VersionCmd.Name() {
|
||||
|
@ -85,7 +85,7 @@ func interceptLoadConfig() (conf *cfg.Config, err error) {
|
|||
|
||||
if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
|
||||
// the following parse config is needed to create directories
|
||||
conf, _ = tcmd.ParseConfig()
|
||||
conf, _ = tcmd.ParseConfig() // NOTE: ParseConfig() creates dir/files as necessary.
|
||||
conf.ProfListenAddress = "localhost:6060"
|
||||
conf.P2P.RecvRate = 5120000
|
||||
conf.P2P.SendRate = 5120000
|
||||
|
@ -96,7 +96,7 @@ func interceptLoadConfig() (conf *cfg.Config, err error) {
|
|||
}
|
||||
|
||||
if conf == nil {
|
||||
conf, err = tcmd.ParseConfig()
|
||||
conf, err = tcmd.ParseConfig() // NOTE: ParseConfig() creates dir/files as necessary.
|
||||
}
|
||||
|
||||
cosmosConfigFilePath := filepath.Join(rootDir, "config/gaiad.toml")
|
||||
|
@ -143,8 +143,6 @@ func AddCommands(
|
|||
)
|
||||
|
||||
rootCmd.AddCommand(
|
||||
InitCmd(ctx, cdc, appInit),
|
||||
TestnetFilesCmd(ctx, cdc, appInit),
|
||||
StartCmd(ctx, appCreator),
|
||||
UnsafeResetAllCmd(ctx),
|
||||
client.LineBreak,
|
||||
|
@ -177,7 +175,7 @@ func InsertKeyJSON(cdc *codec.Codec, baseJSON []byte, key string, value json.Raw
|
|||
|
||||
// https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go
|
||||
// TODO there must be a better way to get external IP
|
||||
func externalIP() (string, error) {
|
||||
func ExternalIP() (string, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -8,11 +9,27 @@ import (
|
|||
|
||||
var _ KVStore = prefixStore{}
|
||||
|
||||
// prefixStore is similar with tendermint/tendermint/libs/db/prefix_db
|
||||
// both gives access only to the limited subset of the store
|
||||
// for convinience or safety
|
||||
|
||||
type prefixStore struct {
|
||||
parent KVStore
|
||||
prefix []byte
|
||||
}
|
||||
|
||||
func cloneAppend(bz []byte, tail []byte) (res []byte) {
|
||||
res = make([]byte, len(bz)+len(tail))
|
||||
copy(res, bz)
|
||||
copy(res[len(bz):], tail)
|
||||
return
|
||||
}
|
||||
|
||||
func (s prefixStore) key(key []byte) (res []byte) {
|
||||
res = cloneAppend(s.prefix, key)
|
||||
return
|
||||
}
|
||||
|
||||
// Implements Store
|
||||
func (s prefixStore) GetStoreType() StoreType {
|
||||
return s.parent.GetStoreType()
|
||||
|
@ -30,22 +47,23 @@ func (s prefixStore) CacheWrapWithTrace(w io.Writer, tc TraceContext) CacheWrap
|
|||
|
||||
// Implements KVStore
|
||||
func (s prefixStore) Get(key []byte) []byte {
|
||||
return s.parent.Get(append(s.prefix, key...))
|
||||
res := s.parent.Get(s.key(key))
|
||||
return res
|
||||
}
|
||||
|
||||
// Implements KVStore
|
||||
func (s prefixStore) Has(key []byte) bool {
|
||||
return s.parent.Has(append(s.prefix, key...))
|
||||
return s.parent.Has(s.key(key))
|
||||
}
|
||||
|
||||
// Implements KVStore
|
||||
func (s prefixStore) Set(key, value []byte) {
|
||||
s.parent.Set(append(s.prefix, key...), value)
|
||||
s.parent.Set(s.key(key), value)
|
||||
}
|
||||
|
||||
// Implements KVStore
|
||||
func (s prefixStore) Delete(key []byte) {
|
||||
s.parent.Delete(append(s.prefix, key...))
|
||||
s.parent.Delete(s.key(key))
|
||||
}
|
||||
|
||||
// Implements KVStore
|
||||
|
@ -59,68 +77,147 @@ func (s prefixStore) Gas(meter GasMeter, config GasConfig) KVStore {
|
|||
}
|
||||
|
||||
// Implements KVStore
|
||||
// Check https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db.go#L106
|
||||
func (s prefixStore) Iterator(start, end []byte) Iterator {
|
||||
newstart := cloneAppend(s.prefix, start)
|
||||
|
||||
var newend []byte
|
||||
if end == nil {
|
||||
end = sdk.PrefixEndBytes(s.prefix)
|
||||
newend = cpIncr(s.prefix)
|
||||
} else {
|
||||
end = append(s.prefix, end...)
|
||||
}
|
||||
return prefixIterator{
|
||||
prefix: s.prefix,
|
||||
iter: s.parent.Iterator(append(s.prefix, start...), end),
|
||||
newend = cloneAppend(s.prefix, end)
|
||||
}
|
||||
|
||||
iter := s.parent.Iterator(newstart, newend)
|
||||
|
||||
return newPrefixIterator(s.prefix, start, end, iter)
|
||||
}
|
||||
|
||||
// Implements KVStore
|
||||
// Check https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db.go#L129
|
||||
func (s prefixStore) ReverseIterator(start, end []byte) Iterator {
|
||||
if end == nil {
|
||||
end = sdk.PrefixEndBytes(s.prefix)
|
||||
var newstart []byte
|
||||
if start == nil {
|
||||
newstart = cpIncr(s.prefix)
|
||||
} else {
|
||||
end = append(s.prefix, end...)
|
||||
newstart = cloneAppend(s.prefix, start)
|
||||
}
|
||||
return prefixIterator{
|
||||
prefix: s.prefix,
|
||||
iter: s.parent.ReverseIterator(start, end),
|
||||
|
||||
var newend []byte
|
||||
if end == nil {
|
||||
newend = cpDecr(s.prefix)
|
||||
} else {
|
||||
newend = cloneAppend(s.prefix, end)
|
||||
}
|
||||
|
||||
iter := s.parent.ReverseIterator(newstart, newend)
|
||||
if start == nil {
|
||||
skipOne(iter, cpIncr(s.prefix))
|
||||
}
|
||||
|
||||
return newPrefixIterator(s.prefix, start, end, iter)
|
||||
}
|
||||
|
||||
var _ sdk.Iterator = (*prefixIterator)(nil)
|
||||
|
||||
type prefixIterator struct {
|
||||
prefix []byte
|
||||
|
||||
start, end []byte
|
||||
iter Iterator
|
||||
valid bool
|
||||
}
|
||||
|
||||
func newPrefixIterator(prefix, start, end []byte, parent Iterator) *prefixIterator {
|
||||
return &prefixIterator{
|
||||
prefix: prefix,
|
||||
start: start,
|
||||
end: end,
|
||||
iter: parent,
|
||||
valid: parent.Valid() && bytes.HasPrefix(parent.Key(), prefix),
|
||||
}
|
||||
}
|
||||
|
||||
// Implements Iterator
|
||||
func (iter prefixIterator) Domain() (start []byte, end []byte) {
|
||||
start, end = iter.iter.Domain()
|
||||
start = start[len(iter.prefix):]
|
||||
end = end[len(iter.prefix):]
|
||||
return
|
||||
func (iter *prefixIterator) Domain() ([]byte, []byte) {
|
||||
return iter.start, iter.end
|
||||
}
|
||||
|
||||
// Implements Iterator
|
||||
func (iter prefixIterator) Valid() bool {
|
||||
return iter.iter.Valid()
|
||||
func (iter *prefixIterator) Valid() bool {
|
||||
return iter.valid && iter.iter.Valid()
|
||||
}
|
||||
|
||||
// Implements Iterator
|
||||
func (iter prefixIterator) Next() {
|
||||
func (iter *prefixIterator) Next() {
|
||||
if !iter.valid {
|
||||
panic("prefixIterator invalid, cannot call Next()")
|
||||
}
|
||||
iter.iter.Next()
|
||||
if !iter.iter.Valid() || !bytes.HasPrefix(iter.iter.Key(), iter.prefix) {
|
||||
iter.valid = false
|
||||
}
|
||||
}
|
||||
|
||||
// Implements Iterator
|
||||
func (iter prefixIterator) Key() (key []byte) {
|
||||
func (iter *prefixIterator) Key() (key []byte) {
|
||||
if !iter.valid {
|
||||
panic("prefixIterator invalid, cannot call Key()")
|
||||
}
|
||||
key = iter.iter.Key()
|
||||
key = key[len(iter.prefix):]
|
||||
key = stripPrefix(key, iter.prefix)
|
||||
return
|
||||
}
|
||||
|
||||
// Implements Iterator
|
||||
func (iter prefixIterator) Value() []byte {
|
||||
func (iter *prefixIterator) Value() []byte {
|
||||
if !iter.valid {
|
||||
panic("prefixIterator invalid, cannot call Value()")
|
||||
}
|
||||
return iter.iter.Value()
|
||||
}
|
||||
|
||||
// Implements Iterator
|
||||
func (iter prefixIterator) Close() {
|
||||
func (iter *prefixIterator) Close() {
|
||||
iter.iter.Close()
|
||||
}
|
||||
|
||||
// copied from github.com/tendermint/tendermint/libs/db/prefix_db.go
|
||||
func stripPrefix(key []byte, prefix []byte) []byte {
|
||||
if len(key) < len(prefix) || !bytes.Equal(key[:len(prefix)], prefix) {
|
||||
panic("should not happen")
|
||||
}
|
||||
return key[len(prefix):]
|
||||
}
|
||||
|
||||
// wrapping sdk.PrefixEndBytes
|
||||
func cpIncr(bz []byte) []byte {
|
||||
return sdk.PrefixEndBytes(bz)
|
||||
}
|
||||
|
||||
// copied from github.com/tendermint/tendermint/libs/db/util.go
|
||||
func cpDecr(bz []byte) (ret []byte) {
|
||||
if len(bz) == 0 {
|
||||
panic("cpDecr expects non-zero bz length")
|
||||
}
|
||||
ret = make([]byte, len(bz))
|
||||
copy(ret, bz)
|
||||
for i := len(bz) - 1; i >= 0; i-- {
|
||||
if ret[i] > byte(0x00) {
|
||||
ret[i]--
|
||||
return
|
||||
}
|
||||
ret[i] = byte(0xFF)
|
||||
if i == 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func skipOne(iter Iterator, skipKey []byte) {
|
||||
if iter.Valid() {
|
||||
if bytes.Equal(iter.Key(), skipKey) {
|
||||
iter.Next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,286 @@ func TestPrefixStoreIterate(t *testing.T) {
|
|||
pIter.Next()
|
||||
}
|
||||
|
||||
require.Equal(t, bIter.Valid(), pIter.Valid())
|
||||
bIter.Close()
|
||||
pIter.Close()
|
||||
}
|
||||
|
||||
func TestPrefixStoreIteratorEdgeCase(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
baseStore := dbStoreAdapter{db}
|
||||
|
||||
// overflow in cpIncr
|
||||
prefix := []byte{0xAA, 0xFF, 0xFF}
|
||||
prefixStore := baseStore.Prefix(prefix)
|
||||
|
||||
// ascending order
|
||||
baseStore.Set([]byte{0xAA, 0xFF, 0xFE}, []byte{})
|
||||
baseStore.Set([]byte{0xAA, 0xFF, 0xFE, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAA, 0xFF, 0xFF}, []byte{})
|
||||
baseStore.Set([]byte{0xAA, 0xFF, 0xFF, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAB}, []byte{})
|
||||
baseStore.Set([]byte{0xAB, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAB, 0x00, 0x00}, []byte{})
|
||||
|
||||
iter := prefixStore.Iterator(nil, nil)
|
||||
|
||||
checkDomain(t, iter, nil, nil)
|
||||
checkItem(t, iter, []byte{}, bz(""))
|
||||
checkNext(t, iter, true)
|
||||
checkItem(t, iter, []byte{0x00}, bz(""))
|
||||
checkNext(t, iter, false)
|
||||
|
||||
checkInvalid(t, iter)
|
||||
|
||||
iter.Close()
|
||||
}
|
||||
|
||||
func TestPrefixStoreReverseIteratorEdgeCase(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
baseStore := dbStoreAdapter{db}
|
||||
|
||||
// overflow in cpIncr
|
||||
prefix := []byte{0xAA, 0xFF, 0xFF}
|
||||
prefixStore := baseStore.Prefix(prefix)
|
||||
|
||||
// descending order
|
||||
baseStore.Set([]byte{0xAB, 0x00, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAB, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAB}, []byte{})
|
||||
baseStore.Set([]byte{0xAA, 0xFF, 0xFF, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAA, 0xFF, 0xFF}, []byte{})
|
||||
baseStore.Set([]byte{0xAA, 0xFF, 0xFE, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAA, 0xFF, 0xFE}, []byte{})
|
||||
|
||||
iter := prefixStore.ReverseIterator(nil, nil)
|
||||
|
||||
checkDomain(t, iter, nil, nil)
|
||||
checkItem(t, iter, []byte{0x00}, bz(""))
|
||||
checkNext(t, iter, true)
|
||||
checkItem(t, iter, []byte{}, bz(""))
|
||||
checkNext(t, iter, false)
|
||||
|
||||
checkInvalid(t, iter)
|
||||
|
||||
iter.Close()
|
||||
|
||||
db = dbm.NewMemDB()
|
||||
baseStore = dbStoreAdapter{db}
|
||||
|
||||
// underflow in cpDecr
|
||||
prefix = []byte{0xAA, 0x00, 0x00}
|
||||
prefixStore = baseStore.Prefix(prefix)
|
||||
|
||||
baseStore.Set([]byte{0xAB, 0x00, 0x01, 0x00, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAB, 0x00, 0x01, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAB, 0x00, 0x01}, []byte{})
|
||||
baseStore.Set([]byte{0xAA, 0x00, 0x00, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xAA, 0x00, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xA9, 0xFF, 0xFF, 0x00}, []byte{})
|
||||
baseStore.Set([]byte{0xA9, 0xFF, 0xFF}, []byte{})
|
||||
|
||||
iter = prefixStore.ReverseIterator(nil, nil)
|
||||
|
||||
checkDomain(t, iter, nil, nil)
|
||||
checkItem(t, iter, []byte{0x00}, bz(""))
|
||||
checkNext(t, iter, true)
|
||||
checkItem(t, iter, []byte{}, bz(""))
|
||||
checkNext(t, iter, false)
|
||||
|
||||
checkInvalid(t, iter)
|
||||
|
||||
iter.Close()
|
||||
}
|
||||
|
||||
// Tests below are ported from https://github.com/tendermint/tendermint/blob/master/libs/db/prefix_db_test.go
|
||||
|
||||
func mockStoreWithStuff() sdk.KVStore {
|
||||
db := dbm.NewMemDB()
|
||||
store := dbStoreAdapter{db}
|
||||
// Under "key" prefix
|
||||
store.Set(bz("key"), bz("value"))
|
||||
store.Set(bz("key1"), bz("value1"))
|
||||
store.Set(bz("key2"), bz("value2"))
|
||||
store.Set(bz("key3"), bz("value3"))
|
||||
store.Set(bz("something"), bz("else"))
|
||||
store.Set(bz(""), bz(""))
|
||||
store.Set(bz("k"), bz("val"))
|
||||
store.Set(bz("ke"), bz("valu"))
|
||||
store.Set(bz("kee"), bz("valuu"))
|
||||
return store
|
||||
}
|
||||
|
||||
func checkValue(t *testing.T, store sdk.KVStore, key []byte, expected []byte) {
|
||||
bz := store.Get(key)
|
||||
require.Equal(t, expected, bz)
|
||||
}
|
||||
|
||||
func checkValid(t *testing.T, itr sdk.Iterator, expected bool) {
|
||||
valid := itr.Valid()
|
||||
require.Equal(t, expected, valid)
|
||||
}
|
||||
|
||||
func checkNext(t *testing.T, itr sdk.Iterator, expected bool) {
|
||||
itr.Next()
|
||||
valid := itr.Valid()
|
||||
require.Equal(t, expected, valid)
|
||||
}
|
||||
|
||||
func checkDomain(t *testing.T, itr sdk.Iterator, start, end []byte) {
|
||||
ds, de := itr.Domain()
|
||||
require.Equal(t, start, ds)
|
||||
require.Equal(t, end, de)
|
||||
}
|
||||
|
||||
func checkItem(t *testing.T, itr sdk.Iterator, key, value []byte) {
|
||||
require.Exactly(t, key, itr.Key())
|
||||
require.Exactly(t, value, itr.Value())
|
||||
}
|
||||
|
||||
func checkInvalid(t *testing.T, itr sdk.Iterator) {
|
||||
checkValid(t, itr, false)
|
||||
checkKeyPanics(t, itr)
|
||||
checkValuePanics(t, itr)
|
||||
checkNextPanics(t, itr)
|
||||
}
|
||||
|
||||
func checkKeyPanics(t *testing.T, itr sdk.Iterator) {
|
||||
require.Panics(t, func() { itr.Key() })
|
||||
}
|
||||
|
||||
func checkValuePanics(t *testing.T, itr sdk.Iterator) {
|
||||
require.Panics(t, func() { itr.Value() })
|
||||
}
|
||||
|
||||
func checkNextPanics(t *testing.T, itr sdk.Iterator) {
|
||||
require.Panics(t, func() { itr.Next() })
|
||||
}
|
||||
|
||||
func TestPrefixDBSimple(t *testing.T) {
|
||||
store := mockStoreWithStuff()
|
||||
pstore := store.Prefix(bz("key"))
|
||||
|
||||
checkValue(t, pstore, bz("key"), nil)
|
||||
checkValue(t, pstore, bz(""), bz("value"))
|
||||
checkValue(t, pstore, bz("key1"), nil)
|
||||
checkValue(t, pstore, bz("1"), bz("value1"))
|
||||
checkValue(t, pstore, bz("key2"), nil)
|
||||
checkValue(t, pstore, bz("2"), bz("value2"))
|
||||
checkValue(t, pstore, bz("key3"), nil)
|
||||
checkValue(t, pstore, bz("3"), bz("value3"))
|
||||
checkValue(t, pstore, bz("something"), nil)
|
||||
checkValue(t, pstore, bz("k"), nil)
|
||||
checkValue(t, pstore, bz("ke"), nil)
|
||||
checkValue(t, pstore, bz("kee"), nil)
|
||||
}
|
||||
|
||||
func TestPrefixDBIterator1(t *testing.T) {
|
||||
store := mockStoreWithStuff()
|
||||
pstore := store.Prefix(bz("key"))
|
||||
|
||||
itr := pstore.Iterator(nil, nil)
|
||||
checkDomain(t, itr, nil, nil)
|
||||
checkItem(t, itr, bz(""), bz("value"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("1"), bz("value1"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("2"), bz("value2"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("3"), bz("value3"))
|
||||
checkNext(t, itr, false)
|
||||
checkInvalid(t, itr)
|
||||
itr.Close()
|
||||
}
|
||||
|
||||
func TestPrefixDBIterator2(t *testing.T) {
|
||||
store := mockStoreWithStuff()
|
||||
pstore := store.Prefix(bz("key"))
|
||||
|
||||
itr := pstore.Iterator(nil, bz(""))
|
||||
checkDomain(t, itr, nil, bz(""))
|
||||
checkInvalid(t, itr)
|
||||
itr.Close()
|
||||
}
|
||||
|
||||
func TestPrefixDBIterator3(t *testing.T) {
|
||||
store := mockStoreWithStuff()
|
||||
pstore := store.Prefix(bz("key"))
|
||||
|
||||
itr := pstore.Iterator(bz(""), nil)
|
||||
checkDomain(t, itr, bz(""), nil)
|
||||
checkItem(t, itr, bz(""), bz("value"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("1"), bz("value1"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("2"), bz("value2"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("3"), bz("value3"))
|
||||
checkNext(t, itr, false)
|
||||
checkInvalid(t, itr)
|
||||
itr.Close()
|
||||
}
|
||||
|
||||
func TestPrefixDBIterator4(t *testing.T) {
|
||||
store := mockStoreWithStuff()
|
||||
pstore := store.Prefix(bz("key"))
|
||||
|
||||
itr := pstore.Iterator(bz(""), bz(""))
|
||||
checkDomain(t, itr, bz(""), bz(""))
|
||||
checkInvalid(t, itr)
|
||||
itr.Close()
|
||||
}
|
||||
|
||||
func TestPrefixDBReverseIterator1(t *testing.T) {
|
||||
store := mockStoreWithStuff()
|
||||
pstore := store.Prefix(bz("key"))
|
||||
|
||||
itr := pstore.ReverseIterator(nil, nil)
|
||||
checkDomain(t, itr, nil, nil)
|
||||
checkItem(t, itr, bz("3"), bz("value3"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("2"), bz("value2"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("1"), bz("value1"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz(""), bz("value"))
|
||||
checkNext(t, itr, false)
|
||||
checkInvalid(t, itr)
|
||||
itr.Close()
|
||||
}
|
||||
|
||||
func TestPrefixDBReverseIterator2(t *testing.T) {
|
||||
store := mockStoreWithStuff()
|
||||
pstore := store.Prefix(bz("key"))
|
||||
|
||||
itr := pstore.ReverseIterator(nil, bz(""))
|
||||
checkDomain(t, itr, nil, bz(""))
|
||||
checkItem(t, itr, bz("3"), bz("value3"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("2"), bz("value2"))
|
||||
checkNext(t, itr, true)
|
||||
checkItem(t, itr, bz("1"), bz("value1"))
|
||||
checkNext(t, itr, false)
|
||||
checkInvalid(t, itr)
|
||||
itr.Close()
|
||||
}
|
||||
|
||||
func TestPrefixDBReverseIterator3(t *testing.T) {
|
||||
store := mockStoreWithStuff()
|
||||
pstore := store.Prefix(bz("key"))
|
||||
|
||||
itr := pstore.ReverseIterator(bz(""), nil)
|
||||
checkDomain(t, itr, bz(""), nil)
|
||||
checkItem(t, itr, bz(""), bz("value"))
|
||||
checkNext(t, itr, false)
|
||||
checkInvalid(t, itr)
|
||||
itr.Close()
|
||||
}
|
||||
|
||||
func TestPrefixDBReverseIterator4(t *testing.T) {
|
||||
store := mockStoreWithStuff()
|
||||
pstore := store.Prefix(bz("key"))
|
||||
|
||||
itr := pstore.ReverseIterator(bz(""), bz(""))
|
||||
checkInvalid(t, itr)
|
||||
itr.Close()
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"Linters": {
|
||||
"vet": "go tool vet -composites=false :PATH:LINE:MESSAGE"
|
||||
},
|
||||
"Enable": ["golint", "vet", "ineffassign", "unparam", "unconvert", "misspell"],
|
||||
"Enable": ["golint", "vet", "ineffassign", "unconvert", "misspell"],
|
||||
"Deadline": "500s",
|
||||
"Vendor": true,
|
||||
"Cyclo": 11,
|
||||
|
|
|
@ -66,7 +66,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command {
|
|||
// build and sign the transaction, then broadcast to Tendermint
|
||||
msg := client.CreateMsg(from, to, coins)
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
|
|
|
@ -103,7 +103,7 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome
|
|||
}
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
|
||||
// Build and sign the transaction, then broadcast to Tendermint
|
||||
|
@ -183,7 +183,7 @@ func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
|
||||
// Build and sign the transaction, then broadcast to a Tendermint
|
||||
|
@ -229,7 +229,7 @@ func GetCmdVote(cdc *codec.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
|
||||
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]",
|
||||
|
|
|
@ -42,7 +42,7 @@ func IBCTransferCmd(cdc *codec.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
|
|
|
@ -31,7 +31,7 @@ func GetCmdUnjail(cdc *codec.Codec) *cobra.Command {
|
|||
|
||||
msg := slashing.NewMsgUnjail(sdk.ValAddress(valAddr))
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
},
|
||||
|
|
|
@ -88,7 +88,7 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, true)
|
||||
}
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
|
@ -143,7 +143,7 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command {
|
|||
msg := stake.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
|
@ -186,7 +186,7 @@ func GetCmdDelegate(cdc *codec.Codec) *cobra.Command {
|
|||
msg := stake.NewMsgDelegate(delAddr, valAddr, amount)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
|
@ -256,7 +256,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *codec.Codec) *cobra.Command {
|
|||
msg := stake.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, sharesAmount)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
|
@ -319,7 +319,7 @@ func GetCmdBeginUnbonding(storeName string, cdc *codec.Codec) *cobra.Command {
|
|||
msg := stake.NewMsgBeginUnbonding(delAddr, valAddr, sharesAmount)
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
|
||||
}
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
|
||||
|
|
Loading…
Reference in New Issue