From bdccbeff9e3a495cf7acdd737709775188fd5918 Mon Sep 17 00:00:00 2001 From: Joon Date: Fri, 13 Jul 2018 17:12:23 -0700 Subject: [PATCH 1/3] Merge PR #1265: Global Paramstore in progress in progress stake and slashing now params fix gaia fix gaia again add msg type deactivation delete local error in progress revert actual application in baseapp/gaia/stake add test, fix apps fix MinSignedPerWindow, pass lint fix gaia fix keeper_test fit with multiple msgs fix apply requests pass lint really the last fix fix dependency fix keeper_test fix lint --- cmd/gaia/app/app.go | 9 +- cmd/gaia/cmd/gaiadebug/hack.go | 7 +- x/params/keeper.go | 405 ++++++++++++++++++++++++++++++++ x/params/keeper_test.go | 280 ++++++++++++++++++++++ x/params/msg_status.go | 36 +++ x/slashing/app_test.go | 8 +- x/slashing/handler_test.go | 2 +- x/slashing/keeper.go | 30 ++- x/slashing/keeper_test.go | 39 ++- x/slashing/params.go | 96 +++++--- x/slashing/signing_info_test.go | 4 +- x/slashing/test_common.go | 10 +- x/slashing/tick_test.go | 6 +- 13 files changed, 855 insertions(+), 77 deletions(-) create mode 100644 x/params/keeper.go create mode 100644 x/params/keeper_test.go create mode 100644 x/params/msg_status.go diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index ac1d27d39d..7b0f85e306 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -18,6 +18,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -45,6 +46,7 @@ type GaiaApp struct { keySlashing *sdk.KVStoreKey keyGov *sdk.KVStoreKey keyFeeCollection *sdk.KVStoreKey + keyParams *sdk.KVStoreKey // Manage getting and setting accounts accountMapper auth.AccountMapper @@ -54,6 +56,7 @@ type GaiaApp struct { stakeKeeper stake.Keeper slashingKeeper slashing.Keeper govKeeper gov.Keeper + paramsKeeper params.Keeper } // NewGaiaApp returns a reference to an initialized GaiaApp. @@ -73,6 +76,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio keySlashing: sdk.NewKVStoreKey("slashing"), keyGov: sdk.NewKVStoreKey("gov"), keyFeeCollection: sdk.NewKVStoreKey("fee"), + keyParams: sdk.NewKVStoreKey("params"), } // define the accountMapper @@ -85,10 +89,11 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio // add handlers app.coinKeeper = bank.NewKeeper(app.accountMapper) app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace)) + app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams) app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace)) - app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace)) app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.coinKeeper, app.stakeKeeper, app.RegisterCodespace(gov.DefaultCodespace)) app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection) + app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace)) // register message routes app.Router(). @@ -103,7 +108,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio app.SetBeginBlocker(app.BeginBlocker) app.SetEndBlocker(app.EndBlocker) app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper)) - app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing, app.keyGov, app.keyFeeCollection) + app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyIBC, app.keyStake, app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams) err := app.LoadLatestVersion(app.keyMain) if err != nil { cmn.Exit(err.Error()) diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index 0d8af92eee..11d2dfa730 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -24,6 +24,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/ibc" + "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/stake" @@ -133,6 +134,7 @@ type GaiaApp struct { keyIBC *sdk.KVStoreKey keyStake *sdk.KVStoreKey keySlashing *sdk.KVStoreKey + keyParams *sdk.KVStoreKey // Manage getting and setting accounts accountMapper auth.AccountMapper @@ -141,6 +143,7 @@ type GaiaApp struct { ibcMapper ibc.Mapper stakeKeeper stake.Keeper slashingKeeper slashing.Keeper + paramsKeeper params.Keeper } func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp { @@ -158,6 +161,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp keyIBC: sdk.NewKVStoreKey("ibc"), keyStake: sdk.NewKVStoreKey("stake"), keySlashing: sdk.NewKVStoreKey("slashing"), + keyParams: sdk.NewKVStoreKey("params"), } // define the accountMapper @@ -170,8 +174,9 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseAp // add handlers app.coinKeeper = bank.NewKeeper(app.accountMapper) app.ibcMapper = ibc.NewMapper(app.cdc, app.keyIBC, app.RegisterCodespace(ibc.DefaultCodespace)) + app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams) app.stakeKeeper = stake.NewKeeper(app.cdc, app.keyStake, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace)) - app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.RegisterCodespace(slashing.DefaultCodespace)) + app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakeKeeper, app.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace)) // register message routes app.Router(). diff --git a/x/params/keeper.go b/x/params/keeper.go new file mode 100644 index 0000000000..8817b7c6c8 --- /dev/null +++ b/x/params/keeper.go @@ -0,0 +1,405 @@ +package params + +import ( + "fmt" + "reflect" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" +) + +// Keeper manages global parameter store +type Keeper struct { + cdc *wire.Codec + key sdk.StoreKey +} + +// NewKeeper constructs a new Keeper +func NewKeeper(cdc *wire.Codec, key sdk.StoreKey) Keeper { + return Keeper{ + cdc: cdc, + key: key, + } +} + +// InitKeeper constructs a new Keeper with initial parameters +func InitKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, params ...interface{}) Keeper { + if len(params)%2 != 0 { + panic("Odd params list length for InitKeeper") + } + + k := NewKeeper(cdc, key) + + for i := 0; i < len(params); i += 2 { + k.set(ctx, params[i].(string), params[i+1]) + } + + return k +} + +// get automatically unmarshalls parameter to pointer +func (k Keeper) get(ctx sdk.Context, key string, ptr interface{}) error { + store := ctx.KVStore(k.key) + bz := store.Get([]byte(key)) + return k.cdc.UnmarshalBinary(bz, ptr) +} + +// getRaw returns raw byte slice +func (k Keeper) getRaw(ctx sdk.Context, key string) []byte { + store := ctx.KVStore(k.key) + return store.Get([]byte(key)) +} + +// set automatically marshalls and type check parameter +func (k Keeper) set(ctx sdk.Context, key string, param interface{}) error { + store := ctx.KVStore(k.key) + bz := store.Get([]byte(key)) + if bz != nil { + ptrty := reflect.PtrTo(reflect.TypeOf(param)) + ptr := reflect.New(ptrty).Interface() + + if k.cdc.UnmarshalBinary(bz, ptr) != nil { + return fmt.Errorf("Type mismatch with stored param and provided param") + } + } + + bz, err := k.cdc.MarshalBinary(param) + if err != nil { + return err + } + store.Set([]byte(key), bz) + + return nil +} + +// setRaw sets raw byte slice +func (k Keeper) setRaw(ctx sdk.Context, key string, param []byte) { + store := ctx.KVStore(k.key) + store.Set([]byte(key), param) +} + +// Getter returns readonly struct +func (k Keeper) Getter() Getter { + return Getter{k} +} + +// Setter returns read/write struct +func (k Keeper) Setter() Setter { + return Setter{Getter{k}} +} + +// Getter exposes methods related with only getting params +type Getter struct { + k Keeper +} + +// Get exposes get +func (k Getter) Get(ctx sdk.Context, key string, ptr interface{}) error { + return k.k.get(ctx, key, ptr) +} + +// GetRaw exposes getRaw +func (k Getter) GetRaw(ctx sdk.Context, key string) []byte { + return k.k.getRaw(ctx, key) +} + +// GetString is helper function for string params +func (k Getter) GetString(ctx sdk.Context, key string) (res string, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetBool is helper function for bool params +func (k Getter) GetBool(ctx sdk.Context, key string) (res bool, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetInt16 is helper function for int16 params +func (k Getter) GetInt16(ctx sdk.Context, key string) (res int16, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetInt32 is helper function for int32 params +func (k Getter) GetInt32(ctx sdk.Context, key string) (res int32, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetInt64 is helper function for int64 params +func (k Getter) GetInt64(ctx sdk.Context, key string) (res int64, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetUint16 is helper function for uint16 params +func (k Getter) GetUint16(ctx sdk.Context, key string) (res uint16, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetUint32 is helper function for uint32 params +func (k Getter) GetUint32(ctx sdk.Context, key string) (res uint32, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetUint64 is helper function for uint64 params +func (k Getter) GetUint64(ctx sdk.Context, key string) (res uint64, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetInt is helper function for sdk.Int params +func (k Getter) GetInt(ctx sdk.Context, key string) (res sdk.Int, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetUint is helper function for sdk.Uint params +func (k Getter) GetUint(ctx sdk.Context, key string) (res sdk.Uint, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetRat is helper function for rat params +func (k Getter) GetRat(ctx sdk.Context, key string) (res sdk.Rat, err error) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + err = k.k.cdc.UnmarshalBinary(bz, &res) + return +} + +// GetStringWithDefault is helper function for string params with default value +func (k Getter) GetStringWithDefault(ctx sdk.Context, key string, def string) (res string) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetBoolWithDefault is helper function for bool params with default value +func (k Getter) GetBoolWithDefault(ctx sdk.Context, key string, def bool) (res bool) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetInt16WithDefault is helper function for int16 params with default value +func (k Getter) GetInt16WithDefault(ctx sdk.Context, key string, def int16) (res int16) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetInt32WithDefault is helper function for int32 params with default value +func (k Getter) GetInt32WithDefault(ctx sdk.Context, key string, def int32) (res int32) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetInt64WithDefault is helper function for int64 params with default value +func (k Getter) GetInt64WithDefault(ctx sdk.Context, key string, def int64) (res int64) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetUint16WithDefault is helper function for uint16 params with default value +func (k Getter) GetUint16WithDefault(ctx sdk.Context, key string, def uint16) (res uint16) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetUint32WithDefault is helper function for uint32 params with default value +func (k Getter) GetUint32WithDefault(ctx sdk.Context, key string, def uint32) (res uint32) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetUint64WithDefault is helper function for uint64 params with default value +func (k Getter) GetUint64WithDefault(ctx sdk.Context, key string, def uint64) (res uint64) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetIntWithDefault is helper function for sdk.Int params with default value +func (k Getter) GetIntWithDefault(ctx sdk.Context, key string, def sdk.Int) (res sdk.Int) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetUintWithDefault is helper function for sdk.Uint params with default value +func (k Getter) GetUintWithDefault(ctx sdk.Context, key string, def sdk.Uint) (res sdk.Uint) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// GetRatWithDefault is helper function for sdk.Rat params with default value +func (k Getter) GetRatWithDefault(ctx sdk.Context, key string, def sdk.Rat) (res sdk.Rat) { + store := ctx.KVStore(k.k.key) + bz := store.Get([]byte(key)) + if bz == nil { + return def + } + k.k.cdc.MustUnmarshalBinary(bz, &res) + return +} + +// Setter exposes all methods including Set +type Setter struct { + Getter +} + +// Set exposes set +func (k Setter) Set(ctx sdk.Context, key string, param interface{}) error { + return k.k.set(ctx, key, param) +} + +// SetRaw exposes setRaw +func (k Setter) SetRaw(ctx sdk.Context, key string, param []byte) { + k.k.setRaw(ctx, key, param) +} + +// SetString is helper function for string params +func (k Setter) SetString(ctx sdk.Context, key string, param string) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetBool is helper function for bool params +func (k Setter) SetBool(ctx sdk.Context, key string, param bool) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetInt16 is helper function for int16 params +func (k Setter) SetInt16(ctx sdk.Context, key string, param int16) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetInt32 is helper function for int32 params +func (k Setter) SetInt32(ctx sdk.Context, key string, param int32) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetInt64 is helper function for int64 params +func (k Setter) SetInt64(ctx sdk.Context, key string, param int64) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetUint16 is helper function for uint16 params +func (k Setter) SetUint16(ctx sdk.Context, key string, param uint16) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetUint32 is helper function for uint32 params +func (k Setter) SetUint32(ctx sdk.Context, key string, param uint32) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetUint64 is helper function for uint64 params +func (k Setter) SetUint64(ctx sdk.Context, key string, param uint64) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetInt is helper function for sdk.Int params +func (k Setter) SetInt(ctx sdk.Context, key string, param sdk.Int) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetUint is helper function for sdk.Uint params +func (k Setter) SetUint(ctx sdk.Context, key string, param sdk.Uint) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} + +// SetRat is helper function for rat params +func (k Setter) SetRat(ctx sdk.Context, key string, param sdk.Rat) { + if err := k.k.set(ctx, key, param); err != nil { + panic(err) + } +} diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go new file mode 100644 index 0000000000..4bb5744ea4 --- /dev/null +++ b/x/params/keeper_test.go @@ -0,0 +1,280 @@ +package params + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" +) + +func defaultContext(key sdk.StoreKey) sdk.Context { + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db) + cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + cms.LoadLatestVersion() + ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) + return ctx +} + +func TestKeeper(t *testing.T) { + kvs := []struct { + key string + param int64 + }{ + {"key1", 10}, + {"key2", 55}, + {"key3", 182}, + {"key4", 17582}, + {"key5", 2768554}, + } + + skey := sdk.NewKVStoreKey("test") + ctx := defaultContext(skey) + setter := NewKeeper(wire.NewCodec(), skey).Setter() + + for _, kv := range kvs { + err := setter.Set(ctx, kv.key, kv.param) + assert.Nil(t, err) + } + + for _, kv := range kvs { + var param int64 + err := setter.Get(ctx, kv.key, ¶m) + assert.Nil(t, err) + assert.Equal(t, kv.param, param) + } + + cdc := wire.NewCodec() + for _, kv := range kvs { + var param int64 + bz := setter.GetRaw(ctx, kv.key) + err := cdc.UnmarshalBinary(bz, ¶m) + assert.Nil(t, err) + assert.Equal(t, kv.param, param) + } + + for _, kv := range kvs { + var param bool + err := setter.Get(ctx, kv.key, ¶m) + assert.NotNil(t, err) + } + + for _, kv := range kvs { + err := setter.Set(ctx, kv.key, true) + assert.NotNil(t, err) + } +} + +func TestGetter(t *testing.T) { + key := sdk.NewKVStoreKey("test") + ctx := defaultContext(key) + keeper := NewKeeper(wire.NewCodec(), key) + + g := keeper.Getter() + s := keeper.Setter() + + kvs := []struct { + key string + param interface{} + }{ + {"string", "test"}, + {"bool", true}, + {"int16", int16(1)}, + {"int32", int32(1)}, + {"int64", int64(1)}, + {"uint16", uint16(1)}, + {"uint32", uint32(1)}, + {"uint64", uint64(1)}, + {"int", sdk.NewInt(1)}, + {"uint", sdk.NewUint(1)}, + {"rat", sdk.NewRat(1)}, + } + + assert.NotPanics(t, func() { s.SetString(ctx, kvs[0].key, "test") }) + assert.NotPanics(t, func() { s.SetBool(ctx, kvs[1].key, true) }) + assert.NotPanics(t, func() { s.SetInt16(ctx, kvs[2].key, int16(1)) }) + assert.NotPanics(t, func() { s.SetInt32(ctx, kvs[3].key, int32(1)) }) + assert.NotPanics(t, func() { s.SetInt64(ctx, kvs[4].key, int64(1)) }) + assert.NotPanics(t, func() { s.SetUint16(ctx, kvs[5].key, uint16(1)) }) + assert.NotPanics(t, func() { s.SetUint32(ctx, kvs[6].key, uint32(1)) }) + assert.NotPanics(t, func() { s.SetUint64(ctx, kvs[7].key, uint64(1)) }) + assert.NotPanics(t, func() { s.SetInt(ctx, kvs[8].key, sdk.NewInt(1)) }) + assert.NotPanics(t, func() { s.SetUint(ctx, kvs[9].key, sdk.NewUint(1)) }) + assert.NotPanics(t, func() { s.SetRat(ctx, kvs[10].key, sdk.NewRat(1)) }) + + var res interface{} + var err error + + // String + def0 := "default" + res, err = g.GetString(ctx, kvs[0].key) + assert.Nil(t, err) + assert.Equal(t, kvs[0].param, res) + + _, err = g.GetString(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetStringWithDefault(ctx, kvs[0].key, def0) + assert.Equal(t, kvs[0].param, res) + + res = g.GetStringWithDefault(ctx, "invalid", def0) + assert.Equal(t, def0, res) + + // Bool + def1 := false + res, err = g.GetBool(ctx, kvs[1].key) + assert.Nil(t, err) + assert.Equal(t, kvs[1].param, res) + + _, err = g.GetBool(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetBoolWithDefault(ctx, kvs[1].key, def1) + assert.Equal(t, kvs[1].param, res) + + res = g.GetBoolWithDefault(ctx, "invalid", def1) + assert.Equal(t, def1, res) + + // Int16 + def2 := int16(0) + res, err = g.GetInt16(ctx, kvs[2].key) + assert.Nil(t, err) + assert.Equal(t, kvs[2].param, res) + + _, err = g.GetInt16(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetInt16WithDefault(ctx, kvs[2].key, def2) + assert.Equal(t, kvs[2].param, res) + + res = g.GetInt16WithDefault(ctx, "invalid", def2) + assert.Equal(t, def2, res) + + // Int32 + def3 := int32(0) + res, err = g.GetInt32(ctx, kvs[3].key) + assert.Nil(t, err) + assert.Equal(t, kvs[3].param, res) + + _, err = g.GetInt32(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetInt32WithDefault(ctx, kvs[3].key, def3) + assert.Equal(t, kvs[3].param, res) + + res = g.GetInt32WithDefault(ctx, "invalid", def3) + assert.Equal(t, def3, res) + + // Int64 + def4 := int64(0) + res, err = g.GetInt64(ctx, kvs[4].key) + assert.Nil(t, err) + assert.Equal(t, kvs[4].param, res) + + _, err = g.GetInt64(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetInt64WithDefault(ctx, kvs[4].key, def4) + assert.Equal(t, kvs[4].param, res) + + res = g.GetInt64WithDefault(ctx, "invalid", def4) + assert.Equal(t, def4, res) + + // Uint16 + def5 := uint16(0) + res, err = g.GetUint16(ctx, kvs[5].key) + assert.Nil(t, err) + assert.Equal(t, kvs[5].param, res) + + _, err = g.GetUint16(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetUint16WithDefault(ctx, kvs[5].key, def5) + assert.Equal(t, kvs[5].param, res) + + res = g.GetUint16WithDefault(ctx, "invalid", def5) + assert.Equal(t, def5, res) + + // Uint32 + def6 := uint32(0) + res, err = g.GetUint32(ctx, kvs[6].key) + assert.Nil(t, err) + assert.Equal(t, kvs[6].param, res) + + _, err = g.GetUint32(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetUint32WithDefault(ctx, kvs[6].key, def6) + assert.Equal(t, kvs[6].param, res) + + res = g.GetUint32WithDefault(ctx, "invalid", def6) + assert.Equal(t, def6, res) + + // Uint64 + def7 := uint64(0) + res, err = g.GetUint64(ctx, kvs[7].key) + assert.Nil(t, err) + assert.Equal(t, kvs[7].param, res) + + _, err = g.GetUint64(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetUint64WithDefault(ctx, kvs[7].key, def7) + assert.Equal(t, kvs[7].param, res) + + res = g.GetUint64WithDefault(ctx, "invalid", def7) + assert.Equal(t, def7, res) + + // Int + def8 := sdk.NewInt(0) + res, err = g.GetInt(ctx, kvs[8].key) + assert.Nil(t, err) + assert.Equal(t, kvs[8].param, res) + + _, err = g.GetInt(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetIntWithDefault(ctx, kvs[8].key, def8) + assert.Equal(t, kvs[8].param, res) + + res = g.GetIntWithDefault(ctx, "invalid", def8) + assert.Equal(t, def8, res) + + // Uint + def9 := sdk.NewUint(0) + res, err = g.GetUint(ctx, kvs[9].key) + assert.Nil(t, err) + assert.Equal(t, kvs[9].param, res) + + _, err = g.GetUint(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetUintWithDefault(ctx, kvs[9].key, def9) + assert.Equal(t, kvs[9].param, res) + + res = g.GetUintWithDefault(ctx, "invalid", def9) + assert.Equal(t, def9, res) + + // Rat + def10 := sdk.NewRat(0) + res, err = g.GetRat(ctx, kvs[10].key) + assert.Nil(t, err) + assert.Equal(t, kvs[10].param, res) + + _, err = g.GetRat(ctx, "invalid") + assert.NotNil(t, err) + + res = g.GetRatWithDefault(ctx, kvs[10].key, def10) + assert.Equal(t, kvs[10].param, res) + + res = g.GetRatWithDefault(ctx, "invalid", def10) + assert.Equal(t, def10, res) + +} diff --git a/x/params/msg_status.go b/x/params/msg_status.go new file mode 100644 index 0000000000..72704e4dc7 --- /dev/null +++ b/x/params/msg_status.go @@ -0,0 +1,36 @@ +package params + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// GenesisState defines initial activated msg types +type GenesisState struct { + ActivatedTypes []string `json:"activated-types"` +} + +// ActivatedParamKey - paramstore key for msg type activation +func ActivatedParamKey(ty string) string { + return "Activated/" + ty +} + +// InitGenesis stores activated type to param store +func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { + for _, ty := range data.ActivatedTypes { + k.set(ctx, ActivatedParamKey(ty), true) + } +} + +// NewAnteHandler returns an AnteHandler that checks +// whether msg type is activate or not +func NewAnteHandler(k Keeper) sdk.AnteHandler { + return func(ctx sdk.Context, tx sdk.Tx) (sdk.Context, sdk.Result, bool) { + for _, msg := range tx.GetMsgs() { + ok := k.Getter().GetBoolWithDefault(ctx, ActivatedParamKey(msg.Type()), false) + if !ok { + return ctx, sdk.ErrUnauthorized("deactivated msg type").Result(), true + } + } + return ctx, sdk.Result{}, false + } +} diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index c249134ac1..4531c3882c 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/mock" + "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/stake" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" @@ -26,15 +27,18 @@ func getMockApp(t *testing.T) (*mock.App, stake.Keeper, Keeper) { RegisterWire(mapp.Cdc) keyStake := sdk.NewKVStoreKey("stake") keySlashing := sdk.NewKVStoreKey("slashing") + keyParams := sdk.NewKVStoreKey("params") coinKeeper := bank.NewKeeper(mapp.AccountMapper) + paramsKeeper := params.NewKeeper(mapp.Cdc, keyParams) stakeKeeper := stake.NewKeeper(mapp.Cdc, keyStake, coinKeeper, mapp.RegisterCodespace(stake.DefaultCodespace)) - keeper := NewKeeper(mapp.Cdc, keySlashing, stakeKeeper, mapp.RegisterCodespace(DefaultCodespace)) + + keeper := NewKeeper(mapp.Cdc, keySlashing, stakeKeeper, paramsKeeper.Getter(), mapp.RegisterCodespace(DefaultCodespace)) mapp.Router().AddRoute("stake", stake.NewHandler(stakeKeeper)) mapp.Router().AddRoute("slashing", NewHandler(keeper)) mapp.SetEndBlocker(getEndBlocker(stakeKeeper)) mapp.SetInitChainer(getInitChainer(mapp, stakeKeeper)) - require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake, keySlashing})) + require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake, keySlashing, keyParams})) return mapp, stakeKeeper, keeper } diff --git a/x/slashing/handler_test.go b/x/slashing/handler_test.go index d5a6b15dbb..89c1e11a60 100644 --- a/x/slashing/handler_test.go +++ b/x/slashing/handler_test.go @@ -11,7 +11,7 @@ import ( func TestCannotUnrevokeUnlessRevoked(t *testing.T) { // initial setup - ctx, ck, sk, keeper := createTestInput(t) + ctx, ck, sk, _, keeper := createTestInput(t) slh := NewHandler(keeper) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 9f1ff205b5..3d721f4a45 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -5,6 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/params" "github.com/tendermint/tendermint/crypto" ) @@ -13,17 +14,19 @@ type Keeper struct { storeKey sdk.StoreKey cdc *wire.Codec validatorSet sdk.ValidatorSet + params params.Getter // codespace codespace sdk.CodespaceType } // NewKeeper creates a slashing keeper -func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, codespace sdk.CodespaceType) Keeper { +func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, params params.Getter, codespace sdk.CodespaceType) Keeper { keeper := Keeper{ storeKey: key, cdc: cdc, validatorSet: vs, + params: params, codespace: codespace, } return keeper @@ -37,16 +40,17 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infracti address := sdk.ValAddress(pubkey.Address()) // Double sign too old - if age > MaxEvidenceAge { - logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", pubkey.Address(), infractionHeight, age, MaxEvidenceAge)) + maxEvidenceAge := k.MaxEvidenceAge(ctx) + if age > maxEvidenceAge { + logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d", pubkey.Address(), infractionHeight, age, maxEvidenceAge)) return } // Double sign confirmed - logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), infractionHeight, age, MaxEvidenceAge)) + logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d less than max age of %d", pubkey.Address(), infractionHeight, age, maxEvidenceAge)) // Slash validator - k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, SlashFractionDoubleSign) + k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, k.SlashFractionDoubleSign(ctx)) // Revoke validator k.validatorSet.Revoke(ctx, pubkey) @@ -56,7 +60,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infracti if !found { panic(fmt.Sprintf("Expected signing info for validator %s but not found", address)) } - signInfo.JailedUntil = time + DoubleSignUnbondDuration + signInfo.JailedUntil = time + k.DoubleSignUnbondDuration(ctx) k.setValidatorSigningInfo(ctx, address, signInfo) } @@ -73,7 +77,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, // If this validator has never been seen before, construct a new SigningInfo with the correct start height signInfo = NewValidatorSigningInfo(height, 0, 0, 0) } - index := signInfo.IndexOffset % SignedBlocksWindow + index := signInfo.IndexOffset % k.SignedBlocksWindow(ctx) signInfo.IndexOffset++ // Update signed block bit array & counter @@ -93,15 +97,15 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, } if !signed { - logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", pubkey.Address(), height, signInfo.SignedBlocksCounter, MinSignedPerWindow)) + logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", pubkey.Address(), height, signInfo.SignedBlocksCounter, k.MinSignedPerWindow(ctx))) } - minHeight := signInfo.StartHeight + SignedBlocksWindow - if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { + minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx) + if height > minHeight && signInfo.SignedBlocksCounter < k.MinSignedPerWindow(ctx) { // Downtime confirmed, slash, revoke, and jail the validator - logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow)) - k.validatorSet.Slash(ctx, pubkey, height, power, SlashFractionDowntime) + logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, k.MinSignedPerWindow(ctx))) + k.validatorSet.Slash(ctx, pubkey, height, power, k.SlashFractionDowntime(ctx)) k.validatorSet.Revoke(ctx, pubkey) - signInfo.JailedUntil = ctx.BlockHeader().Time + DowntimeUnbondDuration + signInfo.JailedUntil = ctx.BlockHeader().Time + k.DowntimeUnbondDuration(ctx) } // Set the updated signing info diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 794bc2c92c..71ac3b099c 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -14,10 +14,9 @@ import ( // Have to change these parameters for tests // lest the tests take forever func init() { - SignedBlocksWindow = 1000 - MinSignedPerWindow = SignedBlocksWindow / 2 - DowntimeUnbondDuration = 60 * 60 - DoubleSignUnbondDuration = 60 * 60 + defaultSignedBlocksWindow = 1000 + defaultDowntimeUnbondDuration = 60 * 60 + defaultDoubleSignUnbondDuration = 60 * 60 } // Test that a validator is slashed correctly @@ -25,7 +24,7 @@ func init() { func TestHandleDoubleSign(t *testing.T) { // initial setup - ctx, ck, sk, keeper := createTestInput(t) + ctx, ck, sk, _, keeper := createTestInput(t) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) @@ -46,7 +45,7 @@ func TestHandleDoubleSign(t *testing.T) { sk.Unrevoke(ctx, val) // power should be reduced require.Equal(t, sdk.NewRatFromInt(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower()) - ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + MaxEvidenceAge}) + ctx = ctx.WithBlockHeader(abci.Header{Time: 1 + keeper.MaxEvidenceAge(ctx)}) // double sign past max age keeper.handleDoubleSign(ctx, val, 0, 0, amtInt) @@ -58,7 +57,7 @@ func TestHandleDoubleSign(t *testing.T) { func TestHandleAbsentValidator(t *testing.T) { // initial setup - ctx, ck, sk, keeper := createTestInput(t) + ctx, ck, sk, _, keeper := createTestInput(t) amtInt := int64(100) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) sh := stake.NewHandler(sk) @@ -77,24 +76,24 @@ func TestHandleAbsentValidator(t *testing.T) { height := int64(0) // 1000 first blocks OK - for ; height < SignedBlocksWindow; height++ { + for ; height < keeper.SignedBlocksWindow(ctx); height++ { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, amtInt, true) } info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, SignedBlocksWindow, info.SignedBlocksCounter) + require.Equal(t, keeper.SignedBlocksWindow(ctx), info.SignedBlocksCounter) // 500 blocks missed - for ; height < SignedBlocksWindow+(SignedBlocksWindow-MinSignedPerWindow); height++ { + for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)); height++ { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, amtInt, false) } info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, SignedBlocksWindow-MinSignedPerWindow, info.SignedBlocksCounter) + require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.SignedBlocksCounter) // validator should be bonded still validator, _ := sk.GetValidatorByPubKey(ctx, val) @@ -108,7 +107,7 @@ func TestHandleAbsentValidator(t *testing.T) { info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.True(t, found) require.Equal(t, int64(0), info.StartHeight) - require.Equal(t, SignedBlocksWindow-MinSignedPerWindow-1, info.SignedBlocksCounter) + require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter) // validator should have been revoked validator, _ = sk.GetValidatorByPubKey(ctx, val) @@ -119,7 +118,7 @@ func TestHandleAbsentValidator(t *testing.T) { require.False(t, got.IsOK()) // unrevocation should succeed after jail expiration - ctx = ctx.WithBlockHeader(abci.Header{Time: DowntimeUnbondDuration + 1}) + ctx = ctx.WithBlockHeader(abci.Header{Time: keeper.DowntimeUnbondDuration(ctx) + 1}) got = slh(ctx, NewMsgUnrevoke(addr)) require.True(t, got.IsOK()) @@ -135,7 +134,7 @@ func TestHandleAbsentValidator(t *testing.T) { info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.True(t, found) require.Equal(t, height, info.StartHeight) - require.Equal(t, SignedBlocksWindow-MinSignedPerWindow-1, info.SignedBlocksCounter) + require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter) // validator should not be immediately revoked again height++ @@ -145,14 +144,14 @@ func TestHandleAbsentValidator(t *testing.T) { require.Equal(t, sdk.Bonded, validator.GetStatus()) // 500 signed blocks - nextHeight := height + MinSignedPerWindow + 1 + nextHeight := height + keeper.MinSignedPerWindow(ctx) + 1 for ; height < nextHeight; height++ { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, amtInt, false) } // validator should be revoked again after 500 unsigned blocks - nextHeight = height + MinSignedPerWindow + 1 + nextHeight = height + keeper.MinSignedPerWindow(ctx) + 1 for ; height <= nextHeight; height++ { ctx = ctx.WithBlockHeight(height) keeper.handleValidatorSignature(ctx, val, amtInt, false) @@ -166,7 +165,7 @@ func TestHandleAbsentValidator(t *testing.T) { // and that they are not immediately revoked func TestHandleNewValidator(t *testing.T) { // initial setup - ctx, ck, sk, keeper := createTestInput(t) + ctx, ck, sk, _, keeper := createTestInput(t) addr, val, amt := addrs[0], pks[0], int64(100) sh := stake.NewHandler(sk) got := sh(ctx, newTestMsgCreateValidator(addr, val, sdk.NewInt(amt))) @@ -176,16 +175,16 @@ func TestHandleNewValidator(t *testing.T) { require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower()) // 1000 first blocks not a validator - ctx = ctx.WithBlockHeight(SignedBlocksWindow + 1) + ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1) // Now a validator, for two blocks keeper.handleValidatorSignature(ctx, val, 100, true) - ctx = ctx.WithBlockHeight(SignedBlocksWindow + 2) + ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 2) keeper.handleValidatorSignature(ctx, val, 100, false) info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address())) require.True(t, found) - require.Equal(t, int64(SignedBlocksWindow+1), info.StartHeight) + require.Equal(t, int64(keeper.SignedBlocksWindow(ctx)+1), info.StartHeight) require.Equal(t, int64(2), info.IndexOffset) require.Equal(t, int64(1), info.SignedBlocksCounter) require.Equal(t, int64(0), info.JailedUntil) diff --git a/x/slashing/params.go b/x/slashing/params.go index ebf14f283d..b0c85698ca 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -4,39 +4,75 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +// nolint +const ( + MaxEvidenceAgeKey = "slashing/MaxEvidenceAge" + SignedBlocksWindowKey = "slashing/SignedBlocksWindow" + MinSignedPerWindowKey = "slashing/MinSignedPerWindow" + DoubleSignUnbondDurationKey = "slashing/DoubleSignUnbondDuration" + DowntimeUnbondDurationKey = "slashing/DowntimeUnbondDuration" + SlashFractionDoubleSignKey = "slashing/SlashFractionDoubleSign" + SlashFractionDowntimeKey = "slashing/SlashFractionDowntime" +) + +// MaxEvidenceAge - Max age for evidence - 21 days (3 weeks) +// MaxEvidenceAge = 60 * 60 * 24 * 7 * 3 +func (k Keeper) MaxEvidenceAge(ctx sdk.Context) int64 { + return k.params.GetInt64WithDefault(ctx, MaxEvidenceAgeKey, defaultMaxEvidenceAge) +} + +// SignedBlocksWindow - sliding window for downtime slashing +func (k Keeper) SignedBlocksWindow(ctx sdk.Context) int64 { + return k.params.GetInt64WithDefault(ctx, SignedBlocksWindowKey, defaultSignedBlocksWindow) +} + +// Downtime slashing thershold - default 50% +func (k Keeper) MinSignedPerWindow(ctx sdk.Context) int64 { + minSignedPerWindow := k.params.GetRatWithDefault(ctx, MinSignedPerWindowKey, defaultMinSignedPerWindow) + signedBlocksWindow := k.SignedBlocksWindow(ctx) + return sdk.NewRat(signedBlocksWindow).Mul(minSignedPerWindow).RoundInt64() +} + +// Double-sign unbond duration +func (k Keeper) DoubleSignUnbondDuration(ctx sdk.Context) int64 { + return k.params.GetInt64WithDefault(ctx, DoubleSignUnbondDurationKey, defaultDoubleSignUnbondDuration) +} + +// Downtime unbond duration +func (k Keeper) DowntimeUnbondDuration(ctx sdk.Context) int64 { + return k.params.GetInt64WithDefault(ctx, DowntimeUnbondDurationKey, defaultDowntimeUnbondDuration) +} + +// SlashFractionDoubleSign - currently default 5% +func (k Keeper) SlashFractionDoubleSign(ctx sdk.Context) sdk.Rat { + return k.params.GetRatWithDefault(ctx, SlashFractionDoubleSignKey, defaultSlashFractionDoubleSign) +} + +// SlashFractionDowntime - currently default 1% +func (k Keeper) SlashFractionDowntime(ctx sdk.Context) sdk.Rat { + return k.params.GetRatWithDefault(ctx, SlashFractionDowntimeKey, defaultSlashFractionDowntime) +} + +// declared as var because of keeper_test.go +// TODO: make it const or parameter of NewKeeper + var ( - // MaxEvidenceAge - Max age for evidence - 21 days (3 weeks) - // TODO Should this be a governance parameter or just modifiable with SoftwareUpgradeProposals? - // MaxEvidenceAge = 60 * 60 * 24 * 7 * 3 + // defaultMaxEvidenceAge = 60 * 60 * 24 * 7 * 3 // TODO Temporarily set to 2 minutes for testnets. - MaxEvidenceAge int64 = 60 * 2 + defaultMaxEvidenceAge int64 = 60 * 2 - // SignedBlocksWindow - sliding window for downtime slashing - // TODO Governance parameter? - // TODO Temporarily set to 40000 blocks for testnets - SignedBlocksWindow int64 = 40000 - - // Downtime slashing threshold - 50% - // TODO Governance parameter? - MinSignedPerWindow = SignedBlocksWindow / 2 - - // Downtime unbond duration - // TODO Governance parameter? // TODO Temporarily set to five minutes for testnets - DowntimeUnbondDuration int64 = 60 * 5 + defaultDoubleSignUnbondDuration int64 = 60 * 5 - // Double-sign unbond duration - // TODO Governance parameter? - // TODO Temporarily set to five minutes for testnets - DoubleSignUnbondDuration int64 = 60 * 5 -) - -var ( - // SlashFractionDoubleSign - currently 5% - // TODO Governance parameter? - SlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20)) - - // SlashFractionDowntime - currently 1% - // TODO Governance parameter? - SlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100)) + // TODO Temporarily set to 100 blocks for testnets + defaultSignedBlocksWindow int64 = 100 + + // TODO Temporarily set to 10 minutes for testnets + defaultDowntimeUnbondDuration int64 = 60 * 10 + + defaultMinSignedPerWindow sdk.Rat = sdk.NewRat(1, 2) + + defaultSlashFractionDoubleSign = sdk.NewRat(1).Quo(sdk.NewRat(20)) + + defaultSlashFractionDowntime = sdk.NewRat(1).Quo(sdk.NewRat(100)) ) diff --git a/x/slashing/signing_info_test.go b/x/slashing/signing_info_test.go index 742769013a..b2da974e79 100644 --- a/x/slashing/signing_info_test.go +++ b/x/slashing/signing_info_test.go @@ -9,7 +9,7 @@ import ( ) func TestGetSetValidatorSigningInfo(t *testing.T) { - ctx, _, _, keeper := createTestInput(t) + ctx, _, _, _, keeper := createTestInput(t) info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(addrs[0])) require.False(t, found) newInfo := ValidatorSigningInfo{ @@ -28,7 +28,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) { } func TestGetSetValidatorSigningBitArray(t *testing.T) { - ctx, _, _, keeper := createTestInput(t) + ctx, _, _, _, keeper := createTestInput(t) signed := keeper.getValidatorSigningBitArray(ctx, sdk.ValAddress(addrs[0]), 0) require.False(t, signed) // treat empty key as unsigned keeper.setValidatorSigningBitArray(ctx, sdk.ValAddress(addrs[0]), 0, true) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index 4647961922..5cec7ce788 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -17,6 +17,7 @@ import ( "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -46,21 +47,24 @@ func createTestCodec() *wire.Codec { return cdc } -func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keeper) { +func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, params.Setter, Keeper) { keyAcc := sdk.NewKVStoreKey("acc") keyStake := sdk.NewKVStoreKey("stake") keySlashing := sdk.NewKVStoreKey("slashing") + keyParams := sdk.NewKVStoreKey("params") db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyStake, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db) + ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db) err := ms.LoadLatestVersion() require.Nil(t, err) ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewTMLogger(os.Stdout)) cdc := createTestCodec() accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount) ck := bank.NewKeeper(accountMapper) + params := params.NewKeeper(cdc, keyParams) sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace) genesis := stake.DefaultGenesisState() @@ -75,8 +79,8 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep }) } require.Nil(t, err) - keeper := NewKeeper(cdc, keySlashing, sk, DefaultCodespace) - return ctx, ck, sk, keeper + keeper := NewKeeper(cdc, keySlashing, sk, params.Getter(), DefaultCodespace) + return ctx, ck, sk, params.Setter(), keeper } func newPubKey(pk string) (res crypto.PubKey) { diff --git a/x/slashing/tick_test.go b/x/slashing/tick_test.go index 247fe0972a..38e339e590 100644 --- a/x/slashing/tick_test.go +++ b/x/slashing/tick_test.go @@ -13,7 +13,7 @@ import ( ) func TestBeginBlocker(t *testing.T) { - ctx, ck, sk, keeper := createTestInput(t) + ctx, ck, sk, _, keeper := createTestInput(t) addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100) // bond the validator @@ -47,7 +47,7 @@ func TestBeginBlocker(t *testing.T) { height := int64(0) // for 1000 blocks, mark the validator as having signed - for ; height < SignedBlocksWindow; height++ { + for ; height < keeper.SignedBlocksWindow(ctx); height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ Validators: []abci.SigningValidator{{ @@ -59,7 +59,7 @@ func TestBeginBlocker(t *testing.T) { } // for 500 blocks, mark the validator as having not signed - for ; height < ((SignedBlocksWindow * 2) - MinSignedPerWindow + 1); height++ { + for ; height < ((keeper.SignedBlocksWindow(ctx) * 2) - keeper.MinSignedPerWindow(ctx) + 1); height++ { ctx = ctx.WithBlockHeight(height) req = abci.RequestBeginBlock{ Validators: []abci.SigningValidator{{ From bb1f1a21bf540dad6b1d39d2c013b5cef59559c0 Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 13 Jul 2018 22:17:53 -0400 Subject: [PATCH 2/3] Fix Cross Compile Build/Ledger Build Tag (#1674) * Merge pull request #1674: Fix Cross Compile Build/Ledger Build Tag * Merge pull request #1674: Fix Cross Compile Build/Ledger Build Tag * Remove incorrect Ledger test --- CHANGELOG.md | 2 + Gopkg.lock | 184 ++++++++++++++++++++++++++++++++---- Gopkg.toml | 2 +- Makefile | 36 +++++--- crypto/keys/keybase.go | 37 ++++---- crypto/ledger.go | 18 ++++ crypto/ledger_common.go | 19 ---- crypto/ledger_secp256k1.go | 185 ++++++++++++++++++++++--------------- crypto/ledger_test.go | 32 +++---- 9 files changed, 356 insertions(+), 159 deletions(-) create mode 100644 crypto/ledger.go delete mode 100644 crypto/ledger_common.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 547ab53459..532e981550 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ BUG FIXES * [keys] \#1629 - updating password no longer asks for a new password when the first entered password was incorrect * [lcd] importing an account would create a random account * [server] 'gaiad init' command family now writes provided name as the moniker in `config.toml` +* [build] Added Ledger build support via `LEDGER_ENABLED=true|false` + * True by default except when cross-compiling ## 0.20.0 diff --git a/Gopkg.lock b/Gopkg.lock index ee1b5cf1ee..a1372b1fa8 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -3,59 +3,78 @@ [[projects]] branch = "master" + digest = "1:09a7f74eb6bb3c0f14d8926610c87f569c5cff68e978d30e9a3540aeb626fdf0" name = "github.com/bartekn/go-bip39" packages = ["."] + pruneopts = "UT" revision = "a05967ea095d81c8fe4833776774cfaff8e5036c" [[projects]] branch = "master" + digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d" name = "github.com/beorn7/perks" packages = ["quantile"] + pruneopts = "UT" revision = "3a771d992973f24aa725d07868b467d1ddfceafb" [[projects]] + digest = "1:1343a2963481a305ca4d051e84bc2abd16b601ee22ed324f8d605de1adb291b0" name = "github.com/bgentry/speakeasy" packages = ["."] + pruneopts = "UT" revision = "4aabc24848ce5fd31929f7d1e4ea74d3709c14cd" version = "v0.1.0" [[projects]] branch = "master" + digest = "1:70f6b224a59b2fa453debffa85c77f71063d8754b90c8c4fbad5794e2c382b0f" name = "github.com/brejski/hid" packages = ["."] + pruneopts = "UT" revision = "06112dcfcc50a7e0e4fd06e17f9791e788fdaafc" [[projects]] branch = "master" + digest = "1:6aabc1566d6351115d561d038da82a4c19b46c3b6e17f4a0a2fa60260663dc79" name = "github.com/btcsuite/btcd" packages = ["btcec"] + pruneopts = "UT" revision = "fdfc19097e7ac6b57035062056f5b7b4638b8898" [[projects]] branch = "master" + digest = "1:386de157f7d19259a7f9c81f26ce011223ce0f090353c1152ffdf730d7d10ac2" name = "github.com/btcsuite/btcutil" packages = ["bech32"] + pruneopts = "UT" revision = "ab6388e0c60ae4834a1f57511e20c17b5f78be4b" [[projects]] + digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39" name = "github.com/davecgh/go-spew" packages = ["spew"] + pruneopts = "UT" revision = "346938d642f2ec3594ed81d874461961cd0faa76" version = "v1.1.0" [[projects]] branch = "master" + digest = "1:c7644c73a3d23741fdba8a99b1464e021a224b7e205be497271a8003a15ca41b" name = "github.com/ebuchman/fail-test" packages = ["."] + pruneopts = "UT" revision = "95f809107225be108efcf10a3509e4ea6ceef3c4" [[projects]] + digest = "1:abeb38ade3f32a92943e5be54f55ed6d6e3b6602761d74b4aab4c9dd45c18abd" name = "github.com/fsnotify/fsnotify" packages = ["."] + pruneopts = "UT" revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9" version = "v1.4.7" [[projects]] + digest = "1:fa30c0652956e159cdb97dcb2ef8b8db63ed668c02a5c3a40961c8f0641252fe" name = "github.com/go-kit/kit" packages = [ "log", @@ -64,24 +83,30 @@ "metrics", "metrics/discard", "metrics/internal/lv", - "metrics/prometheus" + "metrics/prometheus", ] + pruneopts = "UT" revision = "4dc7be5d2d12881735283bcab7352178e190fc71" version = "v0.6.0" [[projects]] + digest = "1:31a18dae27a29aa074515e43a443abfd2ba6deb6d69309d8d7ce789c45f34659" name = "github.com/go-logfmt/logfmt" packages = ["."] + pruneopts = "UT" revision = "390ab7935ee28ec6b286364bba9b4dd6410cb3d5" version = "v0.3.0" [[projects]] + digest = "1:c4a2528ccbcabf90f9f3c464a5fc9e302d592861bbfd0b7135a7de8a943d0406" name = "github.com/go-stack/stack" packages = ["."] + pruneopts = "UT" revision = "259ab82a6cad3992b4e21ff5cac294ccb06474bc" version = "v1.7.0" [[projects]] + digest = "1:af1306bff89268721ea2550d504413c9487ebfca11e2ff8f39ae79b99a720ff5" name = "github.com/gogo/protobuf" packages = [ "gogoproto", @@ -89,49 +114,61 @@ "proto", "protoc-gen-gogo/descriptor", "sortkeys", - "types" + "types", ] + pruneopts = "UT" revision = "1adfc126b41513cc696b209667c8656ea7aac67c" version = "v1.0.0" [[projects]] + digest = "1:cb22af0ed7c72d495d8be1106233ee553898950f15fd3f5404406d44c2e86888" name = "github.com/golang/protobuf" packages = [ "proto", "ptypes", "ptypes/any", "ptypes/duration", - "ptypes/timestamp" + "ptypes/timestamp", ] + pruneopts = "UT" revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" version = "v1.1.0" [[projects]] branch = "master" + digest = "1:4a0c6bb4805508a6287675fac876be2ac1182539ca8a32468d8128882e9d5009" name = "github.com/golang/snappy" packages = ["."] + pruneopts = "UT" revision = "2e65f85255dbc3072edf28d6b5b8efc472979f5a" [[projects]] + digest = "1:c79fb010be38a59d657c48c6ba1d003a8aa651fa56b579d959d74573b7dff8e1" name = "github.com/gorilla/context" packages = ["."] + pruneopts = "UT" revision = "08b5f424b9271eedf6f9f0ce86cb9396ed337a42" version = "v1.1.1" [[projects]] + digest = "1:e73f5b0152105f18bc131fba127d9949305c8693f8a762588a82a48f61756f5f" name = "github.com/gorilla/mux" packages = ["."] + pruneopts = "UT" revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf" version = "v1.6.2" [[projects]] + digest = "1:43dd08a10854b2056e615d1b1d22ac94559d822e1f8b6fcc92c1a1057e85188e" name = "github.com/gorilla/websocket" packages = ["."] + pruneopts = "UT" revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b" version = "v1.2.0" [[projects]] branch = "master" + digest = "1:8951fe6e358876736d8fa1f3992624fdbb2dec6bc49401c1381d1ef8abbb544f" name = "github.com/hashicorp/hcl" packages = [ ".", @@ -142,162 +179,208 @@ "hcl/token", "json/parser", "json/scanner", - "json/token" + "json/token", ] + pruneopts = "UT" revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168" [[projects]] + digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" name = "github.com/inconshreveable/mousetrap" packages = ["."] + pruneopts = "UT" revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" version = "v1.0" [[projects]] branch = "master" + digest = "1:39b27d1381a30421f9813967a5866fba35dc1d4df43a6eefe3b7a5444cb07214" name = "github.com/jmhodges/levigo" packages = ["."] + pruneopts = "UT" revision = "c42d9e0ca023e2198120196f842701bb4c55d7b9" [[projects]] branch = "master" + digest = "1:a64e323dc06b73892e5bb5d040ced475c4645d456038333883f58934abbf6f72" name = "github.com/kr/logfmt" packages = ["."] + pruneopts = "UT" revision = "b84e30acd515aadc4b783ad4ff83aff3299bdfe0" [[projects]] + digest = "1:c568d7727aa262c32bdf8a3f7db83614f7af0ed661474b24588de635c20024c7" name = "github.com/magiconair/properties" packages = ["."] + pruneopts = "UT" revision = "c2353362d570a7bfa228149c62842019201cfb71" version = "v1.8.0" [[projects]] + digest = "1:d4d17353dbd05cb52a2a52b7fe1771883b682806f68db442b436294926bbfafb" name = "github.com/mattn/go-isatty" packages = ["."] + pruneopts = "UT" revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" version = "v0.0.3" [[projects]] + digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc" name = "github.com/matttproud/golang_protobuf_extensions" packages = ["pbutil"] + pruneopts = "UT" revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" version = "v1.0.1" [[projects]] branch = "master" + digest = "1:e730597b38a4d56e2361e0b6236cb800e52c73cace2ff91396f4ff35792ddfa7" name = "github.com/mitchellh/mapstructure" packages = ["."] + pruneopts = "UT" revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b" [[projects]] + digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e" name = "github.com/pelletier/go-toml" packages = ["."] + pruneopts = "UT" revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" version = "v1.2.0" [[projects]] + digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747" name = "github.com/pkg/errors" packages = ["."] + pruneopts = "UT" revision = "645ef00459ed84a119197bfb8d8205042c6df63d" version = "v0.8.0" [[projects]] + digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe" name = "github.com/pmezard/go-difflib" packages = ["difflib"] + pruneopts = "UT" revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:98225904b7abff96c052b669b25788f18225a36673fba022fb93514bb9a2a64e" name = "github.com/prometheus/client_golang" packages = [ "prometheus", - "prometheus/promhttp" + "prometheus/promhttp", ] + pruneopts = "UT" revision = "ae27198cdd90bf12cd134ad79d1366a6cf49f632" [[projects]] branch = "master" + digest = "1:53a76eb11bdc815fcf0c757a9648fda0ab6887da13f07587181ff2223b67956c" name = "github.com/prometheus/client_model" packages = ["go"] + pruneopts = "UT" revision = "99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c" [[projects]] branch = "master" + digest = "1:4d291d51042ed9de40eef61a3c1b56e969d6e0f8aa5fd3da5e958ec66bee68e4" name = "github.com/prometheus/common" packages = [ "expfmt", "internal/bitbucket.org/ww/goautoneg", - "model" + "model", ] + pruneopts = "UT" revision = "7600349dcfe1abd18d72d3a1770870d9800a7801" [[projects]] branch = "master" + digest = "1:55d7449d6987dabf272b4e81b2f9c449f05b17415c939b68d1e82f57e3374b7f" name = "github.com/prometheus/procfs" packages = [ ".", "internal/util", "nfs", - "xfs" + "xfs", ] + pruneopts = "UT" revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a" [[projects]] branch = "master" + digest = "1:c4556a44e350b50a490544d9b06e9fba9c286c21d6c0e47f54f3a9214597298c" name = "github.com/rcrowley/go-metrics" packages = ["."] + pruneopts = "UT" revision = "e2704e165165ec55d062f5919b4b29494e9fa790" [[projects]] + digest = "1:37ace7f35375adec11634126944bdc45a673415e2fcc07382d03b75ec76ea94c" name = "github.com/spf13/afero" packages = [ ".", - "mem" + "mem", ] + pruneopts = "UT" revision = "787d034dfe70e44075ccc060d346146ef53270ad" version = "v1.1.1" [[projects]] + digest = "1:516e71bed754268937f57d4ecb190e01958452336fa73dbac880894164e91c1f" name = "github.com/spf13/cast" packages = ["."] + pruneopts = "UT" revision = "8965335b8c7107321228e3e3702cab9832751bac" version = "v1.2.0" [[projects]] + digest = "1:627ab2f549a6a55c44f46fa24a4307f4d0da81bfc7934ed0473bf38b24051d26" name = "github.com/spf13/cobra" packages = ["."] + pruneopts = "UT" revision = "7b2c5ac9fc04fc5efafb60700713d4fa609b777b" version = "v0.0.1" [[projects]] branch = "master" + digest = "1:080e5f630945ad754f4b920e60b4d3095ba0237ebf88dc462eb28002932e3805" name = "github.com/spf13/jwalterweatherman" packages = ["."] + pruneopts = "UT" revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394" [[projects]] + digest = "1:9424f440bba8f7508b69414634aef3b2b3a877e522d8a4624692412805407bb7" name = "github.com/spf13/pflag" packages = ["."] + pruneopts = "UT" revision = "583c0c0531f06d5278b7d917446061adc344b5cd" version = "v1.0.1" [[projects]] + digest = "1:f8e1a678a2571e265f4bf91a3e5e32aa6b1474a55cb0ea849750cc177b664d96" name = "github.com/spf13/viper" packages = ["."] + pruneopts = "UT" revision = "25b30aa063fc18e48662b86996252eabdcf2f0c7" version = "v1.0.0" [[projects]] + digest = "1:73697231b93fb74a73ebd8384b68b9a60c57ea6b13c56d2425414566a72c8e6d" name = "github.com/stretchr/testify" packages = [ "assert", - "require" + "require", ] + pruneopts = "UT" revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71" version = "v1.2.1" [[projects]] branch = "master" + digest = "1:922191411ad8f61bcd8018ac127589bb489712c1d1a0ab2497aca4b16de417d2" name = "github.com/syndtr/goleveldb" packages = [ "leveldb", @@ -311,33 +394,41 @@ "leveldb/opt", "leveldb/storage", "leveldb/table", - "leveldb/util" + "leveldb/util", ] + pruneopts = "UT" revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445" [[projects]] branch = "master" + digest = "1:203b409c21115233a576f99e8f13d8e07ad82b25500491f7e1cca12588fb3232" name = "github.com/tendermint/ed25519" packages = [ ".", "edwards25519", - "extra25519" + "extra25519", ] + pruneopts = "UT" revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057" [[projects]] + digest = "1:e9113641c839c21d8eaeb2c907c7276af1eddeed988df8322168c56b7e06e0e1" name = "github.com/tendermint/go-amino" packages = ["."] + pruneopts = "UT" revision = "2106ca61d91029c931fd54968c2bb02dc96b1412" version = "0.10.1" [[projects]] + digest = "1:d4a15d404afbf591e8be16fcda7f5ac87948d5c7531f9d909fd84cc730ab16e2" name = "github.com/tendermint/iavl" packages = ["."] + pruneopts = "UT" revision = "35f66e53d9b01e83b30de68b931f54b2477a94c9" version = "v0.9.2" [[projects]] + digest = "1:2511fa7bc2725251a1a48a923c8f01cd41de29b00a21224092d448a9e4627c21" name = "github.com/tendermint/tendermint" packages = [ "abci/client", @@ -392,18 +483,22 @@ "state/txindex/kv", "state/txindex/null", "types", - "version" + "version", ] + pruneopts = "UT" revision = "5ff65274b84ea905787a48512cc3124385bddf2f" version = "v0.22.2" [[projects]] + digest = "1:5bd938386bd1f61a581bf8cd6ff2b7b2f79c542929176db4ceb44965440dae07" name = "github.com/zondax/ledger-goclient" packages = ["."] - revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a" + pruneopts = "UT" + revision = "39ba4728c137c75718a21f9b4b3280fa31b9139b" [[projects]] branch = "master" + digest = "1:e8206c1653e050116ec8c9a823a86413fc9f9ee3c2f3ae977c96d6a1747f7325" name = "golang.org/x/crypto" packages = [ "blowfish", @@ -416,12 +511,14 @@ "pbkdf2", "poly1305", "ripemd160", - "salsa20/salsa" + "salsa20/salsa", ] + pruneopts = "UT" revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602" [[projects]] branch = "master" + digest = "1:04dda8391c3e2397daf254ac68003f30141c069b228d06baec8324a5f81dc1e9" name = "golang.org/x/net" packages = [ "context", @@ -431,17 +528,21 @@ "idna", "internal/timeseries", "netutil", - "trace" + "trace", ] + pruneopts = "UT" revision = "292b43bbf7cb8d35ddf40f8d5100ef3837cced3f" [[projects]] branch = "master" + digest = "1:d773e525476aefa22ea944a5425a9bfb99819b2e67eeb9b1966454fd57522bbf" name = "golang.org/x/sys" packages = ["unix"] + pruneopts = "UT" revision = "1b2967e3c290b7c545b3db0deeda16e9be4f98a2" [[projects]] + digest = "1:7509ba4347d1f8de6ae9be8818b0cd1abc3deeffe28aeaf4be6d4b6b5178d9ca" name = "golang.org/x/text" packages = [ "collate", @@ -457,18 +558,22 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable" + "unicode/rangetable", ] + pruneopts = "UT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" + digest = "1:601e63e7d4577f907118bec825902505291918859d223bce015539e79f1160e3" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] + pruneopts = "UT" revision = "e92b116572682a5b432ddd840aeaba2a559eeff1" [[projects]] + digest = "1:4d7b5d9746840266938cdb21a40f8eba7137d9153c4ed404d6bb2a450d06f690" name = "google.golang.org/grpc" packages = [ ".", @@ -493,20 +598,63 @@ "stats", "status", "tap", - "transport" + "transport", ] + pruneopts = "UT" revision = "d11072e7ca9811b1100b80ca0269ac831f06d024" version = "v1.11.3" [[projects]] + digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "UT" revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" version = "v2.2.1" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "5c3ab73a85af1b3110b5f7ddbb27e77bb9cf42848ee29efcad9d78c0ecc26519" + input-imports = [ + "github.com/bartekn/go-bip39", + "github.com/bgentry/speakeasy", + "github.com/btcsuite/btcd/btcec", + "github.com/golang/protobuf/proto", + "github.com/gorilla/mux", + "github.com/mattn/go-isatty", + "github.com/pkg/errors", + "github.com/spf13/cobra", + "github.com/spf13/pflag", + "github.com/spf13/viper", + "github.com/stretchr/testify/assert", + "github.com/stretchr/testify/require", + "github.com/tendermint/go-amino", + "github.com/tendermint/iavl", + "github.com/tendermint/tendermint/abci/server", + "github.com/tendermint/tendermint/abci/types", + "github.com/tendermint/tendermint/cmd/tendermint/commands", + "github.com/tendermint/tendermint/config", + "github.com/tendermint/tendermint/crypto", + "github.com/tendermint/tendermint/crypto/merkle", + "github.com/tendermint/tendermint/crypto/tmhash", + "github.com/tendermint/tendermint/libs/bech32", + "github.com/tendermint/tendermint/libs/cli", + "github.com/tendermint/tendermint/libs/cli/flags", + "github.com/tendermint/tendermint/libs/common", + "github.com/tendermint/tendermint/libs/db", + "github.com/tendermint/tendermint/libs/log", + "github.com/tendermint/tendermint/node", + "github.com/tendermint/tendermint/p2p", + "github.com/tendermint/tendermint/privval", + "github.com/tendermint/tendermint/proxy", + "github.com/tendermint/tendermint/rpc/client", + "github.com/tendermint/tendermint/rpc/core/types", + "github.com/tendermint/tendermint/rpc/lib/client", + "github.com/tendermint/tendermint/rpc/lib/server", + "github.com/tendermint/tendermint/types", + "github.com/zondax/ledger-goclient", + "golang.org/x/crypto/blowfish", + "golang.org/x/crypto/ripemd160", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 0bb13c3e38..da2c8e29ce 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -70,7 +70,7 @@ [[constraint]] name = "github.com/zondax/ledger-goclient" - revision = "065cbf938a16f20335c40cfe180f9cd4955c6a5a" + revision = "39ba4728c137c75718a21f9b4b3280fa31b9139b" [prune] go-tests = true diff --git a/Makefile b/Makefile index 4d761ede14..6f440e0200 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,10 @@ PACKAGES=$(shell go list ./... | grep -v '/vendor/') PACKAGES_NOCLITEST=$(shell go list ./... | grep -v '/vendor/' | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test) COMMIT_HASH := $(shell git rev-parse --short HEAD) -BUILD_FLAGS = -tags netgo -ldflags "-X github.com/cosmos/cosmos-sdk/version.GitCommit=${COMMIT_HASH}" - +BUILD_TAGS = netgo ledger +BUILD_FLAGS = -tags "${BUILD_TAGS}" -ldflags "-X github.com/cosmos/cosmos-sdk/version.GitCommit=${COMMIT_HASH}" +GCC := $(shell command -v gcc 2> /dev/null) +LEDGER_ENABLED ?= true all: get_tools get_vendor_deps install install_examples test_lint test ######################################## @@ -11,10 +13,19 @@ all: get_tools get_vendor_deps install install_examples test_lint test ci: get_tools get_vendor_deps install test_cover test_lint test ######################################## -### Build +### Build/Install -# This can be unified later, here for easy demos -build: +check-ledger: +ifeq ($(LEDGER_ENABLED),true) +ifndef GCC +$(error "gcc not installed for ledger support, please install") +endif +else +TMP_BUILD_TAGS := $(BUILD_TAGS) +BUILD_TAGS = $(filter-out ledger, $(TMP_BUILD_TAGS)) +endif + +build: check-ledger ifeq ($(OS),Windows_NT) go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaia/cmd/gaiad go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaia/cmd/gaiacli @@ -23,6 +34,9 @@ else go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli endif +build-linux: + LEDGER_ENABLED=false GOOS=linux GOARCH=amd64 $(MAKE) build + build_examples: ifeq ($(OS),Windows_NT) go build $(BUILD_FLAGS) -o build/basecoind.exe ./examples/basecoin/cmd/basecoind @@ -36,7 +50,7 @@ else go build $(BUILD_FLAGS) -o build/democli ./examples/democoin/cmd/democli endif -install: +install: check-ledger go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli @@ -141,10 +155,6 @@ devdoc_update: ######################################## ### Local validator nodes using docker and docker-compose -# Build linux binary -build-linux: - GOOS=linux GOARCH=amd64 $(MAKE) build - build-docker-gaiadnode: $(MAKE) -C networks/local @@ -181,4 +191,8 @@ remotenet-status: # To avoid unintended conflicts with file names, always add to .PHONY # unless there is a reason not to. # https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html -.PHONY: build build_examples install install_examples install_debug dist check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update build-linux build-docker-gaiadnode localnet-start localnet-stop remotenet-start remotenet-stop remotenet-status format +.PHONY: build build_examples install install_examples install_debug dist \ +check_tools get_tools get_vendor_deps draw_deps test test_cli test_unit \ +test_cover test_lint benchmark devdoc_init devdoc devdoc_save devdoc_update \ +build-linux build-docker-gaiadnode localnet-start localnet-stop remotenet-start \ +remotenet-stop remotenet-status format check-ledger diff --git a/crypto/keys/keybase.go b/crypto/keys/keybase.go index ef2c6243a6..d9c1b5f57f 100644 --- a/crypto/keys/keybase.go +++ b/crypto/keys/keybase.go @@ -6,13 +6,12 @@ import ( "os" "strings" - "github.com/pkg/errors" - tcrypto "github.com/tendermint/tendermint/crypto" - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/cosmos/cosmos-sdk/crypto" "github.com/cosmos/cosmos-sdk/crypto/keys/bip39" "github.com/cosmos/cosmos-sdk/crypto/keys/hd" + "github.com/pkg/errors" + tmcrypto "github.com/tendermint/tendermint/crypto" + dbm "github.com/tendermint/tendermint/libs/db" ) var _ Keybase = dbKeybase{} @@ -43,10 +42,12 @@ const ( ) var ( - // ErrUnsupportedSigningAlgo is raised when the caller tries to use a different signing scheme than secp256k1. + // ErrUnsupportedSigningAlgo is raised when the caller tries to use a + // different signing scheme than secp256k1. ErrUnsupportedSigningAlgo = errors.New("unsupported signing algo: only secp256k1 is supported") - // ErrUnsupportedLanguage is raised when the caller tries to use a different language than english for creating - // a mnemonic sentence. + + // ErrUnsupportedLanguage is raised when the caller tries to use a + // different language than english for creating a mnemonic sentence. ErrUnsupportedLanguage = errors.New("unsupported language: only english is supported") ) @@ -147,7 +148,7 @@ func (kb dbKeybase) CreateLedger(name string, path crypto.DerivationPath, algo S // CreateOffline creates a new reference to an offline keypair // It returns the created key info -func (kb dbKeybase) CreateOffline(name string, pub tcrypto.PubKey) (Info, error) { +func (kb dbKeybase) CreateOffline(name string, pub tmcrypto.PubKey) (Info, error) { return kb.writeOfflineKey(pub, name), nil } @@ -162,9 +163,9 @@ func (kb *dbKeybase) persistDerivedKey(seed []byte, passwd, name, fullHdPath str // if we have a password, use it to encrypt the private key and store it // else store the public key only if passwd != "" { - info = kb.writeLocalKey(tcrypto.PrivKeySecp256k1(derivedPriv), name, passwd) + info = kb.writeLocalKey(tmcrypto.PrivKeySecp256k1(derivedPriv), name, passwd) } else { - pubk := tcrypto.PrivKeySecp256k1(derivedPriv).PubKey() + pubk := tmcrypto.PrivKeySecp256k1(derivedPriv).PubKey() info = kb.writeOfflineKey(pubk, name) } return @@ -196,12 +197,12 @@ func (kb dbKeybase) Get(name string) (Info, error) { // Sign signs the msg with the named key. // It returns an error if the key doesn't exist or the decryption fails. -func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig tcrypto.Signature, pub tcrypto.PubKey, err error) { +func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig tmcrypto.Signature, pub tmcrypto.PubKey, err error) { info, err := kb.Get(name) if err != nil { return } - var priv tcrypto.PrivKey + var priv tmcrypto.PrivKey switch info.(type) { case localInfo: linfo := info.(localInfo) @@ -240,12 +241,12 @@ func (kb dbKeybase) Sign(name, passphrase string, msg []byte) (sig tcrypto.Signa return sig, pub, nil } -func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tcrypto.PrivKey, error) { +func (kb dbKeybase) ExportPrivateKeyObject(name string, passphrase string) (tmcrypto.PrivKey, error) { info, err := kb.Get(name) if err != nil { return nil, err } - var priv tcrypto.PrivKey + var priv tmcrypto.PrivKey switch info.(type) { case localInfo: linfo := info.(localInfo) @@ -313,7 +314,7 @@ func (kb dbKeybase) ImportPubKey(name string, armor string) (err error) { if err != nil { return } - pubKey, err := tcrypto.PubKeyFromBytes(pubBytes) + pubKey, err := tmcrypto.PubKeyFromBytes(pubBytes) if err != nil { return } @@ -380,7 +381,7 @@ func (kb dbKeybase) Update(name, oldpass string, getNewpass func() (string, erro } } -func (kb dbKeybase) writeLocalKey(priv tcrypto.PrivKey, name, passphrase string) Info { +func (kb dbKeybase) writeLocalKey(priv tmcrypto.PrivKey, name, passphrase string) Info { // encrypt private key using passphrase privArmor := encryptArmorPrivKey(priv, passphrase) // make Info @@ -390,13 +391,13 @@ func (kb dbKeybase) writeLocalKey(priv tcrypto.PrivKey, name, passphrase string) return info } -func (kb dbKeybase) writeLedgerKey(pub tcrypto.PubKey, path crypto.DerivationPath, name string) Info { +func (kb dbKeybase) writeLedgerKey(pub tmcrypto.PubKey, path crypto.DerivationPath, name string) Info { info := newLedgerInfo(name, pub, path) kb.writeInfo(info, name) return info } -func (kb dbKeybase) writeOfflineKey(pub tcrypto.PubKey, name string) Info { +func (kb dbKeybase) writeOfflineKey(pub tmcrypto.PubKey, name string) Info { info := newOfflineInfo(name, pub) kb.writeInfo(info, name) return info diff --git a/crypto/ledger.go b/crypto/ledger.go new file mode 100644 index 0000000000..9d446202f7 --- /dev/null +++ b/crypto/ledger.go @@ -0,0 +1,18 @@ +// +build cgo,ledger + +package crypto + +import ( + ledger "github.com/zondax/ledger-goclient" +) + +// If ledger support (build tag) has been enabled, automically attempt to load +// and set the ledger device, ledgerDevice, if it has not already been set. +func init() { + device, err := ledger.FindLedger() + if err != nil { + ledgerDeviceErr = err + } else { + ledgerDevice = device + } +} diff --git a/crypto/ledger_common.go b/crypto/ledger_common.go deleted file mode 100644 index 39f15464a7..0000000000 --- a/crypto/ledger_common.go +++ /dev/null @@ -1,19 +0,0 @@ -package crypto - -import ( - ledger "github.com/zondax/ledger-goclient" -) - -var device *ledger.Ledger - -// Ledger derivation path -type DerivationPath = []uint32 - -// getLedger gets a copy of the device, and caches it -func getLedger() (*ledger.Ledger, error) { - var err error - if device == nil { - device, err = ledger.FindLedger() - } - return device, err -} diff --git a/crypto/ledger_secp256k1.go b/crypto/ledger_secp256k1.go index 1ba36f69df..7a9f10c0dd 100644 --- a/crypto/ledger_secp256k1.go +++ b/crypto/ledger_secp256k1.go @@ -1,126 +1,159 @@ package crypto import ( + "errors" "fmt" secp256k1 "github.com/btcsuite/btcd/btcec" - ledger "github.com/zondax/ledger-goclient" - - tcrypto "github.com/tendermint/tendermint/crypto" + tmcrypto "github.com/tendermint/tendermint/crypto" ) -func pubkeyLedgerSecp256k1(device *ledger.Ledger, path DerivationPath) (pub tcrypto.PubKey, err error) { - key, err := device.GetPublicKeySECP256K1(path) - if err != nil { - return nil, fmt.Errorf("error fetching public key: %v", err) +var ( + ledgerDevice LedgerSECP256K1 + ledgerDeviceErr error + + // ErrMissingLedgerDevice is used to reflect that a ledger device load has + // not been attempted. + ErrMissingLedgerDevice = errors.New("missing ledger device") +) + +type ( + // DerivationPath represents a Ledger derivation path. + DerivationPath []uint32 + + // LedgerSECP256K1 reflects an interface a Ledger API must implement for + // the SECP256K1 scheme. + LedgerSECP256K1 interface { + GetPublicKeySECP256K1([]uint32) ([]byte, error) + SignSECP256K1([]uint32, []byte) ([]byte, error) } - var p tcrypto.PubKeySecp256k1 - // Reserialize in the 33-byte compressed format - cmp, err := secp256k1.ParsePubKey(key[:], secp256k1.S256()) - copy(p[:], cmp.SerializeCompressed()) - pub = p - return -} -func signLedgerSecp256k1(device *ledger.Ledger, path DerivationPath, msg []byte) (sig tcrypto.Signature, err error) { - bsig, err := device.SignSECP256K1(path, msg) - if err != nil { - return sig, err + // PrivKeyLedgerSecp256k1 implements PrivKey, calling the ledger nano we + // cache the PubKey from the first call to use it later. + PrivKeyLedgerSecp256k1 struct { + // CachedPubKey should be private, but we want to encode it via + // go-amino so we can view the address later, even without having the + // ledger attached. + CachedPubKey tmcrypto.PubKey + Path DerivationPath + ledger LedgerSECP256K1 } - sig = tcrypto.SignatureSecp256k1FromBytes(bsig) - return -} +) -// PrivKeyLedgerSecp256k1 implements PrivKey, calling the ledger nano -// we cache the PubKey from the first call to use it later -type PrivKeyLedgerSecp256k1 struct { - // PubKey should be private, but we want to encode it via go-amino - // so we can view the address later, even without having the ledger - // attached - CachedPubKey tcrypto.PubKey - Path DerivationPath -} +// NewPrivKeyLedgerSecp256k1 will generate a new key and store the public key +// for later use. +// +// CONTRACT: The ledger device, ledgerDevice, must be loaded and set prior to +// any creation of a PrivKeyLedgerSecp256k1. +func NewPrivKeyLedgerSecp256k1(path DerivationPath) (tmcrypto.PrivKey, error) { + if ledgerDevice == nil { + err := ErrMissingLedgerDevice + if ledgerDeviceErr != nil { + err = ledgerDeviceErr + } + + return nil, fmt.Errorf("failed to create PrivKeyLedgerSecp256k1: %v", err) + } + + pkl := &PrivKeyLedgerSecp256k1{Path: path, ledger: ledgerDevice} -// NewPrivKeyLedgerSecp256k1 will generate a new key and store the -// public key for later use. -func NewPrivKeyLedgerSecp256k1(path DerivationPath) (tcrypto.PrivKey, error) { - var pk PrivKeyLedgerSecp256k1 - pk.Path = path // cache the pubkey for later use - pubKey, err := pk.getPubKey() + pubKey, err := pkl.getPubKey() if err != nil { return nil, err } - pk.CachedPubKey = pubKey - return &pk, err + + pkl.CachedPubKey = pubKey + return pkl, err } -// ValidateKey allows us to verify the sanity of a key -// after loading it from disk -func (pk PrivKeyLedgerSecp256k1) ValidateKey() error { +// PubKey returns the cached public key. +func (pkl PrivKeyLedgerSecp256k1) PubKey() tmcrypto.PubKey { + return pkl.CachedPubKey +} + +// ValidateKey allows us to verify the sanity of a public key after loading it +// from disk. +func (pkl PrivKeyLedgerSecp256k1) ValidateKey() error { // getPubKey will return an error if the ledger is not - pub, err := pk.getPubKey() + pub, err := pkl.getPubKey() if err != nil { return err } + // verify this matches cached address - if !pub.Equals(pk.CachedPubKey) { + if !pub.Equals(pkl.CachedPubKey) { return fmt.Errorf("cached key does not match retrieved key") } + return nil } -// AssertIsPrivKeyInner fulfils PrivKey Interface -func (pk *PrivKeyLedgerSecp256k1) AssertIsPrivKeyInner() {} +// AssertIsPrivKeyInner implements the PrivKey interface. It performs a no-op. +func (pkl *PrivKeyLedgerSecp256k1) AssertIsPrivKeyInner() {} -// Bytes fulfils PrivKey Interface - but it stores the cached pubkey so we can verify -// the same key when we reconnect to a ledger -func (pk PrivKeyLedgerSecp256k1) Bytes() []byte { - return cdc.MustMarshalBinaryBare(pk) +// Bytes implements the PrivKey interface. It stores the cached public key so +// we can verify the same key when we reconnect to a ledger. +func (pkl PrivKeyLedgerSecp256k1) Bytes() []byte { + return cdc.MustMarshalBinaryBare(pkl) } -// Sign calls the ledger and stores the PubKey for future use +// Equals implements the PrivKey interface. It makes sure two private keys +// refer to the same public key. +func (pkl PrivKeyLedgerSecp256k1) Equals(other tmcrypto.PrivKey) bool { + if ledger, ok := other.(*PrivKeyLedgerSecp256k1); ok { + return pkl.CachedPubKey.Equals(ledger.CachedPubKey) + } + + return false +} + +// Sign calls the ledger and stores the PubKey for future use. // -// Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes, -// returning an error, so this should only trigger if the privkey is held -// in memory for a while before use. -func (pk PrivKeyLedgerSecp256k1) Sign(msg []byte) (tcrypto.Signature, error) { - dev, err := getLedger() +// Communication is checked on NewPrivKeyLedger and PrivKeyFromBytes, returning +// an error, so this should only trigger if the private key is held in memory +// for a while before use. +func (pkl PrivKeyLedgerSecp256k1) Sign(msg []byte) (tmcrypto.Signature, error) { + sig, err := pkl.signLedgerSecp256k1(msg) if err != nil { return nil, err } - sig, err := signLedgerSecp256k1(dev, pk.Path, msg) - if err != nil { - return nil, err - } - return sig, nil -} -// PubKey returns the stored PubKey -func (pk PrivKeyLedgerSecp256k1) PubKey() tcrypto.PubKey { - return pk.CachedPubKey + return sig, nil } // getPubKey reads the pubkey the ledger itself // since this involves IO, it may return an error, which is not exposed // in the PubKey interface, so this function allows better error handling -func (pk PrivKeyLedgerSecp256k1) getPubKey() (key tcrypto.PubKey, err error) { - dev, err := getLedger() - if err != nil { - return key, fmt.Errorf("cannot connect to Ledger device - error: %v", err) - } - key, err = pubkeyLedgerSecp256k1(dev, pk.Path) +func (pkl PrivKeyLedgerSecp256k1) getPubKey() (key tmcrypto.PubKey, err error) { + key, err = pkl.pubkeyLedgerSecp256k1() if err != nil { return key, fmt.Errorf("please open Cosmos app on the Ledger device - error: %v", err) } + return key, err } -// Equals fulfils PrivKey Interface - makes sure both keys refer to the -// same -func (pk PrivKeyLedgerSecp256k1) Equals(other tcrypto.PrivKey) bool { - if ledger, ok := other.(*PrivKeyLedgerSecp256k1); ok { - return pk.CachedPubKey.Equals(ledger.CachedPubKey) +func (pkl PrivKeyLedgerSecp256k1) signLedgerSecp256k1(msg []byte) (tmcrypto.Signature, error) { + sigBytes, err := pkl.ledger.SignSECP256K1(pkl.Path, msg) + if err != nil { + return nil, err } - return false + + return tmcrypto.SignatureSecp256k1FromBytes(sigBytes), nil +} + +func (pkl PrivKeyLedgerSecp256k1) pubkeyLedgerSecp256k1() (pub tmcrypto.PubKey, err error) { + key, err := pkl.ledger.GetPublicKeySECP256K1(pkl.Path) + if err != nil { + return nil, fmt.Errorf("error fetching public key: %v", err) + } + + var pk tmcrypto.PubKeySecp256k1 + + // re-serialize in the 33-byte compressed format + cmp, err := secp256k1.ParsePubKey(key[:], secp256k1.S256()) + copy(pk[:], cmp.SerializeCompressed()) + + return pk, nil } diff --git a/crypto/ledger_test.go b/crypto/ledger_test.go index 997dfbc3bc..8e1a2ed654 100644 --- a/crypto/ledger_test.go +++ b/crypto/ledger_test.go @@ -1,25 +1,26 @@ package crypto import ( + "fmt" "os" "testing" "github.com/stretchr/testify/require" - - tcrypto "github.com/tendermint/tendermint/crypto" + tmcrypto "github.com/tendermint/tendermint/crypto" ) +var ledgerEnabledEnv = "TEST_WITH_LEDGER" + func TestRealLedgerSecp256k1(t *testing.T) { - - if os.Getenv("WITH_LEDGER") == "" { - t.Skip("Set WITH_LEDGER to run code on real ledger") + if os.Getenv(ledgerEnabledEnv) == "" { + t.Skip(fmt.Sprintf("Set '%s' to run code on a real ledger", ledgerEnabledEnv)) } - msg := []byte("kuhehfeohg") - + msg := []byte("{\"account_number\":\"3\",\"chain_id\":\"1234\",\"fee\":{\"amount\":[{\"amount\":\"150\",\"denom\":\"atom\"}],\"gas\":\"5000\"},\"memo\":\"memo\",\"msgs\":[[\"%s\"]],\"sequence\":\"6\"}") path := DerivationPath{44, 60, 0, 0, 0} priv, err := NewPrivKeyLedgerSecp256k1(path) - require.Nil(t, err, "%+v", err) + require.Nil(t, err, "%s", err) + pub := priv.PubKey() sig, err := priv.Sign(msg) require.Nil(t, err) @@ -27,24 +28,23 @@ func TestRealLedgerSecp256k1(t *testing.T) { valid := pub.VerifyBytes(msg, sig) require.True(t, valid) - // now, let's serialize the key and make sure it still works - bs := priv.Bytes() - priv2, err := tcrypto.PrivKeyFromBytes(bs) + // now, let's serialize the public key and make sure it still works + bs := priv.PubKey().Bytes() + pub2, err := tmcrypto.PubKeyFromBytes(bs) require.Nil(t, err, "%+v", err) // make sure we get the same pubkey when we load from disk - pub2 := priv2.PubKey() require.Equal(t, pub, pub2) // signing with the loaded key should match the original pubkey - sig, err = priv2.Sign(msg) + sig, err = priv.Sign(msg) require.Nil(t, err) valid = pub.VerifyBytes(msg, sig) require.True(t, valid) // make sure pubkeys serialize properly as well bs = pub.Bytes() - bpub, err := tcrypto.PubKeyFromBytes(bs) + bpub, err := tmcrypto.PubKeyFromBytes(bs) require.NoError(t, err) require.Equal(t, pub, bpub) } @@ -52,8 +52,8 @@ func TestRealLedgerSecp256k1(t *testing.T) { // TestRealLedgerErrorHandling calls. These tests assume // the ledger is not plugged in.... func TestRealLedgerErrorHandling(t *testing.T) { - if os.Getenv("WITH_LEDGER") != "" { - t.Skip("Skipping on WITH_LEDGER as it tests unplugged cases") + if os.Getenv(ledgerEnabledEnv) != "" { + t.Skip(fmt.Sprintf("Unset '%s' to run code as if without a real Ledger", ledgerEnabledEnv)) } // first, try to generate a key, must return an error From a2047c5c81f3f838a182ba544d580d43c9358300 Mon Sep 17 00:00:00 2001 From: Dev Ojha Date: Sat, 14 Jul 2018 14:48:41 -0700 Subject: [PATCH 3/3] Merge PR #1687: tools: Ensure Gopkg.lock is correct in linting * tools: Ensure Gopkg.lock is correct in linting This adds dep status to the lint process. Also fixes linting errors that existed earlier. (not sure why they didn't show up on CI) Closes #1574 * Update dep, use the lock file new dep version creates --- Gopkg.lock | 1 - Gopkg.toml | 7 +------ Makefile | 2 ++ crypto/ledger_secp256k1.go | 3 +++ x/gov/client/cli/tx.go | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index a1372b1fa8..8a786fc3d3 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,7 +2,6 @@ [[projects]] - branch = "master" digest = "1:09a7f74eb6bb3c0f14d8926610c87f569c5cff68e978d30e9a3540aeb626fdf0" name = "github.com/bartekn/go-bip39" packages = ["."] diff --git a/Gopkg.toml b/Gopkg.toml index da2c8e29ce..012698c615 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -10,11 +10,6 @@ # name = "github.com/user/project" # version = "1.0.0" # -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# # [[override]] # name = "github.com/x/y" # version = "2.4.0" @@ -66,7 +61,7 @@ [[constraint]] name = "github.com/bartekn/go-bip39" - branch = "master" + revision = "a05967ea095d81c8fe4833776774cfaff8e5036c" [[constraint]] name = "github.com/zondax/ledger-goclient" diff --git a/Makefile b/Makefile index 6f440e0200..b6b136f517 100644 --- a/Makefile +++ b/Makefile @@ -119,6 +119,8 @@ test_lint: gometalinter.v2 --config=tools/gometalinter.json ./... !(gometalinter.v2 --disable-all --enable='errcheck' --vendor ./... | grep -v "client/") find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -d -s + dep status >> /dev/null + !(grep -n branch Gopkg.toml) format: find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -w -s diff --git a/crypto/ledger_secp256k1.go b/crypto/ledger_secp256k1.go index 7a9f10c0dd..9e8940d7bf 100644 --- a/crypto/ledger_secp256k1.go +++ b/crypto/ledger_secp256k1.go @@ -153,6 +153,9 @@ func (pkl PrivKeyLedgerSecp256k1) pubkeyLedgerSecp256k1() (pub tmcrypto.PubKey, // re-serialize in the 33-byte compressed format cmp, err := secp256k1.ParsePubKey(key[:], secp256k1.S256()) + if err != nil { + return nil, fmt.Errorf("error parsing public key: %v", err) + } copy(pk[:], cmp.SerializeCompressed()) return pk, nil diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 8369c99273..88c4b7d170 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -158,7 +158,7 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command { return err } - fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]", bechVoter, msg.ProposalID, msg.Option) + fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]", bechVoter, msg.ProposalID, msg.Option.String()) // build and sign the transaction, then broadcast to Tendermint ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))