diff --git a/CHANGELOG.md b/CHANGELOG.md index 1612f083f..873824c48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ BREAKING CHANGES * Remove go-wire, use go-amino * [store] Add `SubspaceIterator` and `ReverseSubspaceIterator` to `KVStore` interface * [basecoin] NewBasecoinApp takes a `dbm.DB` and uses namespaced DBs for substores +* All module keepers now require a codespace, see basecoin or democoin for usage BUG FIXES diff --git a/Gopkg.lock b/Gopkg.lock index eb2a1c8ca..6d225e261 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -342,7 +342,7 @@ "types/priv_validator", "version" ] - revision = "d0beaba7e8a5652506a34b5fab299cc2dc274c02" + revision = "a2930cd7233f04f5a651020669289296545e70dc" version = "v0.19.0" [[projects]] @@ -384,6 +384,7 @@ name = "golang.org/x/net" packages = [ "context", + "http/httpguts", "http2", "http2/hpack", "idna", @@ -391,13 +392,13 @@ "lex/httplex", "trace" ] - revision = "61147c48b25b599e5b561d2e9c4f3e1ef489ca41" + revision = "8d16fa6dc9a85c1cd3ed24ad08ff21cf94f10888" [[projects]] branch = "master" name = "golang.org/x/sys" packages = ["unix"] - revision = "3b87a42e500a6dc65dae1a55d0b641295971163e" + revision = "b126b21c05a91c856b027c16779c12e3bf236954" [[projects]] name = "golang.org/x/text" @@ -424,7 +425,7 @@ branch = "master" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] - revision = "51d0944304c3cbce4afe9e5247e21100037bff78" + revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" [[projects]] name = "google.golang.org/grpc" diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 884528876..115748ca5 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -24,11 +24,12 @@ var dbHeaderKey = []byte("header") // The ABCI application type BaseApp struct { // initialized on creation - Logger log.Logger - name string // application name from abci.Info - db dbm.DB // common DB backend - cms sdk.CommitMultiStore // Main (uncached) state - router Router // handle any kind of message + Logger log.Logger + name string // application name from abci.Info + db dbm.DB // common DB backend + cms sdk.CommitMultiStore // Main (uncached) state + router Router // handle any kind of message + codespacer *sdk.Codespacer // handle module codespacing // must be set txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx @@ -56,13 +57,18 @@ var _ abci.Application = (*BaseApp)(nil) // Create and name new BaseApp // NOTE: The db is used to store the version number for now. func NewBaseApp(name string, logger log.Logger, db dbm.DB) *BaseApp { - return &BaseApp{ - Logger: logger, - name: name, - db: db, - cms: store.NewCommitMultiStore(db), - router: NewRouter(), + app := &BaseApp{ + Logger: logger, + name: name, + db: db, + cms: store.NewCommitMultiStore(db), + router: NewRouter(), + codespacer: sdk.NewCodespacer(), } + // Register the undefined & root codespaces, which should not be used by any modules + app.codespacer.RegisterOrPanic(sdk.CodespaceUndefined) + app.codespacer.RegisterOrPanic(sdk.CodespaceRoot) + return app } // BaseApp Name @@ -70,6 +76,11 @@ func (app *BaseApp) Name() string { return app.name } +// Register the next available codespace through the baseapp's codespacer, starting from a default +func (app *BaseApp) RegisterCodespace(codespace sdk.CodespaceType) sdk.CodespaceType { + return app.codespacer.RegisterNext(codespace) +} + // Mount a store to the provided key in the BaseApp multistore func (app *BaseApp) MountStoresIAVL(keys ...*sdk.KVStoreKey) { for _, key := range keys { @@ -355,6 +366,7 @@ func (app *BaseApp) runTx(isCheckTx bool, txBytes []byte, tx sdk.Tx) (result sdk // Validate the Msg. err := msg.ValidateBasic() if err != nil { + err = err.WithDefaultCodespace(sdk.CodespaceRoot) return err.Result() } diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 0e7ce7b7b..e84ff8e9b 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -80,7 +80,7 @@ func TestKeys(t *testing.T) { jsonStr = []byte(fmt.Sprintf(`{"name":"%s", "password":"%s", "seed": "%s"}`, newName, newPassword, newSeed)) res, body = request(t, port, "POST", "/keys", jsonStr) - assert.Equal(t, http.StatusOK, res.StatusCode, body) + require.Equal(t, http.StatusOK, res.StatusCode, body) addr := body assert.Len(t, addr, 40, "Returned address has wrong format", addr) @@ -311,7 +311,11 @@ func TestTxs(t *testing.T) { // strt TM and the LCD in process, listening on their respective sockets func startTMAndLCD() (*nm.Node, net.Listener, error) { - viper.Set(cli.HomeFlag, os.TempDir()) + dir, err := ioutil.TempDir("", "lcd_test") + if err != nil { + return nil, nil, err + } + viper.Set(cli.HomeFlag, dir) kb, err := keys.GetKeyBase() // dbm.NewMemDB()) // :( if err != nil { return nil, nil, err diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index ae60e8a73..bb3ef05ac 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -65,8 +65,8 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp { // Add handlers. coinKeeper := bank.NewCoinKeeper(app.accountMapper) - ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore) - stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper) + ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace)) + stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper, app.RegisterCodespace(simplestake.DefaultCodespace)) app.Router(). AddRoute("bank", bank.NewHandler(coinKeeper)). AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)). @@ -123,7 +123,7 @@ func (app *BasecoinApp) txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { // are registered by MakeTxCodec in bank.RegisterAmino. err := app.cdc.UnmarshalBinary(txBytes, &tx) if err != nil { - return nil, sdk.ErrTxDecode("").TraceCause(err, "") + return nil, sdk.ErrTxDecode("").Trace(err.Error()) } return tx, nil } diff --git a/examples/basecoin/app/app_test.go b/examples/basecoin/app/app_test.go index ead49adc2..bc1735dde 100644 --- a/examples/basecoin/app/app_test.go +++ b/examples/basecoin/app/app_test.go @@ -166,7 +166,7 @@ func TestSortGenesis(t *testing.T) { // Unsorted coins means invalid err := sendMsg5.ValidateBasic() - require.Equal(t, sdk.CodeInvalidCoins, err.ABCICode(), err.ABCILog()) + require.Equal(t, sdk.CodeInvalidCoins, err.Code(), err.ABCILog()) // Sort coins, should be valid sendMsg5.Inputs[0].Coins.Sort() @@ -243,7 +243,7 @@ func TestSendMsgWithAccounts(t *testing.T) { tx.Signatures[0].Sequence = 1 res := bapp.Deliver(tx) - assert.Equal(t, sdk.CodeUnauthorized, res.Code, res.Log) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log) // resigning the tx with the bumped sequence should work SignCheckDeliver(t, bapp, sendMsg1, []int64{1}, true, priv1) @@ -437,18 +437,18 @@ func SignCheckDeliver(t *testing.T, bapp *BasecoinApp, msg sdk.Msg, seq []int64, // Run a Check res := bapp.Check(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) } // Simulate a Block bapp.BeginBlock(abci.RequestBeginBlock{}) res = bapp.Deliver(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) } bapp.EndBlock(abci.RequestEndBlock{}) //bapp.Commit() diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index 151241d14..4e5e4e22f 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -70,10 +70,10 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp { // Add handlers. coinKeeper := bank.NewCoinKeeper(app.accountMapper) - coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper) - powKeeper := pow.NewKeeper(app.capKeyPowStore, pow.NewPowConfig("pow", int64(1)), coinKeeper) - ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore) - stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper) + coolKeeper := cool.NewKeeper(app.capKeyMainStore, coinKeeper, app.RegisterCodespace(cool.DefaultCodespace)) + powKeeper := pow.NewKeeper(app.capKeyPowStore, pow.NewPowConfig("pow", int64(1)), coinKeeper, app.RegisterCodespace(pow.DefaultCodespace)) + ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace)) + stakeKeeper := simplestake.NewKeeper(app.capKeyStakingStore, coinKeeper, app.RegisterCodespace(simplestake.DefaultCodespace)) app.Router(). AddRoute("bank", bank.NewHandler(coinKeeper)). AddRoute("cool", cool.NewHandler(coolKeeper)). @@ -136,7 +136,7 @@ func (app *DemocoinApp) txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) { // are registered by MakeTxCodec in bank.RegisterWire. err := app.cdc.UnmarshalBinary(txBytes, &tx) if err != nil { - return nil, sdk.ErrTxDecode("").TraceCause(err, "") + return nil, sdk.ErrTxDecode("").Trace(err.Error()) } return tx, nil } diff --git a/examples/democoin/app/app_test.go b/examples/democoin/app/app_test.go index ca4e2509e..f17e2a9b0 100644 --- a/examples/democoin/app/app_test.go +++ b/examples/democoin/app/app_test.go @@ -202,12 +202,12 @@ func TestSendMsgWithAccounts(t *testing.T) { // Run a Check res := bapp.Check(tx) - assert.Equal(t, sdk.CodeOK, res.Code, res.Log) + assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) // Simulate a Block bapp.BeginBlock(abci.RequestBeginBlock{}) res = bapp.Deliver(tx) - assert.Equal(t, sdk.CodeOK, res.Code, res.Log) + assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) // Check balances ctxDeliver := bapp.BaseApp.NewContext(false, abci.Header{}) @@ -218,19 +218,19 @@ func TestSendMsgWithAccounts(t *testing.T) { // Delivering again should cause replay error res = bapp.Deliver(tx) - assert.Equal(t, sdk.CodeInvalidSequence, res.Code, res.Log) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeInvalidSequence), sdk.ABCICodeType(res.Code), res.Log) // bumping the txnonce number without resigning should be an auth error tx.Signatures[0].Sequence = 1 res = bapp.Deliver(tx) - assert.Equal(t, sdk.CodeUnauthorized, res.Code, res.Log) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), sdk.ABCICodeType(res.Code), res.Log) // resigning the tx with the bumped sequence should work sequences = []int64{1} sig = priv1.Sign(sdk.StdSignBytes(chainID, sequences, fee, tx.Msg)) tx.Signatures[0].Signature = sig res = bapp.Deliver(tx) - assert.Equal(t, sdk.CodeOK, res.Code, res.Log) + assert.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) } func TestMineMsg(t *testing.T) { @@ -403,18 +403,18 @@ func SignCheckDeliver(t *testing.T, bapp *DemocoinApp, msg sdk.Msg, seq int64, e // Run a Check res := bapp.Check(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) } // Simulate a Block bapp.BeginBlock(abci.RequestBeginBlock{}) res = bapp.Deliver(tx) if expPass { - require.Equal(t, sdk.CodeOK, res.Code, res.Log) + require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log) } else { - require.NotEqual(t, sdk.CodeOK, res.Code, res.Log) + require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log) } bapp.EndBlock(abci.RequestEndBlock{}) //bapp.Commit() diff --git a/examples/democoin/x/cool/errors.go b/examples/democoin/x/cool/errors.go index 5db3efc39..4c28f94ba 100644 --- a/examples/democoin/x/cool/errors.go +++ b/examples/democoin/x/cool/errors.go @@ -7,11 +7,13 @@ import ( ) const ( + DefaultCodespace sdk.CodespaceType = 6 + // Cool module reserves error 400-499 lawl CodeIncorrectCoolAnswer sdk.CodeType = 400 ) // ErrIncorrectCoolAnswer - Error returned upon an incorrect guess -func ErrIncorrectCoolAnswer(answer string) sdk.Error { - return sdk.NewError(CodeIncorrectCoolAnswer, fmt.Sprintf("Incorrect cool answer: %v", answer)) +func ErrIncorrectCoolAnswer(codespace sdk.CodespaceType, answer string) sdk.Error { + return sdk.NewError(codespace, CodeIncorrectCoolAnswer, fmt.Sprintf("Incorrect cool answer: %v", answer)) } diff --git a/examples/democoin/x/cool/handler.go b/examples/democoin/x/cool/handler.go index ce86ecd5b..e2b36b218 100644 --- a/examples/democoin/x/cool/handler.go +++ b/examples/democoin/x/cool/handler.go @@ -44,7 +44,7 @@ func handleQuizMsg(ctx sdk.Context, k Keeper, msg QuizMsg) sdk.Result { correct := k.CheckTrend(ctx, msg.CoolAnswer) if !correct { - return ErrIncorrectCoolAnswer(msg.CoolAnswer).Result() + return ErrIncorrectCoolAnswer(k.codespace, msg.CoolAnswer).Result() } if ctx.IsCheckTx() { diff --git a/examples/democoin/x/cool/keeper.go b/examples/democoin/x/cool/keeper.go index 0a4fc81e1..3b6c8e9ae 100644 --- a/examples/democoin/x/cool/keeper.go +++ b/examples/democoin/x/cool/keeper.go @@ -10,11 +10,13 @@ type Keeper struct { ck bank.CoinKeeper storeKey sdk.StoreKey // The (unexposed) key used to access the store from the Context. + + codespace sdk.CodespaceType } // NewKeeper - Returns the Keeper -func NewKeeper(key sdk.StoreKey, bankKeeper bank.CoinKeeper) Keeper { - return Keeper{bankKeeper, key} +func NewKeeper(key sdk.StoreKey, bankKeeper bank.CoinKeeper, codespace sdk.CodespaceType) Keeper { + return Keeper{bankKeeper, key, codespace} } // Key to knowing the trend on the streets! diff --git a/examples/democoin/x/pow/errors.go b/examples/democoin/x/pow/errors.go index b44eb93d6..d387f9b9a 100644 --- a/examples/democoin/x/pow/errors.go +++ b/examples/democoin/x/pow/errors.go @@ -7,6 +7,8 @@ import ( type CodeType = sdk.CodeType const ( + DefaultCodespace sdk.CodespaceType = 5 + CodeInvalidDifficulty CodeType = 201 CodeNonexistentDifficulty CodeType = 202 CodeNonexistentReward CodeType = 203 @@ -40,32 +42,32 @@ func codeToDefaultMsg(code CodeType) string { } } -func ErrInvalidDifficulty(msg string) sdk.Error { - return newError(CodeInvalidDifficulty, msg) +func ErrInvalidDifficulty(codespace sdk.CodespaceType, msg string) sdk.Error { + return newError(codespace, CodeInvalidDifficulty, msg) } -func ErrNonexistentDifficulty() sdk.Error { - return newError(CodeNonexistentDifficulty, "") +func ErrNonexistentDifficulty(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeNonexistentDifficulty, "") } -func ErrNonexistentReward() sdk.Error { - return newError(CodeNonexistentReward, "") +func ErrNonexistentReward(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeNonexistentReward, "") } -func ErrNonexistentCount() sdk.Error { - return newError(CodeNonexistentCount, "") +func ErrNonexistentCount(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeNonexistentCount, "") } -func ErrInvalidProof(msg string) sdk.Error { - return newError(CodeInvalidProof, msg) +func ErrInvalidProof(codespace sdk.CodespaceType, msg string) sdk.Error { + return newError(codespace, CodeInvalidProof, msg) } -func ErrNotBelowTarget(msg string) sdk.Error { - return newError(CodeNotBelowTarget, msg) +func ErrNotBelowTarget(codespace sdk.CodespaceType, msg string) sdk.Error { + return newError(codespace, CodeNotBelowTarget, msg) } -func ErrInvalidCount(msg string) sdk.Error { - return newError(CodeInvalidCount, msg) +func ErrInvalidCount(codespace sdk.CodespaceType, msg string) sdk.Error { + return newError(codespace, CodeInvalidCount, msg) } func msgOrDefaultMsg(msg string, code CodeType) string { @@ -76,7 +78,7 @@ func msgOrDefaultMsg(msg string, code CodeType) string { } } -func newError(code CodeType, msg string) sdk.Error { +func newError(codespace sdk.CodespaceType, code CodeType, msg string) sdk.Error { msg = msgOrDefaultMsg(msg, code) - return sdk.NewError(code, msg) + return sdk.NewError(codespace, code, msg) } diff --git a/examples/democoin/x/pow/handler_test.go b/examples/democoin/x/pow/handler_test.go index a05932780..4b1a571f7 100644 --- a/examples/democoin/x/pow/handler_test.go +++ b/examples/democoin/x/pow/handler_test.go @@ -22,7 +22,7 @@ func TestPowHandler(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, false, nil) config := NewPowConfig("pow", int64(1)) ck := bank.NewCoinKeeper(am) - keeper := NewKeeper(capKey, config, ck) + keeper := NewKeeper(capKey, config, ck, DefaultCodespace) handler := keeper.Handler diff --git a/examples/democoin/x/pow/keeper.go b/examples/democoin/x/pow/keeper.go index 73558632c..70453d6d6 100644 --- a/examples/democoin/x/pow/keeper.go +++ b/examples/democoin/x/pow/keeper.go @@ -21,17 +21,18 @@ type PowGenesis struct { } type Keeper struct { - key sdk.StoreKey - config PowConfig - ck bank.CoinKeeper + key sdk.StoreKey + config PowConfig + ck bank.CoinKeeper + codespace sdk.CodespaceType } func NewPowConfig(denomination string, reward int64) PowConfig { return PowConfig{denomination, reward} } -func NewKeeper(key sdk.StoreKey, config PowConfig, ck bank.CoinKeeper) Keeper { - return Keeper{key, config, ck} +func NewKeeper(key sdk.StoreKey, config PowConfig, ck bank.CoinKeeper, codespace sdk.CodespaceType) Keeper { + return Keeper{key, config, ck, codespace} } func (pk Keeper) InitGenesis(ctx sdk.Context, genesis PowGenesis) error { @@ -78,24 +79,24 @@ func (pk Keeper) CheckValid(ctx sdk.Context, difficulty uint64, count uint64) (u lastDifficulty, err := pk.GetLastDifficulty(ctx) if err != nil { - return 0, 0, ErrNonexistentDifficulty() + return 0, 0, ErrNonexistentDifficulty(pk.codespace) } newDifficulty := lastDifficulty + 1 lastCount, err := pk.GetLastCount(ctx) if err != nil { - return 0, 0, ErrNonexistentCount() + return 0, 0, ErrNonexistentCount(pk.codespace) } newCount := lastCount + 1 if count != newCount { - return 0, 0, ErrInvalidCount(fmt.Sprintf("invalid count: was %d, should have been %d", count, newCount)) + return 0, 0, ErrInvalidCount(pk.codespace, fmt.Sprintf("invalid count: was %d, should have been %d", count, newCount)) } if difficulty != newDifficulty { - return 0, 0, ErrInvalidDifficulty(fmt.Sprintf("invalid difficulty: was %d, should have been %d", difficulty, newDifficulty)) + return 0, 0, ErrInvalidDifficulty(pk.codespace, fmt.Sprintf("invalid difficulty: was %d, should have been %d", difficulty, newDifficulty)) } return newDifficulty, newCount, nil diff --git a/examples/democoin/x/pow/keeper_test.go b/examples/democoin/x/pow/keeper_test.go index cb3492a86..d0b60fa17 100644 --- a/examples/democoin/x/pow/keeper_test.go +++ b/examples/democoin/x/pow/keeper_test.go @@ -35,7 +35,7 @@ func TestPowKeeperGetSet(t *testing.T) { ctx := sdk.NewContext(ms, abci.Header{}, false, nil) config := NewPowConfig("pow", int64(1)) ck := bank.NewCoinKeeper(am) - keeper := NewKeeper(capKey, config, ck) + keeper := NewKeeper(capKey, config, ck, DefaultCodespace) err := keeper.InitGenesis(ctx, PowGenesis{uint64(1), uint64(0)}) assert.Nil(t, err) diff --git a/examples/democoin/x/pow/types.go b/examples/democoin/x/pow/types.go index ea368c306..69d56e4f1 100644 --- a/examples/democoin/x/pow/types.go +++ b/examples/democoin/x/pow/types.go @@ -52,7 +52,7 @@ func (msg MineMsg) ValidateBasic() sdk.Error { hex.Encode(hashHex, hash) hashHex = hashHex[:16] if !bytes.Equal(hashHex, msg.Proof) { - return ErrInvalidProof(fmt.Sprintf("hashHex: %s, proof: %s", hashHex, msg.Proof)) + return ErrInvalidProof(DefaultCodespace, fmt.Sprintf("hashHex: %s, proof: %s", hashHex, msg.Proof)) } // check proof below difficulty @@ -60,10 +60,10 @@ func (msg MineMsg) ValidateBasic() sdk.Error { target := math.MaxUint64 / msg.Difficulty hashUint, err := strconv.ParseUint(string(msg.Proof), 16, 64) if err != nil { - return ErrInvalidProof(fmt.Sprintf("proof: %s", msg.Proof)) + return ErrInvalidProof(DefaultCodespace, fmt.Sprintf("proof: %s", msg.Proof)) } if hashUint >= target { - return ErrNotBelowTarget(fmt.Sprintf("hashuint: %d, target: %d", hashUint, target)) + return ErrNotBelowTarget(DefaultCodespace, fmt.Sprintf("hashuint: %d, target: %d", hashUint, target)) } return nil diff --git a/store/rootmultistore_test.go b/store/rootmultistore_test.go index 3796bd477..f4164f0b5 100644 --- a/store/rootmultistore_test.go +++ b/store/rootmultistore_test.go @@ -128,34 +128,34 @@ func TestMultiStoreQuery(t *testing.T) { // Test bad path. query := abci.RequestQuery{Path: "/key", Data: k, Height: ver} qres := multi.Query(query) - assert.Equal(t, uint32(sdk.CodeUnknownRequest), qres.Code) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code)) query.Path = "h897fy32890rf63296r92" qres = multi.Query(query) - assert.Equal(t, uint32(sdk.CodeUnknownRequest), qres.Code) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code)) // Test invalid store name. query.Path = "/garbage/key" qres = multi.Query(query) - assert.Equal(t, uint32(sdk.CodeUnknownRequest), qres.Code) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnknownRequest), sdk.ABCICodeType(qres.Code)) // Test valid query with data. query.Path = "/store1/key" qres = multi.Query(query) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code)) assert.Equal(t, v, qres.Value) // Test valid but empty query. query.Path = "/store2/key" query.Prove = true qres = multi.Query(query) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code)) assert.Nil(t, qres.Value) // Test store2 data. query.Data = k2 qres = multi.Query(query) - assert.Equal(t, uint32(sdk.CodeOK), qres.Code) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), sdk.ABCICodeType(qres.Code)) assert.Equal(t, v2, qres.Value) } diff --git a/types/codespacer.go b/types/codespacer.go new file mode 100644 index 000000000..92025c1a6 --- /dev/null +++ b/types/codespacer.go @@ -0,0 +1,35 @@ +package types + +// Codespacer is a simple struct to track reserved codespaces +type Codespacer struct { + reserved map[CodespaceType]bool +} + +// NewCodespacer generates a new Codespacer with the starting codespace +func NewCodespacer() *Codespacer { + return &Codespacer{ + reserved: make(map[CodespaceType]bool), + } +} + +// RegisterNext reserves and returns the next available codespace, starting from a default, and panics if the maximum codespace is reached +func (c *Codespacer) RegisterNext(codespace CodespaceType) CodespaceType { + for { + if !c.reserved[codespace] { + c.reserved[codespace] = true + return codespace + } + codespace++ + if codespace == MaximumCodespace { + panic("Maximum codespace reached!") + } + } +} + +// RegisterOrPanic reserved a codespace or panics if it is unavailable +func (c *Codespacer) RegisterOrPanic(codespace CodespaceType) { + if c.reserved[codespace] { + panic("Cannot register codespace, already reserved") + } + c.reserved[codespace] = true +} diff --git a/types/codespacer_test.go b/types/codespacer_test.go new file mode 100644 index 000000000..7052aa92a --- /dev/null +++ b/types/codespacer_test.go @@ -0,0 +1,47 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestRegisterNext(t *testing.T) { + codespacer := NewCodespacer() + // unregistered, allow + code1 := codespacer.RegisterNext(CodespaceType(2)) + require.Equal(t, code1, CodespaceType(2)) + // registered, pick next + code2 := codespacer.RegisterNext(CodespaceType(2)) + require.Equal(t, code2, CodespaceType(3)) + // pick next + code3 := codespacer.RegisterNext(CodespaceType(2)) + require.Equal(t, code3, CodespaceType(4)) + // skip 1 + code4 := codespacer.RegisterNext(CodespaceType(6)) + require.Equal(t, code4, CodespaceType(6)) + code5 := codespacer.RegisterNext(CodespaceType(2)) + require.Equal(t, code5, CodespaceType(5)) + code6 := codespacer.RegisterNext(CodespaceType(2)) + require.Equal(t, code6, CodespaceType(7)) + // panic on maximum + defer func() { + r := recover() + require.NotNil(t, r, "Did not panic on maximum codespace") + }() + codespacer.RegisterNext(MaximumCodespace - 1) + codespacer.RegisterNext(MaximumCodespace - 1) +} + +func TestRegisterOrPanic(t *testing.T) { + codespacer := NewCodespacer() + // unregistered, allow + code1 := codespacer.RegisterNext(CodespaceType(2)) + require.Equal(t, code1, CodespaceType(2)) + // panic on duplicate + defer func() { + r := recover() + require.NotNil(t, r, "Did not panic on duplicate codespace") + }() + codespacer.RegisterOrPanic(CodespaceType(2)) +} diff --git a/types/errors.go b/types/errors.go index 4874c4362..c2fe726a2 100644 --- a/types/errors.go +++ b/types/errors.go @@ -2,25 +2,42 @@ package types import ( "fmt" - "runtime" + + cmn "github.com/tendermint/tmlibs/common" abci "github.com/tendermint/abci/types" ) -// ABCI Response Code -type CodeType uint32 +// ABCICodeType - combined codetype / codespace +type ABCICodeType uint32 -// is everything okay? -func (code CodeType) IsOK() bool { - if code == CodeOK { +// CodeType - code identifier within codespace +type CodeType uint16 + +// CodespaceType - codespace identifier +type CodespaceType uint16 + +// IsOK - is everything okay? +func (code ABCICodeType) IsOK() bool { + if code == ABCICodeOK { return true } return false } -// ABCI Response Codes -// Base SDK reserves 0 - 99. +func ToABCICode(space CodespaceType, code CodeType) ABCICodeType { + // TODO: Make Tendermint more aware of codespaces. + if space == CodespaceRoot && code == CodeOK { + return ABCICodeOK + } + return ABCICodeType((uint32(space) << 16) | uint32(code)) +} + const ( + // ABCI error codes + ABCICodeOK ABCICodeType = 0 + + // Base error codes CodeOK CodeType = 0 CodeInternal CodeType = 1 CodeTxDecode CodeType = 2 @@ -34,7 +51,14 @@ const ( CodeInsufficientCoins CodeType = 10 CodeInvalidCoins CodeType = 11 - CodeGenesisParse CodeType = 0xdead // TODO: remove ? // why remove? + // CodespaceRoot is a codespace for error codes in this file only. + // Notice that 0 is an "unset" codespace, which can be overridden with + // Error.WithDefaultCodespace(). + CodespaceUndefined CodespaceType = 0 + CodespaceRoot CodespaceType = 1 + + // Maximum reservable codespace (2^16 - 1) + MaximumCodespace CodespaceType = 65535 ) // NOTE: Don't stringer this, we'll put better messages in later. @@ -44,8 +68,6 @@ func CodeToDefaultMsg(code CodeType) string { return "Internal error" case CodeTxDecode: return "Tx parse error" - case CodeGenesisParse: - return "Genesis parse error" case CodeInvalidSequence: return "Invalid sequence" case CodeUnauthorized: @@ -75,40 +97,37 @@ func CodeToDefaultMsg(code CodeType) string { // nolint func ErrInternal(msg string) Error { - return newError(CodeInternal, msg) + return newErrorWithRootCodespace(CodeInternal, msg) } func ErrTxDecode(msg string) Error { - return newError(CodeTxDecode, msg) -} -func ErrGenesisParse(msg string) Error { - return newError(CodeGenesisParse, msg) + return newErrorWithRootCodespace(CodeTxDecode, msg) } func ErrInvalidSequence(msg string) Error { - return newError(CodeInvalidSequence, msg) + return newErrorWithRootCodespace(CodeInvalidSequence, msg) } func ErrUnauthorized(msg string) Error { - return newError(CodeUnauthorized, msg) + return newErrorWithRootCodespace(CodeUnauthorized, msg) } func ErrInsufficientFunds(msg string) Error { - return newError(CodeInsufficientFunds, msg) + return newErrorWithRootCodespace(CodeInsufficientFunds, msg) } func ErrUnknownRequest(msg string) Error { - return newError(CodeUnknownRequest, msg) + return newErrorWithRootCodespace(CodeUnknownRequest, msg) } func ErrInvalidAddress(msg string) Error { - return newError(CodeInvalidAddress, msg) + return newErrorWithRootCodespace(CodeInvalidAddress, msg) } func ErrUnknownAddress(msg string) Error { - return newError(CodeUnknownAddress, msg) + return newErrorWithRootCodespace(CodeUnknownAddress, msg) } func ErrInvalidPubKey(msg string) Error { - return newError(CodeInvalidPubKey, msg) + return newErrorWithRootCodespace(CodeInvalidPubKey, msg) } func ErrInsufficientCoins(msg string) Error { - return newError(CodeInsufficientCoins, msg) + return newErrorWithRootCodespace(CodeInsufficientCoins, msg) } func ErrInvalidCoins(msg string) Error { - return newError(CodeInvalidCoins, msg) + return newErrorWithRootCodespace(CodeInvalidCoins, msg) } //---------------------------------------- @@ -117,104 +136,98 @@ func ErrInvalidCoins(msg string) Error { // sdk Error type type Error interface { Error() string - ABCICode() CodeType + Code() CodeType + Codespace() CodespaceType ABCILog() string + ABCICode() ABCICodeType + WithDefaultCodespace(codespace CodespaceType) Error Trace(msg string) Error - TraceCause(cause error, msg string) Error - Cause() error + T() interface{} Result() Result QueryResult() abci.ResponseQuery } -func NewError(code CodeType, msg string) Error { - return newError(code, msg) +// NewError - create an error +func NewError(codespace CodespaceType, code CodeType, msg string) Error { + return newError(codespace, code, msg) } -type traceItem struct { - msg string - filename string - lineno int +func newErrorWithRootCodespace(code CodeType, msg string) *sdkError { + return newError(CodespaceRoot, code, msg) } -func (ti traceItem) String() string { - return fmt.Sprintf("%v:%v %v", ti.filename, ti.lineno, ti.msg) -} - -type sdkError struct { - code CodeType - msg string - cause error - traces []traceItem -} - -func newError(code CodeType, msg string) *sdkError { - // TODO capture stacktrace if ENV is set. +func newError(codespace CodespaceType, code CodeType, msg string) *sdkError { if msg == "" { msg = CodeToDefaultMsg(code) } return &sdkError{ - code: code, - msg: msg, - cause: nil, - traces: nil, + codespace: codespace, + code: code, + err: cmn.NewErrorWithT(code, msg), } } +type sdkError struct { + codespace CodespaceType + code CodeType + err cmn.Error +} + // Implements ABCIError. func (err *sdkError) Error() string { - return fmt.Sprintf("Error{%d:%s,%v,%v}", err.code, err.msg, err.cause, len(err.traces)) + return fmt.Sprintf("Error{%d:%d,%#v}", err.codespace, err.code, err.err) } // Implements ABCIError. -func (err *sdkError) ABCICode() CodeType { +func (err *sdkError) ABCICode() ABCICodeType { + return ToABCICode(err.codespace, err.code) +} + +// Implements Error. +func (err *sdkError) Codespace() CodespaceType { + return err.codespace +} + +// Implements Error. +func (err *sdkError) Code() CodeType { return err.code } // Implements ABCIError. func (err *sdkError) ABCILog() string { - traceLog := "" - for _, ti := range err.traces { - traceLog += ti.String() + "\n" - } - return fmt.Sprintf("msg: %v\ntrace:\n%v", - err.msg, - traceLog, - ) + return fmt.Sprintf(`=== ABCI Log === +Codespace: %v +Code: %v +ABCICode: %v +Error: %#v +=== /ABCI Log === +`, err.codespace, err.code, err.ABCICode(), err.err) } // Add tracing information with msg. func (err *sdkError) Trace(msg string) Error { - return err.doTrace(msg, 2) -} - -// Add tracing information with cause and msg. -func (err *sdkError) TraceCause(cause error, msg string) Error { - err.cause = cause - return err.doTrace(msg, 2) -} - -func (err *sdkError) doTrace(msg string, n int) Error { - _, fn, line, ok := runtime.Caller(n) - if !ok { - if fn == "" { - fn = "" - } - if line <= 0 { - line = -1 - } + return &sdkError{ + codespace: err.codespace, + code: err.code, + err: err.err.Trace(msg), } - // Include file & line number & msg. - // Do not include the whole stack trace. - err.traces = append(err.traces, traceItem{ - filename: fn, - lineno: line, - msg: msg, - }) - return err } -func (err *sdkError) Cause() error { - return err.cause +// Implements Error. +func (err *sdkError) WithDefaultCodespace(cs CodespaceType) Error { + codespace := err.codespace + if codespace == CodespaceUndefined { + codespace = cs + } + return &sdkError{ + codespace: codespace, + code: err.code, + err: err.err, + } +} + +func (err *sdkError) T() interface{} { + return err.err.T() } func (err *sdkError) Result() Result { diff --git a/types/errors_test.go b/types/errors_test.go index 939cced7c..798eafefc 100644 --- a/types/errors_test.go +++ b/types/errors_test.go @@ -16,7 +16,6 @@ var codeTypes = []CodeType{ CodeUnknownRequest, CodeUnknownAddress, CodeInvalidPubKey, - CodeGenesisParse, } type errFn func(msg string) Error @@ -30,14 +29,12 @@ var errFns = []errFn{ ErrUnknownRequest, ErrUnknownAddress, ErrInvalidPubKey, - ErrGenesisParse, } func TestCodeType(t *testing.T) { - assert.True(t, CodeOK.IsOK()) + assert.True(t, ABCICodeOK.IsOK()) for _, c := range codeTypes { - assert.False(t, c.IsOK()) msg := CodeToDefaultMsg(c) assert.False(t, strings.HasPrefix(msg, "Unknown code")) } @@ -47,7 +44,7 @@ func TestErrFn(t *testing.T) { for i, errFn := range errFns { err := errFn("") codeType := codeTypes[i] - assert.Equal(t, err.ABCICode(), codeType) - assert.Equal(t, err.Result().Code, codeType) + assert.Equal(t, err.Code(), codeType) + assert.Equal(t, err.Result().Code, ToABCICode(CodespaceRoot, codeType)) } } diff --git a/types/rational.go b/types/rational.go index 8ebee7140..9199520b2 100644 --- a/types/rational.go +++ b/types/rational.go @@ -97,23 +97,23 @@ func NewRatFromDecimal(decimalStr string) (f Rat, err Error) { switch len(str) { case 1: if len(str[0]) == 0 { - return f, NewError(CodeUnknownRequest, "not a decimal string") + return f, ErrUnknownRequest("not a decimal string") } numStr = str[0] case 2: if len(str[0]) == 0 || len(str[1]) == 0 { - return f, NewError(CodeUnknownRequest, "not a decimal string") + return f, ErrUnknownRequest("not a decimal string") } numStr = str[0] + str[1] len := int64(len(str[1])) denom = new(big.Int).Exp(big.NewInt(10), big.NewInt(len), nil).Int64() default: - return f, NewError(CodeUnknownRequest, "not a decimal string") + return f, ErrUnknownRequest("not a decimal string") } num, errConv := strconv.Atoi(numStr) if errConv != nil { - return f, NewError(CodeUnknownRequest, errConv.Error()) + return f, ErrUnknownRequest(errConv.Error()) } if neg { diff --git a/types/result.go b/types/result.go index 412a9778d..7b0c1a593 100644 --- a/types/result.go +++ b/types/result.go @@ -9,7 +9,7 @@ import ( type Result struct { // Code is the response code, is stored back on the chain. - Code CodeType + Code ABCICodeType // Data is any data returned from the app. Data []byte diff --git a/x/auth/ante_test.go b/x/auth/ante_test.go index 58633ff9a..3baf8ee71 100644 --- a/x/auth/ante_test.go +++ b/x/auth/ante_test.go @@ -40,7 +40,7 @@ func privAndAddr() (crypto.PrivKey, sdk.Address) { func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx) { _, result, abort := anteHandler(ctx, tx) assert.False(t, abort) - assert.Equal(t, sdk.CodeOK, result.Code) + assert.Equal(t, sdk.ABCICodeOK, result.Code) assert.True(t, result.IsOK()) } @@ -48,7 +48,7 @@ func checkValidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx func checkInvalidTx(t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, code sdk.CodeType) { _, result, abort := anteHandler(ctx, tx) assert.True(t, abort) - assert.Equal(t, code, result.Code) + assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, code), result.Code) } func newTestTx(ctx sdk.Context, msg sdk.Msg, privs []crypto.PrivKey, seqs []int64, fee sdk.StdFee) sdk.Tx { diff --git a/x/bank/errors.go b/x/bank/errors.go index 4223dd30b..d7c7e9748 100644 --- a/x/bank/errors.go +++ b/x/bank/errors.go @@ -7,6 +7,8 @@ import ( // Coin errors reserve 100 ~ 199. const ( + DefaultCodespace sdk.CodespaceType = 2 + CodeInvalidInput sdk.CodeType = 101 CodeInvalidOutput sdk.CodeType = 102 ) @@ -26,20 +28,20 @@ func codeToDefaultMsg(code sdk.CodeType) string { //---------------------------------------- // Error constructors -func ErrInvalidInput(msg string) sdk.Error { - return newError(CodeInvalidInput, msg) +func ErrInvalidInput(codespace sdk.CodespaceType, msg string) sdk.Error { + return newError(codespace, CodeInvalidInput, msg) } -func ErrNoInputs() sdk.Error { - return newError(CodeInvalidInput, "") +func ErrNoInputs(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidInput, "") } -func ErrInvalidOutput(msg string) sdk.Error { - return newError(CodeInvalidOutput, msg) +func ErrInvalidOutput(codespace sdk.CodespaceType, msg string) sdk.Error { + return newError(codespace, CodeInvalidOutput, msg) } -func ErrNoOutputs() sdk.Error { - return newError(CodeInvalidOutput, "") +func ErrNoOutputs(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidOutput, "") } //---------------------------------------- @@ -51,7 +53,7 @@ func msgOrDefaultMsg(msg string, code sdk.CodeType) string { return codeToDefaultMsg(code) } -func newError(code sdk.CodeType, msg string) sdk.Error { +func newError(codespace sdk.CodespaceType, code sdk.CodeType, msg string) sdk.Error { msg = msgOrDefaultMsg(msg, code) - return sdk.NewError(code, msg) + return sdk.NewError(codespace, code, msg) } diff --git a/x/bank/msgs.go b/x/bank/msgs.go index 15822eed7..c0f2ad46a 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -28,10 +28,10 @@ func (msg SendMsg) ValidateBasic() sdk.Error { // this just makes sure all the inputs and outputs are properly formatted, // not that they actually have the money inside if len(msg.Inputs) == 0 { - return ErrNoInputs().Trace("") + return ErrNoInputs(DefaultCodespace).Trace("") } if len(msg.Outputs) == 0 { - return ErrNoOutputs().Trace("") + return ErrNoOutputs(DefaultCodespace).Trace("") } // make sure all inputs and outputs are individually valid var totalIn, totalOut sdk.Coins @@ -102,7 +102,7 @@ func (msg IssueMsg) Type() string { return "bank" } // TODO: "bank/issue" func (msg IssueMsg) ValidateBasic() sdk.Error { // XXX if len(msg.Outputs) == 0 { - return ErrNoOutputs().Trace("") + return ErrNoOutputs(DefaultCodespace).Trace("") } for _, out := range msg.Outputs { if err := out.ValidateBasic(); err != nil { diff --git a/x/ibc/errors.go b/x/ibc/errors.go index f3c988b59..3c52bed7b 100644 --- a/x/ibc/errors.go +++ b/x/ibc/errors.go @@ -5,6 +5,8 @@ import ( ) const ( + DefaultCodespace sdk.CodespaceType = 3 + // IBC errors reserve 200 - 299. CodeInvalidSequence sdk.CodeType = 200 CodeIdenticalChains sdk.CodeType = 201 @@ -22,20 +24,20 @@ func codeToDefaultMsg(code sdk.CodeType) string { } } -func ErrInvalidSequence() sdk.Error { - return newError(CodeInvalidSequence, "") +func ErrInvalidSequence(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidSequence, "") } -func ErrIdenticalChains() sdk.Error { - return newError(CodeIdenticalChains, "") +func ErrIdenticalChains(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeIdenticalChains, "") } // ------------------------- // Helpers -func newError(code sdk.CodeType, msg string) sdk.Error { +func newError(codespace sdk.CodespaceType, code sdk.CodeType, msg string) sdk.Error { msg = msgOrDefaultMsg(msg, code) - return sdk.NewError(code, msg) + return sdk.NewError(codespace, code, msg) } func msgOrDefaultMsg(msg string, code sdk.CodeType) string { diff --git a/x/ibc/handler.go b/x/ibc/handler.go index 2922f6dab..dcd00359f 100644 --- a/x/ibc/handler.go +++ b/x/ibc/handler.go @@ -44,7 +44,7 @@ func handleIBCReceiveMsg(ctx sdk.Context, ibcm IBCMapper, ck bank.CoinKeeper, ms seq := ibcm.GetIngressSequence(ctx, packet.SrcChain) if msg.Sequence != seq { - return ErrInvalidSequence().Result() + return ErrInvalidSequence(ibcm.codespace).Result() } _, err := ck.AddCoins(ctx, packet.DestAddr, packet.Coins) diff --git a/x/ibc/ibc_test.go b/x/ibc/ibc_test.go index db172a5ca..1fc724e54 100644 --- a/x/ibc/ibc_test.go +++ b/x/ibc/ibc_test.go @@ -73,7 +73,7 @@ func TestIBC(t *testing.T) { assert.Nil(t, err) assert.Equal(t, mycoins, coins) - ibcm := NewIBCMapper(cdc, key) + ibcm := NewIBCMapper(cdc, key, DefaultCodespace) h := NewHandler(ibcm, ck) packet := IBCPacket{ SrcAddr: src, diff --git a/x/ibc/mapper.go b/x/ibc/mapper.go index 1e8f9de25..d3ecc779d 100644 --- a/x/ibc/mapper.go +++ b/x/ibc/mapper.go @@ -8,17 +8,19 @@ import ( ) type IBCMapper struct { - key sdk.StoreKey - cdc *wire.Codec + key sdk.StoreKey + cdc *wire.Codec + codespace sdk.CodespaceType } // XXX: The IBCMapper should not take a CoinKeeper. Rather have the CoinKeeper // take an IBCMapper. -func NewIBCMapper(cdc *wire.Codec, key sdk.StoreKey) IBCMapper { +func NewIBCMapper(cdc *wire.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) IBCMapper { // XXX: How are these codecs supposed to work? return IBCMapper{ - key: key, - cdc: cdc, + key: key, + cdc: cdc, + codespace: codespace, } } diff --git a/x/ibc/types.go b/x/ibc/types.go index 495d2a900..2bf2c4267 100644 --- a/x/ibc/types.go +++ b/x/ibc/types.go @@ -33,7 +33,7 @@ func NewIBCPacket(srcAddr sdk.Address, destAddr sdk.Address, coins sdk.Coins, func (ibcp IBCPacket) ValidateBasic() sdk.Error { if ibcp.SrcChain == ibcp.DestChain { - return ErrIdenticalChains().Trace("") + return ErrIdenticalChains(DefaultCodespace).Trace("") } if !ibcp.Coins.IsValid() { return sdk.ErrInvalidCoins("") diff --git a/x/simplestake/errors.go b/x/simplestake/errors.go index f69ffcbeb..0fb7eebce 100644 --- a/x/simplestake/errors.go +++ b/x/simplestake/errors.go @@ -5,6 +5,8 @@ import ( ) const ( + DefaultCodespace sdk.CodespaceType = 4 + // simplestake errors reserve 300 - 399. CodeEmptyValidator sdk.CodeType = 300 CodeInvalidUnbond sdk.CodeType = 301 @@ -12,25 +14,25 @@ const ( CodeIncorrectStakingToken sdk.CodeType = 303 ) -func ErrIncorrectStakingToken() sdk.Error { - return newError(CodeIncorrectStakingToken, "") +func ErrIncorrectStakingToken(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeIncorrectStakingToken, "") } -func ErrEmptyValidator() sdk.Error { - return newError(CodeEmptyValidator, "") +func ErrEmptyValidator(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeEmptyValidator, "") } -func ErrInvalidUnbond() sdk.Error { - return newError(CodeInvalidUnbond, "") +func ErrInvalidUnbond(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidUnbond, "") } -func ErrEmptyStake() sdk.Error { - return newError(CodeEmptyStake, "") +func ErrEmptyStake(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeEmptyStake, "") } // ----------------------------- // Helpers -func newError(code sdk.CodeType, msg string) sdk.Error { - return sdk.NewError(code, msg) +func newError(codespace sdk.CodespaceType, code sdk.CodeType, msg string) sdk.Error { + return sdk.NewError(codespace, code, msg) } diff --git a/x/simplestake/handler.go b/x/simplestake/handler.go index 31e5a7d24..894da04b2 100644 --- a/x/simplestake/handler.go +++ b/x/simplestake/handler.go @@ -32,7 +32,7 @@ func handleBondMsg(ctx sdk.Context, k Keeper, msg BondMsg) sdk.Result { } return sdk.Result{ - Code: sdk.CodeOK, + Code: sdk.ABCICodeOK, ValidatorUpdates: abci.Validators{valSet}, } } @@ -49,7 +49,7 @@ func handleUnbondMsg(ctx sdk.Context, k Keeper, msg UnbondMsg) sdk.Result { } return sdk.Result{ - Code: sdk.CodeOK, + Code: sdk.ABCICodeOK, ValidatorUpdates: abci.Validators{valSet}, } } diff --git a/x/simplestake/keeper.go b/x/simplestake/keeper.go index 7dcdbc20f..934d0b5a0 100644 --- a/x/simplestake/keeper.go +++ b/x/simplestake/keeper.go @@ -15,17 +15,19 @@ const moduleName = "simplestake" type Keeper struct { ck bank.CoinKeeper - key sdk.StoreKey - cdc *wire.Codec + key sdk.StoreKey + cdc *wire.Codec + codespace sdk.CodespaceType } -func NewKeeper(key sdk.StoreKey, coinKeeper bank.CoinKeeper) Keeper { +func NewKeeper(key sdk.StoreKey, coinKeeper bank.CoinKeeper, codespace sdk.CodespaceType) Keeper { cdc := wire.NewCodec() wire.RegisterCrypto(cdc) return Keeper{ - key: key, - cdc: cdc, - ck: coinKeeper, + key: key, + cdc: cdc, + ck: coinKeeper, + codespace: codespace, } } @@ -59,7 +61,7 @@ func (k Keeper) deleteBondInfo(ctx sdk.Context, addr sdk.Address) { func (k Keeper) Bond(ctx sdk.Context, addr sdk.Address, pubKey crypto.PubKey, stake sdk.Coin) (int64, sdk.Error) { if stake.Denom != stakingToken { - return 0, ErrIncorrectStakingToken() + return 0, ErrIncorrectStakingToken(k.codespace) } _, err := k.ck.SubtractCoins(ctx, addr, []sdk.Coin{stake}) @@ -84,7 +86,7 @@ func (k Keeper) Bond(ctx sdk.Context, addr sdk.Address, pubKey crypto.PubKey, st func (k Keeper) Unbond(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, int64, sdk.Error) { bi := k.getBondInfo(ctx, addr) if bi.isEmpty() { - return nil, 0, ErrInvalidUnbond() + return nil, 0, ErrInvalidUnbond(k.codespace) } k.deleteBondInfo(ctx, addr) @@ -102,7 +104,7 @@ func (k Keeper) Unbond(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, int64, func (k Keeper) bondWithoutCoins(ctx sdk.Context, addr sdk.Address, pubKey crypto.PubKey, stake sdk.Coin) (int64, sdk.Error) { if stake.Denom != stakingToken { - return 0, ErrIncorrectStakingToken() + return 0, ErrIncorrectStakingToken(k.codespace) } bi := k.getBondInfo(ctx, addr) @@ -122,7 +124,7 @@ func (k Keeper) bondWithoutCoins(ctx sdk.Context, addr sdk.Address, pubKey crypt func (k Keeper) unbondWithoutCoins(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, int64, sdk.Error) { bi := k.getBondInfo(ctx, addr) if bi.isEmpty() { - return nil, 0, ErrInvalidUnbond() + return nil, 0, ErrInvalidUnbond(k.codespace) } k.deleteBondInfo(ctx, addr) diff --git a/x/simplestake/keeper_test.go b/x/simplestake/keeper_test.go index 7f9a120b9..833227968 100644 --- a/x/simplestake/keeper_test.go +++ b/x/simplestake/keeper_test.go @@ -33,7 +33,7 @@ func TestKeeperGetSet(t *testing.T) { ms, _, capKey := setupMultiStore() ctx := sdk.NewContext(ms, abci.Header{}, false, nil) - stakeKeeper := NewKeeper(capKey, bank.NewCoinKeeper(nil)) + stakeKeeper := NewKeeper(capKey, bank.NewCoinKeeper(nil), DefaultCodespace) addr := sdk.Address([]byte("some-address")) bi := stakeKeeper.getBondInfo(ctx, addr) @@ -63,13 +63,13 @@ func TestBonding(t *testing.T) { accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{}) coinKeeper := bank.NewCoinKeeper(accountMapper) - stakeKeeper := NewKeeper(capKey, coinKeeper) + stakeKeeper := NewKeeper(capKey, coinKeeper, DefaultCodespace) addr := sdk.Address([]byte("some-address")) privKey := crypto.GenPrivKeyEd25519() pubKey := privKey.PubKey() _, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr) - assert.Equal(t, err, ErrInvalidUnbond()) + assert.Equal(t, err, ErrInvalidUnbond(DefaultCodespace)) _, err = stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.Coin{"steak", 10}) assert.Nil(t, err) @@ -82,5 +82,5 @@ func TestBonding(t *testing.T) { assert.Equal(t, pubKey, pk) _, _, err = stakeKeeper.unbondWithoutCoins(ctx, addr) - assert.Equal(t, err, ErrInvalidUnbond()) + assert.Equal(t, err, ErrInvalidUnbond(DefaultCodespace)) } diff --git a/x/simplestake/msgs.go b/x/simplestake/msgs.go index 9f4133484..963bfae7b 100644 --- a/x/simplestake/msgs.go +++ b/x/simplestake/msgs.go @@ -31,7 +31,7 @@ func (msg BondMsg) Type() string { func (msg BondMsg) ValidateBasic() sdk.Error { if msg.Stake.IsZero() { - return ErrEmptyStake() + return ErrEmptyStake(DefaultCodespace) } if msg.PubKey == nil { diff --git a/x/stake/errors.go b/x/stake/errors.go index e5b3e0cb3..008d51bc9 100644 --- a/x/stake/errors.go +++ b/x/stake/errors.go @@ -10,6 +10,8 @@ import ( type CodeType = sdk.CodeType const ( + DefaultCodespace sdk.CodespaceType = 4 + // Gaia errors reserve 200 ~ 299. CodeInvalidValidator CodeType = 201 CodeInvalidCandidate CodeType = 202 @@ -45,62 +47,62 @@ func codeToDefaultMsg(code CodeType) string { //---------------------------------------- // Error constructors -func ErrNotEnoughBondShares(shares string) sdk.Error { - return newError(CodeInvalidBond, fmt.Sprintf("not enough shares only have %v", shares)) +func ErrNotEnoughBondShares(codespace sdk.CodespaceType, shares string) sdk.Error { + return newError(codespace, CodeInvalidBond, fmt.Sprintf("not enough shares only have %v", shares)) } -func ErrCandidateEmpty() sdk.Error { - return newError(CodeInvalidValidator, "Cannot bond to an empty candidate") +func ErrCandidateEmpty(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Cannot bond to an empty candidate") } -func ErrBadBondingDenom() sdk.Error { - return newError(CodeInvalidBond, "Invalid coin denomination") +func ErrBadBondingDenom(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidBond, "Invalid coin denomination") } -func ErrBadBondingAmount() sdk.Error { - return newError(CodeInvalidBond, "Amount must be > 0") +func ErrBadBondingAmount(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidBond, "Amount must be > 0") } -func ErrNoBondingAcct() sdk.Error { - return newError(CodeInvalidValidator, "No bond account for this (address, validator) pair") +func ErrNoBondingAcct(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "No bond account for this (address, validator) pair") } -func ErrCommissionNegative() sdk.Error { - return newError(CodeInvalidValidator, "Commission must be positive") +func ErrCommissionNegative(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Commission must be positive") } -func ErrCommissionHuge() sdk.Error { - return newError(CodeInvalidValidator, "Commission cannot be more than 100%") +func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Commission cannot be more than 100%") } -func ErrBadValidatorAddr() sdk.Error { - return newError(CodeInvalidValidator, "Validator does not exist for that address") +func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Validator does not exist for that address") } -func ErrBadCandidateAddr() sdk.Error { - return newError(CodeInvalidValidator, "Candidate does not exist for that address") +func ErrBadCandidateAddr(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Candidate does not exist for that address") } -func ErrBadDelegatorAddr() sdk.Error { - return newError(CodeInvalidValidator, "Delegator does not exist for that address") +func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Delegator does not exist for that address") } -func ErrCandidateExistsAddr() sdk.Error { - return newError(CodeInvalidValidator, "Candidate already exist, cannot re-declare candidacy") +func ErrCandidateExistsAddr(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Candidate already exist, cannot re-declare candidacy") } -func ErrCandidateRevoked() sdk.Error { - return newError(CodeInvalidValidator, "Candidacy for this address is currently revoked") +func ErrCandidateRevoked(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Candidacy for this address is currently revoked") } -func ErrMissingSignature() sdk.Error { - return newError(CodeInvalidValidator, "Missing signature") +func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Missing signature") } -func ErrBondNotNominated() sdk.Error { - return newError(CodeInvalidValidator, "Cannot bond to non-nominated account") +func ErrBondNotNominated(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Cannot bond to non-nominated account") } -func ErrNoCandidateForAddress() sdk.Error { - return newError(CodeInvalidValidator, "Validator does not exist for that address") +func ErrNoCandidateForAddress(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Validator does not exist for that address") } -func ErrNoDelegatorForAddress() sdk.Error { - return newError(CodeInvalidValidator, "Delegator does not contain validator bond") +func ErrNoDelegatorForAddress(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Delegator does not contain validator bond") } -func ErrInsufficientFunds() sdk.Error { - return newError(CodeInvalidInput, "Insufficient bond shares") +func ErrInsufficientFunds(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidInput, "Insufficient bond shares") } -func ErrBadShares() sdk.Error { - return newError(CodeInvalidInput, "bad shares provided as input, must be MAX or decimal") +func ErrBadShares(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidInput, "bad shares provided as input, must be MAX or decimal") } -func ErrBadRemoveValidator() sdk.Error { - return newError(CodeInvalidValidator, "Error removing validator") +func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Error removing validator") } //---------------------------------------- @@ -114,7 +116,7 @@ func msgOrDefaultMsg(msg string, code CodeType) string { return codeToDefaultMsg(code) } -func newError(code CodeType, msg string) sdk.Error { +func newError(codespace sdk.CodespaceType, code CodeType, msg string) sdk.Error { msg = msgOrDefaultMsg(msg, code) - return sdk.NewError(code, msg) + return sdk.NewError(codespace, code, msg) } diff --git a/x/stake/handler.go b/x/stake/handler.go index 2f351a608..5f80ecb37 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -57,10 +57,10 @@ func handleMsgDeclareCandidacy(ctx sdk.Context, msg MsgDeclareCandidacy, k Keepe // check to see if the pubkey or sender has been registered before _, found := k.GetCandidate(ctx, msg.CandidateAddr) if found { - return ErrCandidateExistsAddr().Result() + return ErrCandidateExistsAddr(k.codespace).Result() } if msg.Bond.Denom != k.GetParams(ctx).BondDenom { - return ErrBadBondingDenom().Result() + return ErrBadBondingDenom(k.codespace).Result() } if ctx.IsCheckTx() { return sdk.Result{ @@ -85,7 +85,7 @@ func handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy, k Keeper) sdk // candidate must already be registered candidate, found := k.GetCandidate(ctx, msg.CandidateAddr) if !found { - return ErrBadCandidateAddr().Result() + return ErrBadCandidateAddr(k.codespace).Result() } if ctx.IsCheckTx() { return sdk.Result{ @@ -93,7 +93,7 @@ func handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy, k Keeper) sdk } } if candidate.Status == Unbonded { //candidate has been withdrawn - return ErrBondNotNominated().Result() + return ErrBondNotNominated(k.codespace).Result() } // XXX move to types @@ -111,13 +111,13 @@ func handleMsgDelegate(ctx sdk.Context, msg MsgDelegate, k Keeper) sdk.Result { candidate, found := k.GetCandidate(ctx, msg.CandidateAddr) if !found { - return ErrBadCandidateAddr().Result() + return ErrBadCandidateAddr(k.codespace).Result() } if msg.Bond.Denom != k.GetParams(ctx).BondDenom { - return ErrBadBondingDenom().Result() + return ErrBadBondingDenom(k.codespace).Result() } if candidate.Status == Revoked { - return ErrCandidateRevoked().Result() + return ErrCandidateRevoked(k.codespace).Result() } if ctx.IsCheckTx() { return sdk.Result{ @@ -165,10 +165,10 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result { // check if bond has any shares in it unbond bond, found := k.getDelegatorBond(ctx, msg.DelegatorAddr, msg.CandidateAddr) if !found { - return ErrNoDelegatorForAddress().Result() + return ErrNoDelegatorForAddress(k.codespace).Result() } if !bond.Shares.GT(sdk.ZeroRat) { // bond shares < msg shares - return ErrInsufficientFunds().Result() + return ErrInsufficientFunds(k.codespace).Result() } // test getting rational number from decimal provided @@ -180,18 +180,18 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result { // test that there are enough shares to unbond if msg.Shares == "MAX" { if !bond.Shares.GT(sdk.ZeroRat) { - return ErrNotEnoughBondShares(msg.Shares).Result() + return ErrNotEnoughBondShares(k.codespace, msg.Shares).Result() } } else { if bond.Shares.LT(shares) { - return ErrNotEnoughBondShares(msg.Shares).Result() + return ErrNotEnoughBondShares(k.codespace, msg.Shares).Result() } } // get candidate candidate, found := k.GetCandidate(ctx, msg.CandidateAddr) if !found { - return ErrNoCandidateForAddress().Result() + return ErrNoCandidateForAddress(k.codespace).Result() } if ctx.IsCheckTx() { diff --git a/x/stake/keeper.go b/x/stake/keeper.go index 0f29b177b..ae3dfb7c7 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -19,13 +19,17 @@ type Keeper struct { // caches gs Pool params Params + + // codespace + codespace sdk.CodespaceType } -func NewKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, ck bank.CoinKeeper) Keeper { +func NewKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, ck bank.CoinKeeper, codespace sdk.CodespaceType) Keeper { keeper := Keeper{ storeKey: key, cdc: cdc, coinKeeper: ck, + codespace: codespace, } return keeper } diff --git a/x/stake/msg.go b/x/stake/msg.go index 28a2edf79..b5ba09b5a 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -60,18 +60,18 @@ func (msg MsgDeclareCandidacy) GetSignBytes() []byte { // quick validity check func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error { if msg.CandidateAddr == nil { - return ErrCandidateEmpty() + return ErrCandidateEmpty(DefaultCodespace) } if msg.Bond.Denom != StakingToken { - return ErrBadBondingDenom() + return ErrBadBondingDenom(DefaultCodespace) } if msg.Bond.Amount <= 0 { - return ErrBadBondingAmount() + return ErrBadBondingAmount(DefaultCodespace) // return sdk.ErrInvalidCoins(sdk.Coins{msg.Bond}.String()) } empty := Description{} if msg.Description == empty { - return newError(CodeInvalidInput, "description must be included") + return newError(DefaultCodespace, CodeInvalidInput, "description must be included") } return nil } @@ -111,11 +111,11 @@ func (msg MsgEditCandidacy) GetSignBytes() []byte { // quick validity check func (msg MsgEditCandidacy) ValidateBasic() sdk.Error { if msg.CandidateAddr == nil { - return ErrCandidateEmpty() + return ErrCandidateEmpty(DefaultCodespace) } empty := Description{} if msg.Description == empty { - return newError(CodeInvalidInput, "Transaction must include some information to modify") + return newError(DefaultCodespace, CodeInvalidInput, "Transaction must include some information to modify") } return nil } @@ -157,16 +157,16 @@ func (msg MsgDelegate) GetSignBytes() []byte { // quick validity check func (msg MsgDelegate) ValidateBasic() sdk.Error { if msg.DelegatorAddr == nil { - return ErrBadDelegatorAddr() + return ErrBadDelegatorAddr(DefaultCodespace) } if msg.CandidateAddr == nil { - return ErrBadCandidateAddr() + return ErrBadCandidateAddr(DefaultCodespace) } if msg.Bond.Denom != StakingToken { - return ErrBadBondingDenom() + return ErrBadBondingDenom(DefaultCodespace) } if msg.Bond.Amount <= 0 { - return ErrBadBondingAmount() + return ErrBadBondingAmount(DefaultCodespace) // return sdk.ErrInvalidCoins(sdk.Coins{msg.Bond}.String()) } return nil @@ -209,18 +209,18 @@ func (msg MsgUnbond) GetSignBytes() []byte { // quick validity check func (msg MsgUnbond) ValidateBasic() sdk.Error { if msg.DelegatorAddr == nil { - return ErrBadDelegatorAddr() + return ErrBadDelegatorAddr(DefaultCodespace) } if msg.CandidateAddr == nil { - return ErrBadCandidateAddr() + return ErrBadCandidateAddr(DefaultCodespace) } if msg.Shares != "MAX" { rat, err := sdk.NewRatFromDecimal(msg.Shares) if err != nil { - return ErrBadShares() + return ErrBadShares(DefaultCodespace) } if rat.IsZero() || rat.LT(sdk.ZeroRat) { - return ErrBadShares() + return ErrBadShares(DefaultCodespace) } } return nil diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 395a5bce0..6470abbc7 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -132,7 +132,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context &auth.BaseAccount{}, // prototype ).Seal() ck := bank.NewCoinKeeper(accountMapper) - keeper := NewKeeper(ctx, cdc, keyStake, ck) + keeper := NewKeeper(ctx, cdc, keyStake, ck, DefaultCodespace) keeper.setPool(ctx, initialPool()) keeper.setParams(ctx, defaultParams())