Merge branch 'rigel/new-hooks' into rigel/fee-distribution
This commit is contained in:
commit
3846894c3a
10
Gopkg.lock
generated
10
Gopkg.lock
generated
@ -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",
|
||||
|
||||
@ -70,3 +70,7 @@
|
||||
[prune]
|
||||
go-tests = true
|
||||
unused-packages = true
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
version = "1.0.0"
|
||||
|
||||
@ -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
131
client/config.go
Normal 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)
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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))
|
||||
}
|
||||
|
||||
19
docs/spec/staking/hooks.md
Normal file
19
docs/spec/staking/hooks.md
Normal 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
|
||||
}
|
||||
```
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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) {}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()),
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user