diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 6819b67b2..b09bd7159 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -2,7 +2,6 @@ package app import ( "encoding/json" - "fmt" abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" @@ -183,7 +182,7 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { // GaiaGenAppState expects two args: an account address // and a coin denomination, and gives lots of coins to that address. -func GaiaGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) { +func GaiaGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { var addr sdk.Address var secret string @@ -191,7 +190,10 @@ func GaiaGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes if err != nil { return } - fmt.Printf("secret recovery key:\n%s\n", secret) + + mm := map[string]string{"secret": secret} + bz, err := cdc.MarshalJSON(mm) + message = json.RawMessage(bz) chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 63485433f..8231c4d42 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -15,16 +15,6 @@ import ( "github.com/cosmos/cosmos-sdk/server" ) -// rootCmd is the entry point for this binary -var ( - context = server.NewDefaultContext() - rootCmd = &cobra.Command{ - Use: "gaiad", - Short: "Gaia Daemon (server)", - PersistentPreRunE: server.PersistentPreRunEFn(context), - } -) - func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { dataDir := filepath.Join(rootDir, "data") db, err := dbm.NewGoLevelDB("gaia", dataDir) @@ -36,7 +26,15 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { } func main() { - server.AddCommands(rootCmd, app.GaiaGenAppState, generateApp, context) + cdc := app.MakeCodec() + ctx := server.NewDefaultContext() + rootCmd := &cobra.Command{ + Use: "gaiad", + Short: "Gaia Daemon (server)", + PersistentPreRunE: server.PersistentPreRunEFn(ctx), + } + + server.AddCommands(ctx, cdc, rootCmd, app.GaiaGenAppState, generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.gaiad") diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 37eb7d58f..7d7447300 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -15,15 +15,23 @@ import ( "github.com/cosmos/cosmos-sdk/server" ) -// rootCmd is the entry point for this binary -var ( - context = server.NewDefaultContext() - rootCmd = &cobra.Command{ +func main() { + cdc := app.MakeCodec() + ctx := server.NewDefaultContext() + + rootCmd := &cobra.Command{ Use: "basecoind", Short: "Basecoin Daemon (server)", - PersistentPreRunE: server.PersistentPreRunEFn(context), + PersistentPreRunE: server.PersistentPreRunEFn(ctx), } -) + + server.AddCommands(ctx, cdc, rootCmd, server.SimpleGenAppState, generateApp) + + // prepare and add flags + rootDir := os.ExpandEnv("$HOME/.basecoind") + executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir) + executor.Execute() +} func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { dataDir := filepath.Join(rootDir, "data") @@ -34,12 +42,3 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { bapp := app.NewBasecoinApp(logger, db) return bapp, nil } - -func main() { - server.AddCommands(rootCmd, server.DefaultGenAppState, generateApp, context) - - // prepare and add flags - rootDir := os.ExpandEnv("$HOME/.basecoind") - executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir) - executor.Execute() -} diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 8f8bb5a90..025515629 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -8,42 +8,29 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" + tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" "github.com/cosmos/cosmos-sdk/examples/democoin/app" "github.com/cosmos/cosmos-sdk/server" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) -// rootCmd is the entry point for this binary -var ( - context = server.NewDefaultContext() - rootCmd = &cobra.Command{ - Use: "democoind", - Short: "Democoin Daemon (server)", - PersistentPreRunE: server.PersistentPreRunEFn(context), - } -) - -// defaultAppState sets up the app_state for the -// default genesis file -func defaultAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) { - baseJSON, err := server.DefaultGenAppState(args, addr, coinDenom) +// coolGenAppState sets up the app_state and appends the cool app state +func CoolGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { + chainID, validators, appState, message, err = server.SimpleGenAppState(cdc, pubKey) if err != nil { - return nil, err + return } - var jsonMap map[string]json.RawMessage - err = json.Unmarshal(baseJSON, &jsonMap) - if err != nil { - return nil, err - } - jsonMap["cool"] = json.RawMessage(`{ + key := "cool" + value := json.RawMessage(`{ "trend": "ice-cold" }`) - bz, err := json.Marshal(jsonMap) - return json.RawMessage(bz), err + appState, err = server.AppendJSON(cdc, appState, key, value) + return } func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { @@ -56,7 +43,16 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { } func main() { - server.AddCommands(rootCmd, defaultAppState, generateApp, context) + cdc := app.MakeCodec() + ctx := server.NewDefaultContext() + + rootCmd := &cobra.Command{ + Use: "democoind", + Short: "Democoin Daemon (server)", + PersistentPreRunE: server.PersistentPreRunEFn(ctx), + } + + server.AddCommands(ctx, cdc, rootCmd, CoolGenAppState, generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.democoind") diff --git a/mock/app.go b/mock/app.go index 462c5564f..c687d6d4b 100644 --- a/mock/app.go +++ b/mock/app.go @@ -14,11 +14,11 @@ import ( bam "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) -// NewApp creates a simple mock kvstore app for testing. -// It should work similar to a real app. -// Make sure rootDir is empty before running the test, +// NewApp creates a simple mock kvstore app for testing. It should work +// similar to a real app. Make sure rootDir is empty before running the test, // in order to guarantee consistent results func NewApp(rootDir string, logger log.Logger) (abci.Application, error) { db, err := dbm.NewGoLevelDB("mock", filepath.Join(rootDir, "data")) @@ -108,16 +108,16 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci // GenAppState can be passed into InitCmd, returns a static string of a few // key-values that can be parsed by InitChainer -func GenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) { +func GenAppState(_ *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { - chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + chainID = fmt.Sprintf("test-chain-%v", cmn.RandStr(6)) validators = []tmtypes.GenesisValidator{{ PubKey: pubKey, Power: 10, }} - appState = json.RawMessage(fmt.Sprintf(`{ + appState = json.RawMessage(`{ "values": [ { "key": "hello", @@ -128,6 +128,6 @@ func GenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.Gen "value": "bar" } ] -}`)) +}`) return } diff --git a/mock/app_test.go b/mock/app_test.go index 18449631c..099808ee2 100644 --- a/mock/app_test.go +++ b/mock/app_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" ) // TestInitApp makes sure we can initialize this thing without an error @@ -21,9 +22,13 @@ func TestInitApp(t *testing.T) { require.NoError(t, err) // initialize it future-way - opts, err := GenInitOptions(nil, nil, "") + pubKey := crypto.GenPrivKeyEd25519().PubKey() + _, _, appState, _, err := GenAppState(nil, pubKey) require.NoError(t, err) - req := abci.RequestInitChain{AppStateBytes: opts} + //TODO test validators in the init chain? + req := abci.RequestInitChain{ + AppStateBytes: appState, + } app.InitChain(req) app.Commit() diff --git a/server/init.go b/server/init.go index 7669e5bc5..139a9937d 100644 --- a/server/init.go +++ b/server/init.go @@ -21,7 +21,7 @@ import ( ) // get cmd to initialize all files for tendermint and application -func InitCmd(gen GenAppParams, ctx *Context) *cobra.Command { +func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams) *cobra.Command { cobraCmd := cobra.Command{ Use: "init", Short: "Initialize genesis files", @@ -30,12 +30,12 @@ func InitCmd(gen GenAppParams, ctx *Context) *cobra.Command { config := ctx.Config pubkey := ReadOrCreatePrivValidator(config) - chainID, validators, appState, err := gen(pubkey) + chainID, validators, appState, message, err := gen(cdc, pubkey) if err != nil { return err } - err = CreateGenesisFile(config, chainID, validators, appState) + err = CreateGenesisFile(config, cdc, chainID, validators, appState) if err != nil { return err } @@ -47,11 +47,13 @@ func InitCmd(gen GenAppParams, ctx *Context) *cobra.Command { // print out some key information toPrint := struct { - ChainID string `json:"chain_id"` - NodeID string `json:"node_id"` + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + Message json.RawMessage `json:"message"` }{ chainID, string(nodeKey.ID()), + message, } out, err := wire.MarshalJSONIndent(cdc, toPrint) if err != nil { @@ -79,7 +81,7 @@ func ReadOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { } // create the genesis file -func CreateGenesisFile(tmConfig *cfg.Config, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { +func CreateGenesisFile(tmConfig *cfg.Config, cdc *wire.Codec, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { genFile := tmConfig.GenesisFile() if cmn.FileExists(genFile) { return fmt.Errorf("genesis config file already exists: %v", genFile) @@ -94,24 +96,16 @@ func CreateGenesisFile(tmConfig *cfg.Config, chainID string, validators []tmtype if err := genDoc.SaveAs(genFile); err != nil { return err } - return addAppStateToGenesis(genFile, appState) + return addAppStateToGenesis(cdc, genFile, appState) } // Add one line to the genesis file -func addAppStateToGenesis(genesisConfigPath string, appState json.RawMessage) error { +func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState json.RawMessage) error { bz, err := ioutil.ReadFile(genesisConfigPath) if err != nil { return err } - - var doc map[string]json.RawMessage - err = cdc.UnmarshalJSON(bz, &doc) - if err != nil { - return err - } - - doc["app_state"] = appState - out, err := wire.MarshalJSONIndent(cdc, doc) + out, err := AppendJSON(cdc, bz, "app_state", appState) if err != nil { return err } @@ -122,10 +116,10 @@ func addAppStateToGenesis(genesisConfigPath string, appState json.RawMessage) er // GenAppParams creates the core parameters initialization. It takes in a // pubkey meant to represent the pubkey of the validator of this machine. -type GenAppParams func(crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) +type GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) // Create one account with a whole bunch of mycoin in it -func SimpleGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) { +func SimpleGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { var addr sdk.Address var secret string @@ -133,7 +127,10 @@ func SimpleGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtyp if err != nil { return } - fmt.Printf("secret recovery key:\n%s\n", secret) + + mm := map[string]string{"secret": secret} + bz, err := cdc.MarshalJSON(mm) + message = json.RawMessage(bz) chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) diff --git a/server/init_test.go b/server/init_test.go index 19e669519..a035a3077 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -18,7 +18,7 @@ func TestInit(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - cmd := InitCmd(mock.GenInitOptions, ctx) + cmd := InitCmd(ctx, cdc, mock.GenAppState) err = cmd.RunE(nil, nil) require.NoError(t, err) } diff --git a/server/start.go b/server/start.go index a4ff9852e..c9a38abdf 100644 --- a/server/start.go +++ b/server/start.go @@ -27,45 +27,34 @@ type AppCreator func(string, log.Logger) (abci.Application, error) // StartCmd runs the service passed in, either // stand-alone, or in-process with tendermint -func StartCmd(app AppCreator, ctx *Context) *cobra.Command { - start := startCmd{ - appCreator: app, - context: ctx, - } +func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { cmd := &cobra.Command{ Use: "start", Short: "Run the full node", - RunE: start.run, + RunE: func(cmd *cobra.Command, args []string) error { + if !viper.GetBool(flagWithTendermint) { + ctx.Logger.Info("Starting ABCI without Tendermint") + return startStandAlone(ctx, appCreator) + } + ctx.Logger.Info("Starting ABCI with Tendermint") + return startInProcess(ctx, appCreator) + }, } + // basic flags for abci app cmd.Flags().Bool(flagWithTendermint, true, "run abci app embedded in-process with tendermint") cmd.Flags().String(flagAddress, "tcp://0.0.0.0:46658", "Listen address") - // AddNodeFlags adds support for all - // tendermint-specific command line options + // AddNodeFlags adds support for all tendermint-specific command line options tcmd.AddNodeFlags(cmd) return cmd } -type startCmd struct { - appCreator AppCreator - context *Context -} - -func (s startCmd) run(cmd *cobra.Command, args []string) error { - if !viper.GetBool(flagWithTendermint) { - s.context.Logger.Info("Starting ABCI without Tendermint") - return s.startStandAlone() - } - s.context.Logger.Info("Starting ABCI with Tendermint") - return s.startInProcess() -} - -func (s startCmd) startStandAlone() error { +func startStandAlone(ctx *Context, appCreator AppCreator) error { // Generate the app in the proper dir addr := viper.GetString(flagAddress) home := viper.GetString("home") - app, err := s.appCreator(home, s.context.Logger) + app, err := appCreator(home, ctx.Logger) if err != nil { return err } @@ -74,7 +63,7 @@ func (s startCmd) startStandAlone() error { if err != nil { return errors.Errorf("Error creating listener: %v\n", err) } - svr.SetLogger(s.context.Logger.With("module", "abci-server")) + svr.SetLogger(ctx.Logger.With("module", "abci-server")) svr.Start() // Wait forever @@ -85,10 +74,10 @@ func (s startCmd) startStandAlone() error { return nil } -func (s startCmd) startInProcess() error { - cfg := s.context.Config +func startInProcess(ctx *Context, appCreator AppCreator) error { + cfg := ctx.Config home := cfg.RootDir - app, err := s.appCreator(home, s.context.Logger) + app, err := appCreator(home, ctx.Logger) if err != nil { return err } @@ -99,7 +88,7 @@ func (s startCmd) startInProcess() error { proxy.NewLocalClientCreator(app), node.DefaultGenesisDocProviderFunc(cfg), node.DefaultDBProvider, - s.context.Logger.With("module", "node")) + ctx.Logger.With("module", "node")) if err != nil { return err } diff --git a/server/start_test.go b/server/start_test.go index ec6c886b1..f8ac5f709 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -25,7 +25,7 @@ func TestStartStandAlone(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - initCmd := InitCmd(mock.GenInitOptions, ctx) + initCmd := InitCmd(ctx, cdc, mock.GenAppState) err = initCmd.RunE(nil, nil) require.NoError(t, err) @@ -51,13 +51,13 @@ func TestStartWithTendermint(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - initCmd := InitCmd(mock.GenInitOptions, ctx) + initCmd := InitCmd(ctx, cdc, mock.GenAppState) err = initCmd.RunE(nil, nil) require.NoError(t, err) // set up app and start up viper.Set(flagWithTendermint, true) - startCmd := StartCmd(mock.NewApp, ctx) + startCmd := StartCmd(ctx, mock.NewApp) startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address timeout := time.Duration(5) * time.Second diff --git a/server/test_helpers.go b/server/test_helpers.go index 01a093f47..6855f0e92 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -8,13 +8,10 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/mock" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/stretchr/testify/require" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" "github.com/tendermint/tmlibs/cli" - "github.com/tendermint/tmlibs/log" ) // Get a free address for a test tendermint server @@ -42,27 +39,27 @@ func setupViper(t *testing.T) func() { // Begin the server pass up the channel to close // NOTE pass up the channel so it can be closed at the end of the process -func StartServer(t *testing.T) chan error { - defer setupViper(t)() +//func StartServer(t *testing.T, cdc *wire.Codec) chan error { +//defer setupViper(t)() - cfg, err := tcmd.ParseConfig() - require.Nil(t, err) +//cfg, err := tcmd.ParseConfig() +//require.Nil(t, err) - // init server - ctx := NewContext(cfg, log.NewNopLogger()) - initCmd := InitCmd(mock.GenAppState, ctx) - err = initCmd.RunE(nil, nil) - require.NoError(t, err) +//// init server +//ctx := NewContext(cfg, log.NewNopLogger()) +//initCmd := InitCmd(ctx, cdc, mock.GenAppState) +//err = initCmd.RunE(nil, nil) +//require.NoError(t, err) - // start server - viper.Set(flagWithTendermint, true) - startCmd := StartCmd(mock.NewApp, ctx) - startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address - startCmd.Flags().Set("rpc.laddr", FreeTCPAddr(t)) // set to a new free address - timeout := time.Duration(3) * time.Second +//// start server +//viper.Set(flagWithTendermint, true) +//startCmd := StartCmd(mock.NewApp, ctx) +//startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address +//startCmd.Flags().Set("rpc.laddr", FreeTCPAddr(t)) // set to a new free address +//timeout := time.Duration(3) * time.Second - return RunOrTimeout(startCmd, timeout, t) -} +//return RunOrTimeout(startCmd, timeout, t) +//} // Run or Timout RunE of command passed in func RunOrTimeout(cmd *cobra.Command, timeout time.Duration, t *testing.T) chan error { diff --git a/server/util.go b/server/util.go index 83f22db82..1d60428b5 100644 --- a/server/util.go +++ b/server/util.go @@ -1,12 +1,14 @@ package server import ( + "encoding/json" "os" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/wire" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tmlibs/cli" @@ -31,7 +33,7 @@ func NewContext(config *cfg.Config, logger log.Logger) *Context { return &Context{config, logger} } -//-------------------------------------------------------------------- +//___________________________________________________________________________________ // PersistentPreRunEFn returns a PersistentPreRunE function for cobra // that initailizes the passed in context with a properly configured @@ -62,18 +64,32 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error // add server commands func AddCommands( + ctx *Context, cdc *wire.Codec, rootCmd *cobra.Command, - appState GenAppParams, appCreator AppCreator, - context *Context) { + appState GenAppParams, appCreator AppCreator) { - rootCmd.PersistentFlags().String("log_level", context.Config.LogLevel, "Log level") + rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level") rootCmd.AddCommand( - InitCmd(appState, context), - StartCmd(appCreator, context), - UnsafeResetAllCmd(context), - ShowNodeIDCmd(context), - ShowValidatorCmd(context), + InitCmd(ctx, cdc, appState), + StartCmd(ctx, appCreator), + UnsafeResetAllCmd(ctx), + ShowNodeIDCmd(ctx), + ShowValidatorCmd(ctx), version.VersionCmd, ) } + +//___________________________________________________________________________________ + +// append a new json field to existing json message +func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) { + var jsonMap map[string]json.RawMessage + err = cdc.UnmarshalJSON(baseJSON, &jsonMap) + if err != nil { + return nil, err + } + jsonMap[key] = value + bz, err := wire.MarshalJSONIndent(cdc, jsonMap) + return json.RawMessage(bz), err +} diff --git a/server/util_test.go b/server/util_test.go new file mode 100644 index 000000000..5345b0f8f --- /dev/null +++ b/server/util_test.go @@ -0,0 +1,43 @@ +package server + +import ( + "encoding/json" + "testing" + + "github.com/cosmos/cosmos-sdk/wire" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +//func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) { + +func TestAppendJSON(t *testing.T) { + + foo := map[string]string{"foo": "foofoo"} + bar := map[string]string{"barInner": "barbar"} + + // create raw messages + bz, err := cdc.MarshalJSON(foo) + require.NoError(t, err) + fooRaw := json.RawMessage(bz) + + bz, err = cdc.MarshalJSON(bar) + require.NoError(t, err) + barRaw := json.RawMessage(bz) + + // make the append + cdc := wire.NewCodec() + appBz, err := AppendJSON(cdc, fooRaw, "barOuter", barRaw) + require.NoError(t, err) + + // test the append + var appended map[string]json.RawMessage + err = cdc.UnmarshalJSON(appBz, &appended) + require.NoError(t, err) + + var resBar map[string]string + err = cdc.UnmarshalJSON(appended["barOuter"], &resBar) + require.NoError(t, err) + + assert.Equal(t, bar, resBar, "appended: %v", appended) +}