Merge branch 'rigel/new-hooks' into rigel/fee-distribution

This commit is contained in:
rigelrozanski 2018-09-25 20:09:33 -04:00
commit 3846894c3a
26 changed files with 368 additions and 57 deletions

10
Gopkg.lock generated
View File

@ -229,6 +229,14 @@
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
version = "v1.0.1"
[[projects]]
digest = "1:78bbb1ba5b7c3f2ed0ea1eab57bdd3859aec7e177811563edc41198a760b06af"
name = "github.com/mitchellh/go-homedir"
packages = ["."]
pruneopts = "UT"
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
version = "v1.0.0"
[[projects]]
digest = "1:645110e089152bd0f4a011a2648fbb0e4df5977be73ca605781157ac297f50c4"
name = "github.com/mitchellh/mapstructure"
@ -630,6 +638,8 @@
"github.com/golang/protobuf/proto",
"github.com/gorilla/mux",
"github.com/mattn/go-isatty",
"github.com/mitchellh/go-homedir",
"github.com/pelletier/go-toml",
"github.com/pkg/errors",
"github.com/spf13/cobra",
"github.com/spf13/pflag",

View File

@ -70,3 +70,7 @@
[prune]
go-tests = true
unused-packages = true
[[constraint]]
name = "github.com/mitchellh/go-homedir"
version = "1.0.0"

View File

@ -56,6 +56,7 @@ BREAKING CHANGES
* [types] \#2343 Make sdk.Msg have a names field, to facilitate automatic tagging.
* [baseapp] \#2366 Automatically add action tags to all messages
* [x/staking] \#2244 staking now holds a consensus-address-index instead of a consensus-pubkey-index
* [x/staking] \#2236 more distribution hooks for distribution
* Tendermint
@ -81,6 +82,7 @@ FEATURES
* [\#966](https://github.com/cosmos/cosmos-sdk/issues/966) Add --generate-only flag to build an unsigned transaction and write it to STDOUT.
* [\#1953](https://github.com/cosmos/cosmos-sdk/issues/1953) New `sign` command to sign transactions generated with the --generate-only flag.
* [\#1954](https://github.com/cosmos/cosmos-sdk/issues/1954) New `broadcast` command to broadcast transactions generated offline and signed with the `sign` command.
* [cli] \#2220 Add `gaiacli config` feature to interactively create CLI config files to reduce the number of required flags
* [stake][cli] [\#1672](https://github.com/cosmos/cosmos-sdk/issues/1672) Introduced
new commission flags for validator commands `create-validator` and `edit-validator`.

131
client/config.go Normal file
View File

@ -0,0 +1,131 @@
package client
import (
"github.com/spf13/cobra"
"github.com/mitchellh/go-homedir"
"bufio"
"path"
"os"
"io/ioutil"
"github.com/pelletier/go-toml"
"fmt"
"github.com/cosmos/cosmos-sdk/types"
)
type cliConfig struct {
Home string `toml:"home"`
ChainID string `toml:"chain_id"`
TrustNode bool `toml:"trust_node"`
Encoding string `toml:"encoding"`
Output string `toml:"output"`
Node string `toml:"node"`
Trace bool `toml:"trace"`
}
// ConfigCmd returns a CLI command to interactively create a
// Gaia CLI config file.
func ConfigCmd() *cobra.Command {
cfg := &cobra.Command{
Use: "config",
Short: "Interactively creates a Gaia CLI config file",
RunE: runConfigCmd,
}
return cfg
}
func runConfigCmd(cmd *cobra.Command, args [] string) error {
home, err := homedir.Dir()
if err != nil {
return err
}
stdin := BufferStdin()
gaiaCLIHome, err := handleGaiaCLIHome(home, stdin)
if err != nil {
return err
}
node, err := handleNode(stdin)
if err != nil {
return err
}
trustNode, err := handleTrustNode(stdin)
if err != nil {
return err
}
encoding := "btc"
output := "text"
var chainID string
chainID, err = types.DefaultChainID()
if err != nil {
fmt.Println("Couldn't populate ChainID, so using an empty one.")
}
cfg := &cliConfig{
Home: gaiaCLIHome,
ChainID: chainID,
TrustNode: trustNode,
Encoding: encoding,
Output: output,
Node: node,
Trace: false,
}
return createGaiaCLIConfig(cfg)
}
func handleGaiaCLIHome(dir string, stdin *bufio.Reader) (string, error) {
dirName := ".gaiacli"
home, err := GetString(fmt.Sprintf("Where is your gaiacli home directory? (Default: ~/%s)", dirName), stdin)
if err != nil {
return "", err
}
if home == "" {
home = path.Join(dir, dirName)
}
return home, nil
}
func handleNode(stdin *bufio.Reader) (string, error) {
defaultNode := "tcp://localhost:26657"
node, err := GetString(fmt.Sprintf("Where is your validator node running? (Default: %s)", defaultNode), stdin)
if err != nil {
return "", err
}
if node == "" {
node = defaultNode
}
return node, nil
}
func handleTrustNode(stdin *bufio.Reader) (bool, error) {
return GetConfirmation("Do you trust this node?", stdin)
}
func createGaiaCLIConfig(cfg *cliConfig) error {
cfgPath := path.Join(cfg.Home, "config")
err := os.MkdirAll(cfgPath, os.ModePerm)
if err != nil {
return err
}
data, err := toml.Marshal(*cfg)
if err != nil {
return err
}
cfgFile := path.Join(cfgPath, "config.toml")
if info, err := os.Stat(cfgFile); err == nil && !info.IsDir() {
err = os.Rename(cfgFile, path.Join(cfgPath, "config.toml-old"))
if err != nil {
return err
}
}
return ioutil.WriteFile(cfgFile, data, os.ModePerm)
}

View File

@ -5,6 +5,7 @@ import (
"strconv"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
// nolint
@ -51,6 +52,10 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
c.Flags().String(FlagChainID, "", "Chain ID of tendermint node")
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().Int64(FlagHeight, 0, "block height to query, omit to get most recent provable block")
viper.BindPFlag(FlagTrustNode, c.Flags().Lookup(FlagTrustNode))
viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger))
viper.BindPFlag(FlagChainID, c.Flags().Lookup(FlagChainID))
viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode))
}
return cmds
}
@ -76,6 +81,10 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
// --gas can accept integers and "simulate"
c.Flags().Var(&GasFlagVar, "gas", fmt.Sprintf(
"gas limit to set per-transaction; set to %q to calculate required gas automatically (default %d)", GasFlagSimulate, DefaultGasLimit))
viper.BindPFlag(FlagTrustNode, c.Flags().Lookup(FlagTrustNode))
viper.BindPFlag(FlagUseLedger, c.Flags().Lookup(FlagUseLedger))
viper.BindPFlag(FlagChainID, c.Flags().Lookup(FlagChainID))
viper.BindPFlag(FlagNode, c.Flags().Lookup(FlagNode))
}
return cmds
}

View File

@ -100,6 +100,19 @@ func GetConfirmation(prompt string, buf *bufio.Reader) (bool, error) {
}
}
// GetString simply returns the trimmed string output of a given reader.
func GetString(prompt string, buf *bufio.Reader) (string, error) {
if inputIsTty() && prompt != "" {
PrintPrefixed(prompt)
}
out, err := readLineFromBuf(buf)
if err != nil {
return "", err
}
return strings.TrimSpace(out), nil
}
// inputIsTty returns true iff we have an interactive prompt,
// where we can disable echo and request to repeat the password.
// If false, we can optimize for piped input from another command
@ -117,3 +130,8 @@ func readLineFromBuf(buf *bufio.Reader) (string, error) {
}
return strings.TrimSpace(pass), nil
}
// PrintPrefixed prints a string with > prefixed for use in prompts.
func PrintPrefixed(msg string) {
fmt.Printf("> %s\n", msg)
}

View File

@ -121,6 +121,9 @@ func ServeCommand(cdc *codec.Codec) *cobra.Command {
cmd.Flags().String(client.FlagNode, "tcp://localhost:26657", "Address of the node to connect to")
cmd.Flags().Int(flagMaxOpenConnections, 1000, "The number of maximum open connections")
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
return cmd
}

View File

@ -10,6 +10,7 @@ import (
"github.com/gorilla/mux"
"github.com/spf13/cobra"
"github.com/spf13/viper"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
)
@ -22,7 +23,9 @@ func BlockCommand() *cobra.Command {
RunE: printBlock,
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
return cmd
}

View File

@ -7,6 +7,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/spf13/viper"
)
const (
@ -40,6 +41,9 @@ func initClientCommand() *cobra.Command {
cmd.Flags().String(flagGenesis, "", "Genesis file to verify header validity")
cmd.Flags().String(flagCommit, "", "File with trusted and signed header")
cmd.Flags().String(flagValHash, "", "Hash of trusted validator set (hex-encoded)")
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
return cmd
}

View File

@ -10,6 +10,7 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"github.com/spf13/viper"
)
func statusCommand() *cobra.Command {
@ -20,6 +21,7 @@ func statusCommand() *cobra.Command {
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
return cmd
}

View File

@ -13,6 +13,7 @@ import (
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/spf13/viper"
)
// TODO these next two functions feel kinda hacky based on their placement
@ -26,8 +27,11 @@ func ValidatorCommand() *cobra.Command {
RunE: printValidators,
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
return cmd
}

View File

@ -3,8 +3,8 @@ package tx
import (
"encoding/hex"
"fmt"
"github.com/tendermint/tendermint/libs/common"
"net/http"
"github.com/tendermint/tendermint/libs/common"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/spf13/viper"
)
// QueryTxCmd implements the default command for a tx query.
@ -41,8 +42,11 @@ func QueryTxCmd(cdc *codec.Codec) *cobra.Command {
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
return cmd
}

View File

@ -62,8 +62,11 @@ $ gaiacli tendermint txs --tag test1,test2 --any
}
cmd.Flags().StringP(client.FlagNode, "n", "tcp://localhost:26657", "Node to connect to")
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagNode, cmd.Flags().Lookup(client.FlagNode))
cmd.Flags().String(client.FlagChainID, "", "Chain ID of Tendermint node")
viper.BindPFlag(client.FlagChainID, cmd.Flags().Lookup(client.FlagChainID))
cmd.Flags().Bool(client.FlagTrustNode, false, "Trust connected full node (don't verify proofs for responses)")
viper.BindPFlag(client.FlagTrustNode, cmd.Flags().Lookup(client.FlagTrustNode))
cmd.Flags().StringSlice(flagTags, nil, "Comma-separated list of tags that must match")
cmd.Flags().Bool(flagAny, false, "Return transactions that match ANY tag, rather than ALL")
return cmd

View File

@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"testing"
"path"
"github.com/stretchr/testify/require"
@ -515,6 +516,48 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) {
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
}
func TestGaiaCLIConfig(t *testing.T) {
require.NoError(t, os.RemoveAll(gaiacliHome))
require.NoError(t, os.RemoveAll(gaiadHome))
servAddr, port, err := server.FreeTCPAddr()
require.NoError(t, err)
node := fmt.Sprintf("%s:%s", servAddr, port)
chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome))
executeWrite(t, fmt.Sprintf("gaiacli --home=%s config", gaiadHome), gaiacliHome, node, "y")
config, err := ioutil.ReadFile(path.Join(gaiacliHome, "config", "config.toml"))
require.NoError(t, err)
expectedConfig := fmt.Sprintf(`chain_id = "%s"
encoding = "btc"
home = "%s"
node = "%s"
output = "text"
trace = false
trust_node = true
`, chainID, gaiacliHome, node)
require.Equal(t, expectedConfig, string(config))
// ensure a backup gets created
executeWrite(t, "gaiacli config", gaiacliHome, node, "y", "y")
configBackup, err := ioutil.ReadFile(path.Join(gaiacliHome, "config", "config.toml-old"))
require.NoError(t, err)
require.Equal(t, expectedConfig, string(configBackup))
require.NoError(t, os.RemoveAll(gaiadHome))
executeWrite(t, "gaiacli config", gaiacliHome, node, "y")
// ensure it works without an initialized gaiad state
expectedConfig = fmt.Sprintf(`chain_id = ""
encoding = "btc"
home = "%s"
node = "%s"
output = "text"
trace = false
trust_node = true
`, gaiacliHome, node)
config, err = ioutil.ReadFile(path.Join(gaiacliHome, "config", "config.toml"))
require.NoError(t, err)
require.Equal(t, expectedConfig, string(config))
}
//___________________________________________________________________________________
// helper methods

View File

@ -19,6 +19,9 @@ import (
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/client/cli"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"path"
"os"
"github.com/spf13/viper"
)
// rootCmd is the entry point for this binary
@ -36,6 +39,7 @@ func main() {
// TODO: setup keybase, viper object, etc. to be passed into
// the below functions and eliminate global vars, like we do
// with the cdc
rootCmd.AddCommand(client.ConfigCmd())
// add standard rpc commands
rpc.AddCommands(rootCmd)
@ -146,9 +150,35 @@ func main() {
// prepare and add flags
executor := cli.PrepareMainCmd(rootCmd, "GA", app.DefaultCLIHome)
err := executor.Execute()
err := initConfig(rootCmd)
if err != nil {
panic(err)
}
err = executor.Execute()
if err != nil {
// handle with #870
panic(err)
}
}
func initConfig(cmd *cobra.Command) error {
home, err := cmd.PersistentFlags().GetString(cli.HomeFlag)
if err != nil {
return err
}
cfgFile := path.Join(home, "config", "config.toml")
if _, err := os.Stat(cfgFile); err == nil {
viper.SetConfigFile(cfgFile)
if err := viper.ReadInConfig(); err != nil {
return err
}
}
if err := viper.BindPFlag(cli.EncodingFlag, cmd.PersistentFlags().Lookup(cli.EncodingFlag)); err != nil {
return err
}
return viper.BindPFlag(cli.OutputFlag, cmd.PersistentFlags().Lookup(cli.OutputFlag))
}

View File

@ -0,0 +1,19 @@
## Receiver Hooks
The staking module allow for the following hooks to be registered with staking events:
``` golang
// event hooks for staking validator object
type StakingHooks interface {
OnValidatorCreated(ctx Context, address ValAddress) // called when a validator is created
OnValidatorCommissionChange(ctx Context, address ValAddress) // called when a validator's commission is modified
OnValidatorRemoved(ctx Context, address ValAddress) // called when a validator is deleted
OnValidatorBonded(ctx Context, address ConsAddress) // called when a validator is bonded
OnValidatorBeginUnbonding(ctx Context, address ConsAddress) // called when a validator begins unbonding
OnDelegationCreated(ctx Context, delAddr AccAddress, valAddr ValAddress) // called when a delegation is created
OnDelegationSharesModified(ctx Context, delAddr AccAddress, valAddr ValAddress) // called when a delegation's shares are modified
OnDelegationRemoved(ctx Context, delAddr AccAddress, valAddr ValAddress) // called when a delegation is removed
}
```

View File

@ -102,12 +102,25 @@ type DelegationSet interface {
fn func(index int64, delegation Delegation) (stop bool))
}
// validator event hooks
// These can be utilized to communicate between a staking keeper
// and another keeper which must take particular actions when
// validators are bonded and unbonded. The second keeper must implement
// this interface, which then the staking keeper can call.
type ValidatorHooks interface {
//_______________________________________________________________________________
// Event Hooks
// These can be utilized to communicate between a staking keeper and another
// keeper which must take particular actions when validators/delegators change
// state. The second keeper must implement this interface, which then the
// staking keeper can call.
// TODO refactor event hooks out to the receiver modules
// event hooks for staking validator object
type StakingHooks interface {
OnValidatorCreated(ctx Context, address ValAddress) // Must be called when a validator is created
OnValidatorCommissionChange(ctx Context, address ValAddress) // Must be called when a validator's commission is modified
OnValidatorRemoved(ctx Context, address ValAddress) // Must be called when a validator is deleted
OnValidatorBonded(ctx Context, address ConsAddress) // Must be called when a validator is bonded
OnValidatorBeginUnbonding(ctx Context, address ConsAddress) // Must be called when a validator begins unbonding
OnDelegationCreated(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation is created
OnDelegationSharesModified(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation's shares are modified
OnDelegationRemoved(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation is removed
}

View File

@ -1,6 +1,10 @@
package types
import "encoding/json"
import (
"encoding/json"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
tmtypes "github.com/tendermint/tendermint/types"
)
// SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces
// are removed.
@ -29,3 +33,22 @@ func MustSortJSON(toSortJSON []byte) []byte {
}
return js
}
// DefaultChainID returns the chain ID from the genesis file if present. An
// error is returned if the file cannot be read or parsed.
//
// TODO: This should be removed and the chainID should always be provided by
// the end user.
func DefaultChainID() (string, error) {
cfg, err := tcmd.ParseConfig()
if err != nil {
return "", err
}
doc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile())
if err != nil {
return "", err
}
return doc.ChainID, nil
}

View File

@ -30,7 +30,7 @@ func NewTxBuilderFromCLI() TxBuilder {
// if chain ID is not specified manually, read default chain ID
chainID := viper.GetString(client.FlagChainID)
if chainID == "" {
defaultChainID, err := defaultChainID()
defaultChainID, err := sdk.DefaultChainID()
if err != nil {
chainID = defaultChainID
}

View File

@ -1,25 +0,0 @@
package context
import (
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
tmtypes "github.com/tendermint/tendermint/types"
)
// defaultChainID returns the chain ID from the genesis file if present. An
// error is returned if the file cannot be read or parsed.
//
// TODO: This should be removed and the chainID should always be provided by
// the end user.
func defaultChainID() (string, error) {
cfg, err := tcmd.ParseConfig()
if err != nil {
return "", err
}
doc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile())
if err != nil {
return "", err
}
return doc.ChainID, nil
}

View File

@ -29,10 +29,10 @@ type Hooks struct {
k Keeper
}
var _ sdk.ValidatorHooks = Hooks{}
var _ sdk.StakingHooks = Hooks{}
// Return the wrapper struct
func (k Keeper) ValidatorHooks() Hooks {
func (k Keeper) Hooks() Hooks {
return Hooks{k}
}
@ -45,3 +45,11 @@ func (h Hooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) {
func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) {
h.k.onValidatorBeginUnbonding(ctx, address)
}
// nolint - unused hooks
func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) OnValidatorCommissionChange(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
func (h Hooks) OnDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}

View File

@ -27,7 +27,7 @@ func TestHandleDoubleSign(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
sk = sk.WithHooks(keeper.Hooks())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt))
@ -69,7 +69,7 @@ func TestSlashingPeriodCap(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
sk = sk.WithHooks(keeper.Hooks())
amtInt := int64(100)
addr, amt := addrs[0], sdk.NewInt(amtInt)
valConsPubKey, valConsAddr := pks[0], sdk.ConsAddress(pks[0].Address())
@ -125,7 +125,7 @@ func TestHandleAbsentValidator(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
sk = sk.WithHooks(keeper.Hooks())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
sh := stake.NewHandler(sk)

View File

@ -98,6 +98,10 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
return err.Result()
}
k.OnValidatorCreated(ctx, validator.OperatorAddr)
accAddr := sdk.AccAddress(validator.OperatorAddr)
k.OnDelegationCreated(ctx, accAddr, validator.OperatorAddr)
tags := sdk.NewTags(
tags.Action, tags.ActionCreateValidator,
tags.DstValidator, []byte(msg.ValidatorAddr.String()),
@ -166,6 +170,9 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper)
return err.Result()
}
// call the hook if present
k.OnDelegationCreated(ctx, msg.DelegatorAddr, validator.OperatorAddr)
tags := sdk.NewTags(
tags.Action, tags.ActionDelegate,
tags.Delegator, []byte(msg.DelegatorAddr.String()),

View File

@ -66,7 +66,7 @@ func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) {
// remove a delegation from store
func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) {
k.OnDelegationRemoved(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
store := ctx.KVStore(k.storeKey)
store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr))
}
@ -283,6 +283,8 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co
func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress,
shares sdk.Dec) (amount sdk.Dec, err sdk.Error) {
k.OnDelegationSharesModified(ctx, delAddr, valAddr)
// check if delegation has any shares in it unbond
delegation, found := k.GetDelegation(ctx, delAddr, valAddr)
if !found {
@ -334,6 +336,7 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
k.RemoveValidator(ctx, validator.OperatorAddr)
}
k.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr)
return amount, nil
}

View File

@ -14,7 +14,7 @@ type Keeper struct {
storeTKey sdk.StoreKey
cdc *codec.Codec
bankKeeper bank.Keeper
hooks sdk.ValidatorHooks
hooks sdk.StakingHooks
// codespace
codespace sdk.CodespaceType
@ -33,7 +33,7 @@ func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, ck bank.Keeper, codespa
}
// Set the validator hooks
func (k Keeper) WithValidatorHooks(sh sdk.ValidatorHooks) Keeper {
func (k Keeper) WithHooks(sh sdk.StakingHooks) Keeper {
if k.hooks != nil {
panic("cannot set validator hooks twice")
}

View File

@ -617,12 +617,7 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat
// also remove from the Bonded types.Validators Store
store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr))
// call the unbond hook if present
if k.hooks != nil {
k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())
}
// return updated validator
k.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())
return validator
}
@ -652,18 +647,15 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
tstore := ctx.TransientStore(k.storeTKey)
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI)
// call the bond hook if present
if k.hooks != nil {
k.hooks.OnValidatorBonded(ctx, validator.ConsAddress())
}
// return updated validator
k.OnValidatorBonded(ctx, validator.ConsAddress())
return validator
}
// remove the validator record and associated indexes
func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) {
k.OnValidatorRemoved(ctx, address)
// first retrieve the old validator record
validator, found := k.GetValidator(ctx, address)
if !found {
@ -703,6 +695,7 @@ func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, validator types.Valid
validator.Commission.UpdateTime = blockTime
k.SetValidator(ctx, validator)
k.OnValidatorCommissionChange(ctx, validator.OperatorAddr)
return nil
}