From acdc083821566e76e78ed2da9e9025d23c69bbc7 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Wed, 18 Oct 2017 09:59:05 +0200 Subject: [PATCH] Clean up genesis, add godoc to genesis and app --- app/app_test.go | 16 ++--- app/base.go | 16 ++--- app/doc.go | 19 ++++++ benchmarks/app_test.go | 4 +- .../counter/plugins/counter/counter_test.go | 4 +- genesis/doc.go | 61 +++++++++++++++++++ genesis/parse.go | 7 ++- 7 files changed, 105 insertions(+), 22 deletions(-) create mode 100644 app/doc.go create mode 100644 genesis/doc.go diff --git a/app/app_test.go b/app/app_test.go index 5d6f84a3c..c5e488022 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -100,7 +100,7 @@ func (at *appTest) feeTx(coins coin.Coins, toll coin.Coin, sequence uint32) sdk. // set the account on the app through InitState func (at *appTest) initAccount(acct *coin.AccountWithKey) { - _, err := at.app.InitState("coin", "account", acct.MakeOption()) + err := at.app.InitState("coin", "account", acct.MakeOption()) require.Nil(at.t, err, "%+v", err) } @@ -117,7 +117,7 @@ func (at *appTest) reset() { require.Nil(at.t, err, "%+v", err) at.app = NewBaseApp(store, DefaultHandler("mycoin"), nil) - _, err = at.app.InitState("base", "chain_id", at.chainID) + err = at.app.InitState("base", "chain_id", at.chainID) require.Nil(at.t, err, "%+v", err) at.initAccount(at.acctIn) @@ -174,14 +174,14 @@ func TestInitState(t *testing.T) { //testing ChainID chainID := "testChain" - _, err = app.InitState("base", "chain_id", chainID) + err = app.InitState("base", "chain_id", chainID) require.Nil(err, "%+v", err) assert.EqualValues(app.GetChainID(), chainID) // make a nice account... bal := coin.Coins{{"atom", 77}, {"eth", 12}} acct := coin.NewAccountWithKey(bal) - _, err = app.InitState("coin", "account", acct.MakeOption()) + err = app.InitState("coin", "account", acct.MakeOption()) require.Nil(err, "%+v", err) // make sure it is set correctly, with some balance @@ -209,7 +209,7 @@ func TestInitState(t *testing.T) { } ] }` - _, err = app.InitState("coin", "account", unsortAcc) + err = app.InitState("coin", "account", unsortAcc) require.Nil(err, "%+v", err) coins, err = getAddr(unsortAddr, app.Append()) @@ -217,13 +217,13 @@ func TestInitState(t *testing.T) { assert.True(coins.IsValid()) assert.Equal(unsortCoins, coins) - _, err = app.InitState("base", "dslfkgjdas", "") + err = app.InitState("base", "dslfkgjdas", "") require.NotNil(err) - _, err = app.InitState("", "dslfkgjdas", "") + err = app.InitState("", "dslfkgjdas", "") require.NotNil(err) - _, err = app.InitState("dslfkgjdas", "szfdjzs", "") + err = app.InitState("dslfkgjdas", "szfdjzs", "") require.NotNil(err) } diff --git a/app/base.go b/app/base.go index 8d7e73a1e..2ba14fd64 100644 --- a/app/base.go +++ b/app/base.go @@ -92,22 +92,24 @@ func (app *BaseApp) BeginBlock(req abci.RequestBeginBlock) { // to be used by InitChain later // // TODO: rethink this a bit more.... -func (app *BaseApp) InitState(module, key, value string) (string, error) { +func (app *BaseApp) InitState(module, key, value string) error { state := app.Append() + logger := app.Logger().With("module", module, "key", key) if module == sdk.ModuleNameBase { if key == sdk.ChainKey { app.info.SetChainID(state, value) - return "Success", nil + return nil } - return "", fmt.Errorf("unknown base option: %s", key) + logger.Error("Invalid genesis option") + return fmt.Errorf("Unknown base option: %s", key) } - log, err := app.handler.InitState(app.Logger(), state, module, key, value) + log, err := app.handler.InitState(logger, state, module, key, value) if err != nil { - app.Logger().Error("Genesis App Options", "err", err) + logger.Error("Invalid genesis option", "err", err) } else { - app.Logger().Info(log) + logger.Info(log) } - return log, err + return err } diff --git a/app/doc.go b/app/doc.go new file mode 100644 index 000000000..d88036865 --- /dev/null +++ b/app/doc.go @@ -0,0 +1,19 @@ +/* +Package app contains data structures that provide basic +data storage functionality and act as a bridge between the abci +interface and the internal sdk representations. + +StoreApp handles creating a datastore or loading an existing one +from disk, provides helpers to use in the transaction workflow +(check/deliver/commit), and provides bindings to the ABCI interface +for functionality such as handshaking with tendermint on restart, +querying the data store, and handling begin/end block and commit messages. +It does not handle CheckTx or DeliverTx, or have any logic for modifying +the state, and is quite generic if you don't wish to use the standard Handlers. + +BaseApp embeds StoreApp and extends it for the standard sdk usecase, where +we dispatch all CheckTx/DeliverTx messages to a handler (which may contain +decorators and a router to multiple modules), and supports a Ticker which +is called every BeginBlock. +*/ +package app diff --git a/benchmarks/app_test.go b/benchmarks/app_test.go index 5d72736aa..dc9e54474 100644 --- a/benchmarks/app_test.go +++ b/benchmarks/app_test.go @@ -65,7 +65,7 @@ func NewBenchApp(h sdk.Handler, chainID string, n int, } app := sdkapp.NewBaseApp(store, h, nil) - _, err = app.InitState("base", "chain_id", chainID) + err = app.InitState("base", "chain_id", chainID) if err != nil { panic("cannot set chain") } @@ -75,7 +75,7 @@ func NewBenchApp(h sdk.Handler, chainID string, n int, accts := make([]*coin.AccountWithKey, n) for i := 0; i < n; i++ { accts[i] = coin.NewAccountWithKey(money) - _, err = app.InitState("coin", "account", accts[i].MakeOption()) + err = app.InitState("coin", "account", accts[i].MakeOption()) if err != nil { panic("can't set account") } diff --git a/examples/counter/plugins/counter/counter_test.go b/examples/counter/plugins/counter/counter_test.go index 07861dc29..5c1ef254a 100644 --- a/examples/counter/plugins/counter/counter_test.go +++ b/examples/counter/plugins/counter/counter_test.go @@ -31,13 +31,13 @@ func TestCounterPlugin(t *testing.T) { store, err := app.MockStoreApp("counter", logger) require.Nil(err, "%+v", err) bcApp := app.NewBaseApp(store, h, nil) - _, err = bcApp.InitState("base", "chain_id", chainID) + err = bcApp.InitState("base", "chain_id", chainID) require.Nil(err, "%+v", err) // Account initialization bal := coin.Coins{{"", 1000}, {"gold", 1000}} acct := coin.NewAccountWithKey(bal) - _, err = bcApp.InitState("coin", "account", acct.MakeOption()) + err = bcApp.InitState("coin", "account", acct.MakeOption()) require.Nil(err, "%+v", err) // Deliver a CounterTx diff --git a/genesis/doc.go b/genesis/doc.go new file mode 100644 index 000000000..40636fc07 --- /dev/null +++ b/genesis/doc.go @@ -0,0 +1,61 @@ +/* +Package genesis provides some utility functions for parsing +a standard genesis file to initialize your abci application. + +We wish to support using one genesis file to initialize both +tendermint and the application, so this file format is designed +to be embedable in the tendermint genesis.json file. We reuse +the same chain_id field for tendermint, ignore the other fields, +and add a special app_options field that contains information just +for the abci app (and ignored by tendermint). + +The use of this file format for your application is not required by +the sdk and is only used by default in the start command, if you wish +to write your own start command, you can use any other method to +store and parse options for your abci application. The important part is +that the same data is available on every node. + +Example file format: + + { + "chain_id": "foo_bar_chain", + "app_options": { + "accounts": [{ + "address": "C471FB670E44D219EE6DF2FC284BE38793ACBCE1", + "pub_key": { + "type": "ed25519", + "data": "6880DB93598E283A67C4D88FC67A8858AA2DE70F713FE94A5109E29C137100C2" + }, + "coins": [ + { + "denom": "ETH", + "amount": 654321 + } + ] + }], + "plugin_options": [ + "plugin1/key1", "value1", + "profile/set", {"name": "john", age: 37} + ] + } + } + +Note that there are two subfields under app_options. The first one "accounts" +is a special case for the coin module, which is assumed to be used by most +applications. It is simply a list of accounts with an identifier and their +initial balance. The account must be identified by EITHER an address +(20 bytes in hex) or a pubkey (in the go-crypto json format), not both as in +this example. "coins" defines the initial balance of the account. + +Configuration options for every other module should be placed under +"plugin_options" as key value pairs (there must be an even number of items). +The first value must be "/" to define the option to be set. +The second value is parsed as raw json and is the value to pass to the +application. This may be a string, an array, a map or any other valid json +structure that the module can parse. + +Note that we don't use a map for plugin_options, as we will often wish +to have many values for the same key, to run this setup many times, +just as we support setting many accounts. +*/ +package genesis diff --git a/genesis/parse.go b/genesis/parse.go index 6a183464c..67bc32ef1 100644 --- a/genesis/parse.go +++ b/genesis/parse.go @@ -19,9 +19,10 @@ type Option struct { } // InitStater is anything that can handle app options -// from genesis file. +// from genesis file. Setting the merkle store, config options, +// or anything else type InitStater interface { - InitState(module, key, value string) (string, error) + InitState(module, key, value string) error } // Load parses the genesis file and sets the initial @@ -35,7 +36,7 @@ func Load(app InitStater, filePath string) error { // execute all the genesis init options // abort on any error for _, opt := range opts { - _, err = app.InitState(opt.Module, opt.Key, opt.Value) + err = app.InitState(opt.Module, opt.Key, opt.Value) if err != nil { return err }