Validator by pubkey, tests work-in-progress

This commit is contained in:
Christopher Goes 2018-05-24 23:51:42 +02:00
parent adec1cd7a9
commit b005f9f18d
No known key found for this signature in database
GPG Key ID: E828D98232D328D3
5 changed files with 141 additions and 13 deletions

View File

@ -45,8 +45,9 @@ type ValidatorSet interface {
IterateValidatorsBonded(Context,
func(index int64, validator Validator) (stop bool))
Validator(Context, Address) Validator // get a particular validator by owner address
TotalPower(Context) Rat // total power of the validator set
Validator(Context, Address) Validator // get a particular validator by owner address
ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by public key
TotalPower(Context) Rat // total power of the validator set
}
//_______________________________________________________________________________

View File

@ -71,7 +71,10 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64,
return
}
logger.Info(fmt.Sprintf("Confirmed double sign from %v at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge))
validator := k.stakeKeeper.Validator(ctx, pubkey.Address())
validator := k.stakeKeeper.ValidatorByPubKey(ctx, pubkey)
if validator == nil {
panic(fmt.Errorf("Attempted to slash nonexistent validator with address %s", pubkey.Address()))
}
validator.Slash(ctx, height, SlashFractionDoubleSign)
logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v for double-sign at height %d", pubkey.Address(), SlashFractionDoubleSign, height))
}
@ -98,7 +101,10 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey,
}
minHeight := signInfo.StartHeight + SignedBlocksWindow
if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow {
validator := k.stakeKeeper.Validator(ctx, address)
validator := k.stakeKeeper.ValidatorByPubKey(ctx, pubkey)
if validator == nil {
panic(fmt.Errorf("Attempted to slash nonexistent validator with address %s", pubkey.Address()))
}
validator.Slash(ctx, height, SlashFractionDowntime)
validator.ForceUnbond(ctx, DowntimeUnbondDuration)
logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v and unbonded for downtime at height %d, cannot rebond for %ds",

View File

@ -1,17 +1,110 @@
package slashing
import (
"encoding/hex"
"testing"
"github.com/stretchr/testify/require"
// sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
"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/stake"
)
var (
addrs = []sdk.Address{
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"),
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"),
}
pks = []crypto.PubKey{
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"),
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"),
}
initCoins int64 = 100
)
func createTestCodec() *wire.Codec {
cdc := wire.NewCodec()
sdk.RegisterWire(cdc)
auth.RegisterWire(cdc)
bank.RegisterWire(cdc)
stake.RegisterWire(cdc)
wire.RegisterCrypto(cdc)
return cdc
}
func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keeper) {
keyAcc := sdk.NewKVStoreKey("acc")
keyStake := sdk.NewKVStoreKey("stake")
keySlashing := sdk.NewKVStoreKey("slashing")
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)
err := ms.LoadLatestVersion()
require.Nil(t, err)
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil)
cdc := createTestCodec()
accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{})
ck := bank.NewKeeper(accountMapper)
sk := stake.NewKeeper(cdc, keyStake, ck, stake.DefaultCodespace)
stake.InitGenesis(ctx, sk, stake.DefaultGenesisState())
for _, addr := range addrs {
ck.AddCoins(ctx, addr, sdk.Coins{
{sk.GetParams(ctx).BondDenom, initCoins},
})
}
keeper := NewKeeper(cdc, keySlashing, sk, DefaultCodespace)
return ctx, ck, sk, keeper
}
func TestHandleDoubleSign(t *testing.T) {
require.Equal(t, true, true)
ctx, ck, sk, keeper := createTestInput(t)
addr, val, amt := addrs[0], pks[0], int64(10)
got := stake.NewHandler(sk)(ctx, newTestMsgDeclareCandidacy(addr, val, amt))
require.True(t, got.IsOK())
_ = sk.Tick(ctx)
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}})
keeper.handleDoubleSign(ctx, 0, 0, val)
// TODO
}
func TestHandleAbsentValidator(t *testing.T) {
// TODO
}
func newPubKey(pk string) (res crypto.PubKey) {
pkBytes, err := hex.DecodeString(pk)
if err != nil {
panic(err)
}
var pkEd crypto.PubKeyEd25519
copy(pkEd[:], pkBytes[:])
return pkEd
}
func testAddr(addr string) sdk.Address {
res, err := sdk.GetAddress(addr)
if err != nil {
panic(err)
}
return res
}
func newTestMsgDeclareCandidacy(address sdk.Address, pubKey crypto.PubKey, amt int64) stake.MsgDeclareCandidacy {
return stake.MsgDeclareCandidacy{
Description: stake.Description{},
ValidatorAddr: address,
PubKey: pubKey,
Bond: sdk.Coin{"steak", amt},
}
}

View File

@ -8,6 +8,7 @@ import (
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/bank"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
)
// keeper of the staking store
@ -38,6 +39,18 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator Valid
return k.getValidator(store, addr)
}
// get a single validator by pubkey
func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (validator Validator, found bool) {
store := ctx.KVStore(k.storeKey)
b := store.Get(GetValidatorByPubKeyKey(pubkey))
if b == nil {
return validator, false
}
var addr sdk.Address
k.cdc.MustUnmarshalBinary(b, &addr)
return k.getValidator(store, addr)
}
// get a single validator (reuse store)
func (k Keeper) getValidator(store sdk.KVStore, addr sdk.Address) (validator Validator, found bool) {
b := store.Get(GetValidatorKey(addr))
@ -710,6 +723,15 @@ func (k Keeper) Validator(ctx sdk.Context, addr sdk.Address) sdk.Validator {
return val
}
// get the sdk.validator for a particular pubkey
func (k Keeper) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Validator {
val, found := k.GetValidatorByPubKey(ctx, pubkey)
if !found {
return nil
}
return val
}
// total power from the bond
func (k Keeper) TotalPower(ctx sdk.Context) sdk.Rat {
pool := k.GetPool(ctx)

View File

@ -16,13 +16,14 @@ var (
ParamKey = []byte{0x00} // key for parameters relating to staking
PoolKey = []byte{0x01} // key for the staking pools
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
ValidatorsBondedKey = []byte{0x03} // prefix for each key to bonded/actively validating validators
ValidatorsByPowerKey = []byte{0x04} // prefix for each key to a validator sorted by power
ValidatorCliffKey = []byte{0x05} // key for block-local tx index
ValidatorPowerCliffKey = []byte{0x06} // key for block-local tx index
TendermintUpdatesKey = []byte{0x07} // prefix for each key to a validator which is being updated
DelegationKey = []byte{0x08} // prefix for each key to a delegator's bond
IntraTxCounterKey = []byte{0x09} // key for block-local tx index
ValidatorsByPubKeyKey = []byte{0x03} // prefix for each key to a validator by pubkey
ValidatorsBondedKey = []byte{0x04} // prefix for each key to bonded/actively validating validators
ValidatorsByPowerKey = []byte{0x05} // prefix for each key to a validator sorted by power
ValidatorCliffKey = []byte{0x06} // key for block-local tx index
ValidatorPowerCliffKey = []byte{0x07} // key for block-local tx index
TendermintUpdatesKey = []byte{0x08} // prefix for each key to a validator which is being updated
DelegationKey = []byte{0x09} // prefix for each key to a delegator's bond
IntraTxCounterKey = []byte{0x10} // key for block-local tx index
)
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
@ -32,6 +33,11 @@ func GetValidatorKey(ownerAddr sdk.Address) []byte {
return append(ValidatorsKey, ownerAddr.Bytes()...)
}
// get the key for the validator with pubkey
func GetValidatorByPubKeyKey(pubkey crypto.PubKey) []byte {
return append(ValidatorsByPubKeyKey, pubkey.Bytes()...)
}
// get the key for the current validator group, ordered like tendermint
func GetValidatorsBondedKey(pk crypto.PubKey) []byte {
addr := pk.Address()