Merge branch 'develop' into dev/benchmark_simulation

This commit is contained in:
Dev Ojha 2018-09-01 12:34:59 -07:00 committed by ValarDragon
commit 5643c0801b
113 changed files with 2977 additions and 1241 deletions

45
Gopkg.lock generated
View File

@ -34,7 +34,7 @@
[[projects]]
branch = "master"
digest = "1:6aabc1566d6351115d561d038da82a4c19b46c3b6e17f4a0a2fa60260663dc79"
digest = "1:2c00f064ba355903866cbfbf3f7f4c0fe64af6638cc7d1b8bdcf3181bc67f1d8"
name = "github.com/btcsuite/btcd"
packages = ["btcec"]
pruneopts = "UT"
@ -71,7 +71,7 @@
version = "v1.4.7"
[[projects]]
digest = "1:fa30c0652956e159cdb97dcb2ef8b8db63ed668c02a5c3a40961c8f0641252fe"
digest = "1:fdf5169073fb0ad6dc12a70c249145e30f4058647bea25f0abd48b6d9f228a11"
name = "github.com/go-kit/kit"
packages = [
"log",
@ -103,7 +103,7 @@
version = "v1.7.0"
[[projects]]
digest = "1:212285efb97b9ec2e20550d81f0446cb7897e57cbdfd7301b1363ab113d8be45"
digest = "1:35621fe20f140f05a0c4ef662c26c0ab4ee50bca78aa30fe87d33120bd28165e"
name = "github.com/gogo/protobuf"
packages = [
"gogoproto",
@ -118,7 +118,7 @@
version = "v1.1.1"
[[projects]]
digest = "1:cb22af0ed7c72d495d8be1106233ee553898950f15fd3f5404406d44c2e86888"
digest = "1:17fe264ee908afc795734e8c4e63db2accabaf57326dbf21763a7d6b86096260"
name = "github.com/golang/protobuf"
packages = [
"proto",
@ -165,13 +165,12 @@
[[projects]]
branch = "master"
digest = "1:ac64f01acc5eeea9dde40e326de6b6471e501392ec06524c3b51033aa50789bc"
digest = "1:12247a2e99a060cc692f6680e5272c8adf0b8f572e6bce0d7095e624c958a240"
name = "github.com/hashicorp/hcl"
packages = [
".",
"hcl/ast",
"hcl/parser",
"hcl/printer",
"hcl/scanner",
"hcl/strconv",
"hcl/token",
@ -263,7 +262,7 @@
version = "v1.0.0"
[[projects]]
digest = "1:98225904b7abff96c052b669b25788f18225a36673fba022fb93514bb9a2a64e"
digest = "1:c1a04665f9613e082e1209cf288bf64f4068dcd6c87a64bf1c4ff006ad422ba0"
name = "github.com/prometheus/client_golang"
packages = [
"prometheus",
@ -274,7 +273,7 @@
[[projects]]
branch = "master"
digest = "1:0f37e09b3e92aaeda5991581311f8dbf38944b36a3edec61cc2d1991f527554a"
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
name = "github.com/prometheus/client_model"
packages = ["go"]
pruneopts = "UT"
@ -282,7 +281,7 @@
[[projects]]
branch = "master"
digest = "1:dad2e5a2153ee7a6c9ab8fc13673a16ee4fb64434a7da980965a3741b0c981a3"
digest = "1:63b68062b8968092eb86bedc4e68894bd096ea6b24920faca8b9dcf451f54bb5"
name = "github.com/prometheus/common"
packages = [
"expfmt",
@ -294,7 +293,7 @@
[[projects]]
branch = "master"
digest = "1:a37c98f4b7a66bb5c539c0539f0915a74ef1c8e0b3b6f45735289d94cae92bfd"
digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290"
name = "github.com/prometheus/procfs"
packages = [
".",
@ -313,7 +312,7 @@
revision = "e2704e165165ec55d062f5919b4b29494e9fa790"
[[projects]]
digest = "1:37ace7f35375adec11634126944bdc45a673415e2fcc07382d03b75ec76ea94c"
digest = "1:bd1ae00087d17c5a748660b8e89e1043e1e5479d0fea743352cda2f8dd8c4f84"
name = "github.com/spf13/afero"
packages = [
".",
@ -332,7 +331,7 @@
version = "v1.2.0"
[[projects]]
digest = "1:627ab2f549a6a55c44f46fa24a4307f4d0da81bfc7934ed0473bf38b24051d26"
digest = "1:7ffc0983035bc7e297da3688d9fe19d60a420e9c38bef23f845c53788ed6a05e"
name = "github.com/spf13/cobra"
packages = ["."]
pruneopts = "UT"
@ -364,7 +363,7 @@
version = "v1.0.0"
[[projects]]
digest = "1:73697231b93fb74a73ebd8384b68b9a60c57ea6b13c56d2425414566a72c8e6d"
digest = "1:7e8d267900c7fa7f35129a2a37596e38ed0f11ca746d6d9ba727980ee138f9f6"
name = "github.com/stretchr/testify"
packages = [
"assert",
@ -376,7 +375,7 @@
[[projects]]
branch = "master"
digest = "1:442d2ffa75ffae302ce8800bf4144696b92bef02917923ea132ce2d39efe7d65"
digest = "1:f2ffd421680b0a3f7887501b3c6974bcf19217ecd301d0e2c9b681940ec363d5"
name = "github.com/syndtr/goleveldb"
packages = [
"leveldb",
@ -397,7 +396,7 @@
[[projects]]
branch = "master"
digest = "1:203b409c21115233a576f99e8f13d8e07ad82b25500491f7e1cca12588fb3232"
digest = "1:087aaa7920e5d0bf79586feb57ce01c35c830396ab4392798112e8aae8c47722"
name = "github.com/tendermint/ed25519"
packages = [
".",
@ -424,7 +423,7 @@
version = "v0.9.2"
[[projects]]
digest = "1:963f6c04345ce36f900c1d6367200eebc3cc2db6ee632ff865ea8dcf64b748a0"
digest = "1:4f15e95fe3888cc75dd34f407d6394cbc7fd3ff24920851b92b295f6a8b556e6"
name = "github.com/tendermint/tendermint"
packages = [
"abci/client",
@ -491,7 +490,7 @@
version = "v0.23.1-rc0"
[[projects]]
digest = "1:ad879bb8c71020a3f92f0c61f414d93eae1d5dc2f37023b6abaa3cc84b00165e"
digest = "1:bf6d9a827ea3cad964c2f863302e4f6823170d0b5ed16f72cf1184a7c615067e"
name = "github.com/tendermint/tmlibs"
packages = ["cli"]
pruneopts = "UT"
@ -507,7 +506,7 @@
[[projects]]
branch = "master"
digest = "1:2a3ce1f08dcae8bac666deb6e4c88b5d7170c510da38fd746231144cac351704"
digest = "1:27507554c6d4f060d8d700c31c624a43d3a92baa634e178ddc044bdf7d13b44a"
name = "golang.org/x/crypto"
packages = [
"blowfish",
@ -529,7 +528,7 @@
revision = "614d502a4dac94afa3a6ce146bd1736da82514c6"
[[projects]]
digest = "1:04dda8391c3e2397daf254ac68003f30141c069b228d06baec8324a5f81dc1e9"
digest = "1:d36f55a999540d29b6ea3c2ea29d71c76b1d9853fdcd3e5c5cb4836f2ba118f1"
name = "golang.org/x/net"
packages = [
"context",
@ -546,7 +545,7 @@
[[projects]]
branch = "master"
digest = "1:c8baf78f0ac6eb27c645e264fe5e8a74d5a50db188ab41a7ff3b275c112e0735"
digest = "1:86171d21d59449dcf7cee0b7d2da83dff989dab9b9b69bfe0a3d59c3c1ca6081"
name = "golang.org/x/sys"
packages = [
"cpu",
@ -556,7 +555,7 @@
revision = "11551d06cbcc94edc80a0facaccbda56473c19c1"
[[projects]]
digest = "1:7509ba4347d1f8de6ae9be8818b0cd1abc3deeffe28aeaf4be6d4b6b5178d9ca"
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
name = "golang.org/x/text"
packages = [
"collate",
@ -587,7 +586,7 @@
revision = "c66870c02cf823ceb633bcd05be3c7cda29976f4"
[[projects]]
digest = "1:4515e3030c440845b046354fd5d57671238428b820deebce2e9dabb5cd3c51ac"
digest = "1:2dab32a43451e320e49608ff4542fdfc653c95dcc35d0065ec9c6c3dd540ed74"
name = "google.golang.org/grpc"
packages = [
".",
@ -664,6 +663,8 @@
"github.com/tendermint/tendermint/libs/common",
"github.com/tendermint/tendermint/libs/db",
"github.com/tendermint/tendermint/libs/log",
"github.com/tendermint/tendermint/lite",
"github.com/tendermint/tendermint/lite/proxy",
"github.com/tendermint/tendermint/node",
"github.com/tendermint/tendermint/p2p",
"github.com/tendermint/tendermint/privval",

View File

@ -13,16 +13,24 @@ BREAKING CHANGES
* [cli] \#2061 changed proposalID in governance REST endpoints to proposal-id
* [cli] \#2014 `gaiacli advanced` no longer exists - to access `ibc`, `rest-server`, and `validator-set` commands use `gaiacli ibc`, `gaiacli rest-server`, and `gaiacli tendermint`, respectively
* [makefile] `get_vendor_deps` no longer updates lock file it just updates vendor directory. Use `update_vendor_deps` to update the lock file. [#2152](https://github.com/cosmos/cosmos-sdk/pull/2152)
* [cli] \#2190 `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion
* \#2040 All commands that utilize a validator's address must now use the new
bech32 prefix, `cosmosval`. A validator's Tendermint signing key and address
now use a new bech32 prefix, `cosmoscons`.
* Gaia
* Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013)
* [x/stake] \#1901 Validator type's Owner field renamed to Operator; Validator's GetOwner() renamed accordingly to comply with the SDK's Validator interface.
* [docs] [#2001](https://github.com/cosmos/cosmos-sdk/pull/2001) Update slashing spec for slashing period
* [x/stake, x/slashing] [#1305](https://github.com/cosmos/cosmos-sdk/issues/1305) - Rename "revoked" to "jailed"
* [x/stake] \#2040 Validator operator type has now changed to `sdk.ValAddress`
* A new bech32 prefix has been introduced for Tendermint signing keys and
addresses, `cosmosconspub` and `cosmoscons` respectively.
* SDK
* [core] \#1807 Switch from use of rational to decimal
* [types] \#1901 Validator interface's GetOwner() renamed to GetOperator()
* [x/slashing] [#2122](https://github.com/cosmos/cosmos-sdk/pull/2122) - Implement slashing period
* [types] \#2119 Parsed error messages and ABCI log errors to make them more human readable.
* [simulation] Rename TestAndRunTx to Operation [#2153](https://github.com/cosmos/cosmos-sdk/pull/2153)
@ -33,14 +41,19 @@ FEATURES
* Gaia REST API (`gaiacli advanced rest-server`)
* [lcd] Endpoints to query staking pool and params
* [lcd] \#2110 Add support for `simulate=true` requests query argument to endpoints that send txs to run simulations of transactions
* Gaia CLI (`gaiacli`)
* [cli] Cmds to query staking pool and params
* [gov][cli] #2062 added `--proposal` flag to `submit-proposal` that allows a JSON file containing a proposal to be passed in
* \#2040 Add `--bech` to `gaiacli keys show` and respective REST endpoint to
provide desired Bech32 prefix encoding
* [cli] \#2047 Setting the --gas flag value to 0 triggers a simulation of the tx before the actual execution. The gas estimate obtained via the simulation will be used as gas limit in the actual execution.
* [cli] \#2047 The --gas-adjustment flag can be used to adjust the estimate obtained via the simulation triggered by --gas=0.
* [cli] \#2110 Add --dry-run flag to perform a simulation of a transaction without broadcasting it. The --gas flag is ignored as gas would be automatically estimated.
* Gaia
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
* SDK
* [querier] added custom querier functionality, so ABCI query requests can be handled by keepers
@ -64,6 +77,7 @@ IMPROVEMENTS
* Gaia
* [x/stake] [#2023](https://github.com/cosmos/cosmos-sdk/pull/2023) Terminate iteration loop in `UpdateBondedValidators` and `UpdateBondedValidatorsFull` when the first revoked validator is encountered and perform a sanity check.
* [x/auth] Signature verification's gas cost now accounts for pubkey type. [#2046](https://github.com/tendermint/tendermint/pull/2046)
* [x/stake] [x/slashing] Ensure delegation invariants to jailed validators [#1883](https://github.com/cosmos/cosmos-sdk/issues/1883).
* SDK
* [tools] Make get_vendor_deps deletes `.vendor-new` directories, in case scratch files are present.

View File

@ -1,14 +1,18 @@
package context
import (
"io"
"bytes"
"fmt"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"io"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/cli"
tmlite "github.com/tendermint/tendermint/lite"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"
)
@ -32,6 +36,8 @@ type CLIContext struct {
Async bool
JSON bool
PrintResponse bool
Certifier tmlite.Certifier
DryRun bool
}
// NewCLIContext returns a new initialized CLIContext with parameters from the
@ -57,9 +63,41 @@ func NewCLIContext() CLIContext {
Async: viper.GetBool(client.FlagAsync),
JSON: viper.GetBool(client.FlagJson),
PrintResponse: viper.GetBool(client.FlagPrintResponse),
Certifier: createCertifier(),
DryRun: viper.GetBool(client.FlagDryRun),
}
}
func createCertifier() tmlite.Certifier {
trustNode := viper.GetBool(client.FlagTrustNode)
if trustNode {
return nil
}
chainID := viper.GetString(client.FlagChainID)
home := viper.GetString(cli.HomeFlag)
nodeURI := viper.GetString(client.FlagNode)
var errMsg bytes.Buffer
if chainID == "" {
errMsg.WriteString("chain-id ")
}
if home == "" {
errMsg.WriteString("home ")
}
if nodeURI == "" {
errMsg.WriteString("node ")
}
// errMsg is not empty
if errMsg.Len() != 0 {
panic(fmt.Errorf("can't create certifier for distrust mode, empty values from these options: %s", errMsg.String()))
}
certifier, err := tmliteProxy.GetCertifier(chainID, home, nodeURI)
if err != nil {
panic(err)
}
return certifier
}
// WithCodec returns a copy of the context with an updated codec.
func (ctx CLIContext) WithCodec(cdc *wire.Codec) CLIContext {
ctx.Codec = cdc
@ -117,3 +155,15 @@ func (ctx CLIContext) WithUseLedger(useLedger bool) CLIContext {
ctx.UseLedger = useLedger
return ctx
}
// WithCertifier - return a copy of the context with an updated Certifier
func (ctx CLIContext) WithCertifier(certifier tmlite.Certifier) CLIContext {
ctx.Certifier = certifier
return ctx
}
// WithGasAdjustment returns a copy of the context with an updated GasAdjustment flag.
func (ctx CLIContext) WithGasAdjustment(adjustment float64) CLIContext {
ctx.GasAdjustment = adjustment
return ctx
}

View File

@ -10,9 +10,14 @@ import (
"github.com/pkg/errors"
"github.com/cosmos/cosmos-sdk/store"
"github.com/cosmos/cosmos-sdk/wire"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
tmliteProxy "github.com/tendermint/tendermint/lite/proxy"
rpcclient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
"strings"
)
// GetNode returns an RPC client. If the context's client is not defined, an
@ -304,12 +309,77 @@ func (ctx CLIContext) query(path string, key cmn.HexBytes) (res []byte, err erro
return res, errors.Errorf("query failed: (%d) %s", resp.Code, resp.Log)
}
// Data from trusted node or subspace query doesn't need verification
if ctx.TrustNode || !isQueryStoreWithProof(path) {
return resp.Value, nil
}
err = ctx.verifyProof(path, resp)
if err != nil {
return nil, err
}
return resp.Value, nil
}
// verifyProof perform response proof verification
func (ctx CLIContext) verifyProof(path string, resp abci.ResponseQuery) error {
if ctx.Certifier == nil {
return fmt.Errorf("missing valid certifier to verify data from untrusted node")
}
node, err := ctx.GetNode()
if err != nil {
return err
}
// AppHash for height H is in header H+1
commit, err := tmliteProxy.GetCertifiedCommit(resp.Height+1, node, ctx.Certifier)
if err != nil {
return err
}
var multiStoreProof store.MultiStoreProof
cdc := wire.NewCodec()
err = cdc.UnmarshalBinary(resp.Proof, &multiStoreProof)
if err != nil {
return errors.Wrap(err, "failed to unmarshalBinary rangeProof")
}
// Verify the substore commit hash against trusted appHash
substoreCommitHash, err := store.VerifyMultiStoreCommitInfo(multiStoreProof.StoreName,
multiStoreProof.StoreInfos, commit.Header.AppHash)
if err != nil {
return errors.Wrap(err, "failed in verifying the proof against appHash")
}
err = store.VerifyRangeProof(resp.Key, resp.Value, substoreCommitHash, &multiStoreProof.RangeProof)
if err != nil {
return errors.Wrap(err, "failed in the range proof verification")
}
return nil
}
// queryStore performs a query from a Tendermint node with the provided a store
// name and path.
func (ctx CLIContext) queryStore(key cmn.HexBytes, storeName, endPath string) ([]byte, error) {
path := fmt.Sprintf("/store/%s/%s", storeName, endPath)
return ctx.query(path, key)
}
// isQueryStoreWithProof expects a format like /<queryType>/<storeName>/<subpath>
// queryType can be app or store
func isQueryStoreWithProof(path string) bool {
if !strings.HasPrefix(path, "/") {
return false
}
paths := strings.SplitN(path[1:], "/", 3)
if len(paths) != 3 {
return false
}
if store.RequireProof("/" + paths[2]) {
return true
}
return false
}

View File

@ -4,8 +4,11 @@ import "github.com/spf13/cobra"
// nolint
const (
// DefaultGasAdjustment is applied to gas estimates to avoid tx
// execution failures due to state changes that might
// occur between the tx simulation and the actual run.
DefaultGasAdjustment = 1.0
DefaultGasLimit = 200000
DefaultGasAdjustment = 1.2
FlagUseLedger = "ledger"
FlagChainID = "chain-id"
@ -23,6 +26,7 @@ const (
FlagAsync = "async"
FlagJson = "json"
FlagPrintResponse = "print-response"
FlagDryRun = "dry-run"
)
// LineBreak can be included in a command list to provide a blank line
@ -54,10 +58,12 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device")
c.Flags().Int64(FlagGas, DefaultGasLimit, "gas limit to set per-transaction; set to 0 to calculate required gas automatically")
c.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation")
c.Flags().Float64(FlagGasAdjustment, DefaultGasAdjustment, "adjustment factor to be multiplied against the estimate returned by the tx simulation; if the gas limit is set manually this flag is ignored ")
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
c.Flags().Bool(FlagJson, false, "return output in json format")
c.Flags().Bool(FlagPrintResponse, true, "return tx response (only works with async = false)")
c.Flags().Bool(FlagTrustNode, true, "Don't verify proofs for query responses")
c.Flags().Bool(FlagDryRun, false, "ignore the --gas flag and perform a simulation of a transaction, but don't broadcast it")
}
return cmds
}

View File

@ -128,7 +128,8 @@ func printCreate(info keys.Info, seed string) {
output := viper.Get(cli.OutputFlag)
switch output {
case "text":
printInfo(info)
printKeyInfo(info, Bech32KeyOutput)
// print seed unless requested not to.
if !viper.GetBool(client.FlagUseLedger) && !viper.GetBool(flagNoBackup) {
fmt.Println("**Important** write this seed phrase in a safe place.")

View File

@ -21,7 +21,7 @@ func Commands() *cobra.Command {
cmd.AddCommand(
addKeyCommand(),
listKeysCmd,
showKeysCmd,
showKeysCmd(),
client.LineBreak,
deleteKeyCommand(),
updateKeyCommand(),

View File

@ -2,6 +2,7 @@ package keys
import (
"encoding/json"
"fmt"
"net/http"
"github.com/cosmos/cosmos-sdk/crypto/keys"
@ -18,46 +19,69 @@ const (
FlagAddress = "address"
// FlagPublicKey represents the user's public key on the command line.
FlagPublicKey = "pubkey"
// FlagBechPrefix defines a desired Bech32 prefix encoding for a key
FlagBechPrefix = "bech"
)
var showKeysCmd = &cobra.Command{
Use: "show <name>",
Short: "Show key info for the given name",
Long: `Return public details of one local key.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
info, err := getKey(name)
if err != nil {
return err
}
func showKeysCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "show [name]",
Short: "Show key info for the given name",
Long: `Return public details of one local key.`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0]
info, err := getKey(name)
if err != nil {
return err
}
showAddress := viper.GetBool(FlagAddress)
showPublicKey := viper.GetBool(FlagPublicKey)
outputSet := cmd.Flag(cli.OutputFlag).Changed
if showAddress && showPublicKey {
return errors.New("cannot use both --address and --pubkey at once")
}
if outputSet && (showAddress || showPublicKey) {
return errors.New("cannot use --output with --address or --pubkey")
}
if showAddress {
printKeyAddress(info)
return nil
}
if showPublicKey {
printPubKey(info)
return nil
}
showAddress := viper.GetBool(FlagAddress)
showPublicKey := viper.GetBool(FlagPublicKey)
outputSet := cmd.Flag(cli.OutputFlag).Changed
printInfo(info)
return nil
},
if showAddress && showPublicKey {
return errors.New("cannot use both --address and --pubkey at once")
}
if outputSet && (showAddress || showPublicKey) {
return errors.New("cannot use --output with --address or --pubkey")
}
bechKeyOut, err := getBechKeyOut(viper.GetString(FlagBechPrefix))
if err != nil {
return err
}
switch {
case showAddress:
printKeyAddress(info, bechKeyOut)
case showPublicKey:
printPubKey(info, bechKeyOut)
default:
printKeyInfo(info, bechKeyOut)
}
return nil
},
}
cmd.Flags().String(FlagBechPrefix, "acc", "The Bech32 prefix encoding for a key (acc|val|cons)")
cmd.Flags().Bool(FlagAddress, false, "output the address only (overrides --output)")
cmd.Flags().Bool(FlagPublicKey, false, "output the public key only (overrides --output)")
return cmd
}
func init() {
showKeysCmd.Flags().Bool(FlagAddress, false, "output the address only (overrides --output)")
showKeysCmd.Flags().Bool(FlagPublicKey, false, "output the public key only (overrides --output)")
func getBechKeyOut(bechPrefix string) (bechKeyOutFn, error) {
switch bechPrefix {
case "acc":
return Bech32KeyOutput, nil
case "val":
return Bech32ValKeyOutput, nil
case "cons":
return Bech32ConsKeyOutput, nil
}
return nil, fmt.Errorf("invalid Bech32 prefix encoding provided: %s", bechPrefix)
}
func getKey(name string) (keys.Info, error) {
@ -76,21 +100,35 @@ func getKey(name string) (keys.Info, error) {
func GetKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]
bechPrefix := r.URL.Query().Get(FlagBechPrefix)
if bechPrefix == "" {
bechPrefix = "acc"
}
bechKeyOut, err := getBechKeyOut(bechPrefix)
if err != nil {
w.WriteHeader(400)
w.Write([]byte(err.Error()))
return
}
info, err := getKey(name)
// TODO check for the error if key actually does not exist, instead of assuming this as the reason
// TODO: check for the error if key actually does not exist, instead of
// assuming this as the reason
if err != nil {
w.WriteHeader(404)
w.Write([]byte(err.Error()))
return
}
keyOutput, err := Bech32KeyOutput(info)
keyOutput, err := bechKeyOut(info)
if err != nil {
w.WriteHeader(500)
w.Write([]byte(err.Error()))
return
}
output, err := json.MarshalIndent(keyOutput, "", " ")
if err != nil {
w.WriteHeader(500)

View File

@ -21,6 +21,8 @@ const KeyDBName = "keys"
// keybase is used to make GetKeyBase a singleton
var keybase keys.Keybase
type bechKeyOutFn func(keyInfo keys.Info) (KeyOutput, error)
// TODO make keybase take a database not load from the directory
// initialize a keybase based on the configuration
@ -97,11 +99,11 @@ func SetKeyBase(kb keys.Keybase) {
// used for outputting keys.Info over REST
type KeyOutput struct {
Name string `json:"name"`
Type string `json:"type"`
Address sdk.AccAddress `json:"address"`
PubKey string `json:"pub_key"`
Seed string `json:"seed,omitempty"`
Name string `json:"name"`
Type string `json:"type"`
Address string `json:"address"`
PubKey string `json:"pub_key"`
Seed string `json:"seed,omitempty"`
}
// create a list of KeyOutput in bech32 format
@ -119,24 +121,61 @@ func Bech32KeysOutput(infos []keys.Info) ([]KeyOutput, error) {
// create a KeyOutput in bech32 format
func Bech32KeyOutput(info keys.Info) (KeyOutput, error) {
account := sdk.AccAddress(info.GetPubKey().Address().Bytes())
accAddr := sdk.AccAddress(info.GetPubKey().Address().Bytes())
bechPubKey, err := sdk.Bech32ifyAccPub(info.GetPubKey())
if err != nil {
return KeyOutput{}, err
}
return KeyOutput{
Name: info.GetName(),
Type: info.GetType().String(),
Address: account,
Address: accAddr.String(),
PubKey: bechPubKey,
}, nil
}
func printInfo(info keys.Info) {
ko, err := Bech32KeyOutput(info)
// Bech32ConsKeyOutput returns key output for a consensus node's key
// information.
func Bech32ConsKeyOutput(keyInfo keys.Info) (KeyOutput, error) {
consAddr := sdk.ConsAddress(keyInfo.GetPubKey().Address().Bytes())
bechPubKey, err := sdk.Bech32ifyConsPub(keyInfo.GetPubKey())
if err != nil {
return KeyOutput{}, err
}
return KeyOutput{
Name: keyInfo.GetName(),
Type: keyInfo.GetType().String(),
Address: consAddr.String(),
PubKey: bechPubKey,
}, nil
}
// Bech32ValKeyOutput returns key output for a validator's key information.
func Bech32ValKeyOutput(keyInfo keys.Info) (KeyOutput, error) {
valAddr := sdk.ValAddress(keyInfo.GetPubKey().Address().Bytes())
bechPubKey, err := sdk.Bech32ifyValPub(keyInfo.GetPubKey())
if err != nil {
return KeyOutput{}, err
}
return KeyOutput{
Name: keyInfo.GetName(),
Type: keyInfo.GetType().String(),
Address: valAddr.String(),
PubKey: bechPubKey,
}, nil
}
func printKeyInfo(keyInfo keys.Info, bechKeyOut bechKeyOutFn) {
ko, err := bechKeyOut(keyInfo)
if err != nil {
panic(err)
}
switch viper.Get(cli.OutputFlag) {
case "text":
fmt.Printf("NAME:\tTYPE:\tADDRESS:\t\t\t\t\t\tPUBKEY:\n")
@ -146,6 +185,7 @@ func printInfo(info keys.Info) {
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
}
@ -174,18 +214,20 @@ func printKeyOutput(ko KeyOutput) {
fmt.Printf("%s\t%s\t%s\t%s\n", ko.Name, ko.Type, ko.Address, ko.PubKey)
}
func printKeyAddress(info keys.Info) {
ko, err := Bech32KeyOutput(info)
func printKeyAddress(info keys.Info, bechKeyOut bechKeyOutFn) {
ko, err := bechKeyOut(info)
if err != nil {
panic(err)
}
fmt.Println(ko.Address.String())
fmt.Println(ko.Address)
}
func printPubKey(info keys.Info) {
ko, err := Bech32KeyOutput(info)
func printPubKey(info keys.Info, bechKeyOut bechKeyOutFn) {
ko, err := bechKeyOut(info)
if err != nil {
panic(err)
}
fmt.Println(ko.PubKey)
}

View File

@ -2,6 +2,7 @@ package lcd
import (
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"regexp"
@ -62,7 +63,7 @@ func TestKeys(t *testing.T) {
err = wire.Cdc.UnmarshalJSON([]byte(body), &resp)
require.Nil(t, err, body)
addr2Bech32 := resp.Address.String()
addr2Bech32 := resp.Address
_, err = sdk.AccAddressFromBech32(addr2Bech32)
require.NoError(t, err, "Failed to return a correct bech32 address")
@ -81,9 +82,9 @@ func TestKeys(t *testing.T) {
addrBech32 := addr.String()
require.Equal(t, name, m[0].Name, "Did not serve keys name correctly")
require.Equal(t, addrBech32, m[0].Address.String(), "Did not serve keys Address correctly")
require.Equal(t, addrBech32, m[0].Address, "Did not serve keys Address correctly")
require.Equal(t, newName, m[1].Name, "Did not serve keys name correctly")
require.Equal(t, addr2Bech32, m[1].Address.String(), "Did not serve keys Address correctly")
require.Equal(t, addr2Bech32, m[1].Address, "Did not serve keys Address correctly")
// select key
keyEndpoint := fmt.Sprintf("/keys/%s", newName)
@ -94,7 +95,7 @@ func TestKeys(t *testing.T) {
require.Nil(t, err)
require.Equal(t, newName, m2.Name, "Did not serve keys name correctly")
require.Equal(t, addr2Bech32, m2.Address.String(), "Did not serve keys Address correctly")
require.Equal(t, addr2Bech32, m2.Address, "Did not serve keys Address correctly")
// update key
jsonStr = []byte(fmt.Sprintf(`{
@ -204,8 +205,8 @@ func TestValidators(t *testing.T) {
require.NotEqual(t, rpc.ResultValidatorsOutput{}, resultVals)
require.Contains(t, resultVals.Validators[0].Address.String(), "cosmosvaladdr")
require.Contains(t, resultVals.Validators[0].PubKey, "cosmosvalpub")
require.Contains(t, resultVals.Validators[0].Address.String(), "cosmosval")
require.Contains(t, resultVals.Validators[0].PubKey, "cosmosconspub")
// --
@ -265,11 +266,21 @@ func TestCoinSend(t *testing.T) {
require.Equal(t, int64(1), mycoins.Amount.Int64())
// test failure with too little gas
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 100)
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 100, 0, "")
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
// test success with just enough gas
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 3000)
// test failure with wrong adjustment
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, 0.1, "")
require.Equal(t, http.StatusInternalServerError, res.StatusCode, body)
// run simulation and test success with estimated gas
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, 0, 0, "?simulate=true")
require.Equal(t, http.StatusOK, res.StatusCode, body)
var responseBody struct {
GasEstimate int64 `json:"gas_estimate"`
}
require.Nil(t, json.Unmarshal([]byte(body), &responseBody))
res, body, _ = doSendWithGas(t, port, seed, name, password, addr, responseBody.GasEstimate, 0, "")
require.Equal(t, http.StatusOK, res.StatusCode, body)
}
@ -313,7 +324,7 @@ func TestTxs(t *testing.T) {
require.Equal(t, http.StatusBadRequest, res.StatusCode, body)
// query empty
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmosaccaddr1jawd35d9aq4u76sr3fjalmcqc8hqygs9gtnmv3"), nil)
res, body = Request(t, port, "GET", fmt.Sprintf("/txs?tag=sender_bech32='%s'", "cosmos1jawd35d9aq4u76sr3fjalmcqc8hqygs90d0g0v"), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
require.Equal(t, "[]", body)
@ -407,7 +418,7 @@ func TestValidatorsQuery(t *testing.T) {
// make sure all the validators were found (order unknown because sorted by operator addr)
foundVal := false
pkBech := sdk.MustBech32ifyValPub(pks[0])
pkBech := sdk.MustBech32ifyConsPub(pks[0])
if validators[0].PubKey == pkBech {
foundVal = true
}
@ -419,7 +430,7 @@ func TestValidatorQuery(t *testing.T) {
defer cleanup()
require.Equal(t, 1, len(pks))
validator1Operator := sdk.AccAddress(pks[0].Address())
validator1Operator := sdk.ValAddress(pks[0].Address())
validator := getValidator(t, port, validator1Operator)
assert.Equal(t, validator.Operator, validator1Operator, "The returned validator does not hold the correct data")
}
@ -430,7 +441,7 @@ func TestBonding(t *testing.T) {
cleanup, pks, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr})
defer cleanup()
validator1Operator := sdk.AccAddress(pks[0].Address())
validator1Operator := sdk.ValAddress(pks[0].Address())
validator := getValidator(t, port, validator1Operator)
// create bond TX
@ -611,7 +622,7 @@ func TestUnjail(t *testing.T) {
// XXX: any less than this and it fails
tests.WaitForHeight(3, port)
pkString, _ := sdk.Bech32ifyValPub(pks[0])
pkString, _ := sdk.Bech32ifyConsPub(pks[0])
signingInfo := getSigningInfo(t, port, pkString)
tests.WaitForHeight(4, port)
require.Equal(t, true, signingInfo.IndexOffset > 0)
@ -720,7 +731,7 @@ func getAccount(t *testing.T, port string, addr sdk.AccAddress) auth.Account {
return acc
}
func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas int64) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.AccAddress, gas int64, gasAdjustment float64, queryStr string) (res *http.Response, body string, receiveAddr sdk.AccAddress) {
// create receive address
kb := client.MockKeyBase()
@ -744,22 +755,28 @@ func doSendWithGas(t *testing.T, port, seed, name, password string, addr sdk.Acc
"gas":"%v",
`, gas)
}
gasAdjustmentStr := ""
if gasAdjustment > 0 {
gasStr = fmt.Sprintf(`
"gas_adjustment":"%v",
`, gasAdjustment)
}
jsonStr := []byte(fmt.Sprintf(`{
%v
%v%v
"name":"%s",
"password":"%s",
"account_number":"%d",
"sequence":"%d",
"amount":[%s],
"chain_id":"%s"
}`, gasStr, name, password, accnum, sequence, coinbz, chainID))
}`, gasStr, gasAdjustmentStr, name, password, accnum, sequence, coinbz, chainID))
res, body = Request(t, port, "POST", fmt.Sprintf("/accounts/%s/send", receiveAddr), jsonStr)
res, body = Request(t, port, "POST", fmt.Sprintf("/accounts/%s/send%v", receiveAddr, queryStr), jsonStr)
return
}
func doSend(t *testing.T, port, seed, name, password string, addr sdk.AccAddress) (receiveAddr sdk.AccAddress, resultTx ctypes.ResultBroadcastTxCommit) {
res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, 0)
res, body, receiveAddr := doSendWithGas(t, port, seed, name, password, addr, 0, 0, "")
require.Equal(t, http.StatusOK, res.StatusCode, body)
err := cdc.UnmarshalJSON([]byte(body), &resultTx)
@ -817,8 +834,8 @@ func getSigningInfo(t *testing.T, port string, validatorPubKey string) slashing.
// ============= Stake Module ================
func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) rest.DelegationWithoutRat {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delegatorAddr, validatorAddr), nil)
func getDelegation(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) rest.DelegationWithoutRat {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/delegations/%s", delAddr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bond rest.DelegationWithoutRat
@ -829,8 +846,8 @@ func getDelegation(t *testing.T, port string, delegatorAddr, validatorAddr sdk.A
return bond
}
func getUndelegations(t *testing.T, port string, delegatorAddr, validatorAddr sdk.AccAddress) []stake.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delegatorAddr, validatorAddr), nil)
func getUndelegations(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) []stake.UnbondingDelegation {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/unbonding_delegations/%s", delAddr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var unbondings []stake.UnbondingDelegation
@ -884,8 +901,8 @@ func getDelegatorValidators(t *testing.T, port string, delegatorAddr sdk.AccAddr
return bondedValidators
}
func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) stake.BechValidator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delegatorAddr, validatorAddr), nil)
func getDelegatorValidator(t *testing.T, port string, delAddr sdk.AccAddress, valAddr sdk.ValAddress) stake.BechValidator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/delegators/%s/validators/%s", delAddr, valAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var bondedValidator stake.BechValidator
@ -895,8 +912,10 @@ func getDelegatorValidator(t *testing.T, port string, delegatorAddr sdk.AccAddre
return bondedValidator
}
func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr, validatorAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delegatorAddr)
func doDelegate(t *testing.T, port, seed, name, password string,
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
@ -918,9 +937,9 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr,
"complete_unbondings": [],
"begin_redelegates": [],
"complete_redelegates": []
}`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, "steak", amount))
}`, name, password, accnum, sequence, chainID, delAddr, valAddr, "steak", amount))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr)
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@ -931,9 +950,9 @@ func doDelegate(t *testing.T, port, seed, name, password string, delegatorAddr,
}
func doBeginUnbonding(t *testing.T, port, seed, name, password string,
delegatorAddr, validatorAddr sdk.AccAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delegatorAddr)
acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
chainID := viper.GetString(client.FlagChainID)
@ -955,9 +974,9 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string,
"complete_unbondings": [],
"begin_redelegates": [],
"complete_redelegates": []
}`, name, password, accnum, sequence, chainID, delegatorAddr, validatorAddr, amount))
}`, name, password, accnum, sequence, chainID, delAddr, valAddr, amount))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr)
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@ -968,9 +987,9 @@ func doBeginUnbonding(t *testing.T, port, seed, name, password string,
}
func doBeginRedelegation(t *testing.T, port, seed, name, password string,
delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) (resultTx ctypes.ResultBroadcastTxCommit) {
delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, delegatorAddr)
acc := getAccount(t, port, delAddr)
accnum := acc.GetAccountNumber()
sequence := acc.GetSequence()
@ -994,9 +1013,9 @@ func doBeginRedelegation(t *testing.T, port, seed, name, password string,
}
],
"complete_redelegates": []
}`, name, password, accnum, sequence, chainID, delegatorAddr, validatorSrcAddr, validatorDstAddr))
}`, name, password, accnum, sequence, chainID, delAddr, valSrcAddr, valDstAddr))
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delegatorAddr), jsonStr)
res, body := Request(t, port, "POST", fmt.Sprintf("/stake/delegators/%s/delegations", delAddr), jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var results []ctypes.ResultBroadcastTxCommit
@ -1015,8 +1034,8 @@ func getValidators(t *testing.T, port string) []stake.BechValidator {
return validators
}
func getValidator(t *testing.T, port string, validatorAddr sdk.AccAddress) stake.BechValidator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", validatorAddr.String()), nil)
func getValidator(t *testing.T, port string, valAddr sdk.ValAddress) stake.BechValidator {
res, body := Request(t, port, "GET", fmt.Sprintf("/stake/validators/%s", valAddr.String()), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body)
var validator stake.BechValidator
err := cdc.UnmarshalJSON([]byte(body), &validator)

View File

@ -4,11 +4,11 @@ import (
"net/http"
"os"
client "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
keys "github.com/cosmos/cosmos-sdk/client/keys"
rpc "github.com/cosmos/cosmos-sdk/client/rpc"
tx "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/wire"
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
@ -66,6 +66,7 @@ func ServeCommand(cdc *wire.Codec) *cobra.Command {
cmd.Flags().String(client.FlagChainID, "", "The chain ID to connect to")
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, "Whether trust connected full node")
return cmd
}

View File

@ -190,6 +190,7 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
node, err := startTM(config, logger, genDoc, privVal, app)
require.NoError(t, err)
tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress))
lcd, err := startLCD(logger, listenAddr, cdc)
require.NoError(t, err)

View File

@ -45,7 +45,7 @@ type ResultValidatorsOutput struct {
}
func bech32ValidatorOutput(validator *tmtypes.Validator) (ValidatorOutput, error) {
bechValPubkey, err := sdk.Bech32ifyValPub(validator.PubKey)
bechValPubkey, err := sdk.Bech32ifyConsPub(validator.PubKey)
if err != nil {
return ValidatorOutput{}, err
}

View File

@ -1,12 +1,45 @@
package utils
import (
"fmt"
"net/http"
"strconv"
)
const (
queryArgDryRun = "simulate"
)
// WriteErrorResponse prepares and writes a HTTP error
// given a status code and an error message.
func WriteErrorResponse(w *http.ResponseWriter, status int, msg string) {
(*w).WriteHeader(status)
(*w).Write([]byte(msg))
func WriteErrorResponse(w http.ResponseWriter, status int, msg string) {
w.WriteHeader(status)
w.Write([]byte(msg))
}
// WriteGasEstimateResponse prepares and writes an HTTP
// response for transactions simulations.
func WriteSimulationResponse(w http.ResponseWriter, gas int64) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf(`{"gas_estimate":%v}`, gas)))
}
// HasDryRunArg returns true if the request's URL query contains
// the dry run argument and its value is set to "true".
func HasDryRunArg(r *http.Request) bool {
return r.URL.Query().Get(queryArgDryRun) == "true"
}
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a default
// value if the string is empty. Write
func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEmpty float64) (n float64, ok bool) {
if len(s) == 0 {
return defaultIfEmpty, true
}
n, err := strconv.ParseFloat(s, 64)
if err != nil {
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return n, false
}
return n, true
}

View File

@ -12,46 +12,26 @@ import (
"github.com/tendermint/tendermint/libs/common"
)
// DefaultGasAdjustment is applied to gas estimates to avoid tx
// execution failures due to state changes that might
// occur between the tx simulation and the actual run.
const DefaultGasAdjustment = 1.2
// SendTx implements a auxiliary handler that facilitates sending a series of
// messages in a signed transaction given a TxContext and a QueryContext. It
// ensures that the account exists, has a proper number and sequence set. In
// addition, it builds and signs a transaction with the supplied messages.
// Finally, it broadcasts the signed transaction to a node.
func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg) error {
if err := cliCtx.EnsureAccountExists(); err != nil {
return err
}
from, err := cliCtx.GetFromAddress()
txCtx, err := prepareTxContext(txCtx, cliCtx)
if err != nil {
return err
}
// TODO: (ref #1903) Allow for user supplied account number without
// automatically doing a manual lookup.
if txCtx.AccountNumber == 0 {
accNum, err := cliCtx.GetAccountNumber(from)
autogas := cliCtx.DryRun || (cliCtx.Gas == 0)
if autogas {
txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, msgs)
if err != nil {
return err
}
txCtx = txCtx.WithAccountNumber(accNum)
fmt.Fprintf(os.Stdout, "estimated gas = %v\n", txCtx.Gas)
}
// TODO: (ref #1903) Allow for user supplied account sequence without
// automatically doing a manual lookup.
if txCtx.Sequence == 0 {
accSeq, err := cliCtx.GetAccountSequence(from)
if err != nil {
return err
}
txCtx = txCtx.WithSequence(accSeq)
if cliCtx.DryRun {
return nil
}
passphrase, err := keys.GetPassphrase(cliCtx.FromAddressName)
@ -59,13 +39,6 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg)
return err
}
if cliCtx.Gas == 0 {
txCtx, err = EnrichCtxWithGas(txCtx, cliCtx, cliCtx.FromAddressName, passphrase, msgs)
if err != nil {
return err
}
}
// build and sign the transaction
txBytes, err := txCtx.BuildAndSign(cliCtx.FromAddressName, passphrase, msgs)
if err != nil {
@ -75,24 +48,24 @@ func SendTx(txCtx authctx.TxContext, cliCtx context.CLIContext, msgs []sdk.Msg)
return cliCtx.EnsureBroadcastTx(txBytes)
}
// EnrichCtxWithGas calculates the gas estimate that would be consumed by the
// transaction and set the transaction's respective value accordingly.
func EnrichCtxWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name, passphrase string, msgs []sdk.Msg) (authctx.TxContext, error) {
txBytes, err := BuildAndSignTxWithZeroGas(txCtx, name, passphrase, msgs)
// SimulateMsgs simulates the transaction and returns the gas estimate and the adjusted value.
func SimulateMsgs(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, msgs []sdk.Msg, gas int64) (estimated, adjusted int64, err error) {
txBytes, err := txCtx.WithGas(gas).BuildWithPubKey(name, msgs)
if err != nil {
return txCtx, err
return
}
estimate, adjusted, err := CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment)
if err != nil {
return txCtx, err
}
fmt.Fprintf(os.Stderr, "gas: [estimated = %v] [adjusted = %v]\n", estimate, adjusted)
return txCtx.WithGas(adjusted), nil
estimated, adjusted, err = CalculateGas(cliCtx.Query, cliCtx.Codec, txBytes, cliCtx.GasAdjustment)
return
}
// BuildAndSignTxWithZeroGas builds transactions with GasWanted set to 0.
func BuildAndSignTxWithZeroGas(txCtx authctx.TxContext, name, passphrase string, msgs []sdk.Msg) ([]byte, error) {
return txCtx.WithGas(0).BuildAndSign(name, passphrase, msgs)
// EnrichCtxWithGas calculates the gas estimate that would be consumed by the
// transaction and set the transaction's respective value accordingly.
func EnrichCtxWithGas(txCtx authctx.TxContext, cliCtx context.CLIContext, name string, msgs []sdk.Msg) (authctx.TxContext, error) {
_, adjusted, err := SimulateMsgs(txCtx, cliCtx, name, msgs, 0)
if err != nil {
return txCtx, err
}
return txCtx.WithGas(adjusted), nil
}
// CalculateGas simulates the execution of a transaction and returns
@ -109,14 +82,10 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *
return
}
adjusted = adjustGasEstimate(estimate, adjustment)
fmt.Fprintf(os.Stderr, "gas: [estimated = %v] [adjusted = %v]\n", estimate, adjusted)
return
}
func adjustGasEstimate(estimate int64, adjustment float64) int64 {
if adjustment == 0 {
return int64(DefaultGasAdjustment * float64(estimate))
}
return int64(adjustment * float64(estimate))
}
@ -127,3 +96,35 @@ func parseQueryResponse(cdc *amino.Codec, rawRes []byte) (int64, error) {
}
return simulationResult.GasUsed, nil
}
func prepareTxContext(txCtx authctx.TxContext, cliCtx context.CLIContext) (authctx.TxContext, error) {
if err := cliCtx.EnsureAccountExists(); err != nil {
return txCtx, err
}
from, err := cliCtx.GetFromAddress()
if err != nil {
return txCtx, err
}
// TODO: (ref #1903) Allow for user supplied account number without
// automatically doing a manual lookup.
if txCtx.AccountNumber == 0 {
accNum, err := cliCtx.GetAccountNumber(from)
if err != nil {
return txCtx, err
}
txCtx = txCtx.WithAccountNumber(accNum)
}
// TODO: (ref #1903) Allow for user supplied account sequence without
// automatically doing a manual lookup.
if txCtx.Sequence == 0 {
accSeq, err := cliCtx.GetAccountSequence(from)
if err != nil {
return txCtx, err
}
txCtx = txCtx.WithSequence(accSeq)
}
return txCtx, nil
}

View File

@ -93,9 +93,10 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
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.paramsKeeper.Getter(), app.RegisterCodespace(slashing.DefaultCodespace))
app.stakeKeeper = app.stakeKeeper.WithValidatorHooks(app.slashingKeeper.ValidatorHooks())
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper.Setter(), 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().

View File

@ -142,7 +142,7 @@ func GaiaAppGenTxNF(cdc *wire.Codec, pk crypto.PubKey, addr sdk.AccAddress, name
gaiaGenTx := GaiaGenTx{
Name: name,
Address: addr,
PubKey: sdk.MustBech32ifyAccPub(pk),
PubKey: sdk.MustBech32ifyConsPub(pk),
}
bz, err = wire.MarshalJSONIndent(cdc, gaiaGenTx)
if err != nil {
@ -192,8 +192,9 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState
// add the validator
if len(genTx.Name) > 0 {
desc := stake.NewDescription(genTx.Name, "", "", "")
validator := stake.NewValidator(genTx.Address,
sdk.MustGetAccPubKeyBech32(genTx.PubKey), desc)
validator := stake.NewValidator(
sdk.ValAddress(genTx.Address), sdk.MustGetConsPubKeyBech32(genTx.PubKey), desc,
)
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply
@ -204,7 +205,7 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (genesisState
// create the self-delegation from the issuedDelShares
delegation := stake.Delegation{
DelegatorAddr: validator.Operator,
DelegatorAddr: sdk.AccAddress(validator.Operator),
ValidatorAddr: validator.Operator,
Shares: issuedDelShares,
Height: 0,

View File

@ -61,10 +61,10 @@ func appStateFn(r *rand.Rand, keys []crypto.PrivKey, accs []sdk.AccAddress) json
// XXX Try different numbers of initially bonded validators
numInitiallyBonded := int64(50)
for i := 0; i < int(numInitiallyBonded); i++ {
validator := stake.NewValidator(accs[i], keys[i].PubKey(), stake.Description{})
validator := stake.NewValidator(sdk.ValAddress(accs[i]), keys[i].PubKey(), stake.Description{})
validator.Tokens = sdk.NewDec(100)
validator.DelegatorShares = sdk.NewDec(100)
delegation := stake.Delegation{accs[i], accs[i], sdk.NewDec(100), 0}
delegation := stake.Delegation{accs[i], sdk.ValAddress(accs[i]), sdk.NewDec(100), 0}
validators = append(validators, validator)
delegations = append(delegations, delegation)
}

View File

@ -58,6 +58,13 @@ func TestGaiaCLISend(t *testing.T) {
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
// Test --dry-run
success := executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo --dry-run", flags, barAddr), app.DefaultKeyPass)
require.True(t, success)
// Check state didn't change
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags))
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
// test autosequencing
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
@ -124,7 +131,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
barCeshPubKey := sdk.MustBech32ifyValPub(barPubKey)
barCeshPubKey := sdk.MustBech32ifyConsPub(barPubKey)
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
@ -148,23 +155,27 @@ func TestGaiaCLICreateValidator(t *testing.T) {
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(1))
// Test --dry-run
success := executeWrite(t, cvStr+" --dry-run", app.DefaultKeyPass)
require.True(t, success)
executeWrite(t, cvStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags))
require.Equal(t, int64(8), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc)
validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags))
require.Equal(t, validator.Operator, barAddr)
validator := executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", sdk.ValAddress(barAddr), flags))
require.Equal(t, validator.Operator, sdk.ValAddress(barAddr))
require.True(sdk.DecEq(t, sdk.NewDec(2), validator.Tokens))
// unbond a single share
unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags)
unbondStr += fmt.Sprintf(" --from=%s", "bar")
unbondStr += fmt.Sprintf(" --validator=%s", barAddr)
unbondStr += fmt.Sprintf(" --validator=%s", sdk.ValAddress(barAddr))
unbondStr += fmt.Sprintf(" --shares-amount=%v", "1")
success := executeWrite(t, unbondStr, app.DefaultKeyPass)
success = executeWrite(t, unbondStr, app.DefaultKeyPass)
require.True(t, success)
tests.WaitForNextNBlocksTM(2, port)
@ -172,7 +183,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
require.Equal(t, int64(9), barAcc.GetCoins().AmountOf("steak").Int64(), "%v", barAcc)
*/
validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", barAddr, flags))
validator = executeGetValidator(t, fmt.Sprintf("gaiacli stake validator %s --output=json %v", sdk.ValAddress(barAddr), flags))
require.Equal(t, "1.0000000000", validator.Tokens.String())
params := executeGetParams(t, fmt.Sprintf("gaiacli stake parameters --output=json %v", flags))
@ -211,6 +222,10 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
spStr += fmt.Sprintf(" --title=%s", "Test")
spStr += fmt.Sprintf(" --description=%s", "test")
// Test --dry-run
success := executeWrite(t, spStr+" --dry-run", app.DefaultKeyPass)
require.True(t, success)
executeWrite(t, spStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port)
@ -352,7 +367,10 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.AccAddress, crypto.PubKe
pk, err := sdk.GetAccPubKeyBech32(ko.PubKey)
require.NoError(t, err)
return ko.Address, pk
accAddr, err := sdk.AccAddressFromBech32(ko.Address)
require.NoError(t, err)
return accAddr, pk
}
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {

View File

@ -710,15 +710,15 @@ definitions:
Address:
type: string
description: bech32 encoded addres
example: cosmosaccaddr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
example: cosmos:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
ValidatorAddress:
type: string
description: bech32 encoded addres
example: cosmosvaladdr:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
example: cosmosval:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
PubKey:
type: string
description: bech32 encoded public key
example: cosmosaccpub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
example: cosmospub:zgnkwr7eyyv643dllwfpdwensmgdtz89yu73zq
ValidatorPubKey:
type: string
description: bech32 encoded public key

View File

@ -17,7 +17,7 @@ Once you have the Cosmos app installed on your Ledger, and the Ledger is accessi
```bash
$ gaiacli keys add {{ .Key.Name }} --ledger
NAME: TYPE: ADDRESS: PUBKEY:
{{ .Key.Name }} ledger cosmosaccaddr1aw64xxr80lwqqdk8u2xhlrkxqaxamkr3e2g943 cosmosaccpub1addwnpepqvhs678gh9aqrjc2tg2vezw86csnvgzqq530ujkunt5tkuc7lhjkz5mj629
{{ .Key.Name }} ledger cosmos1aw64xxr80lwqqdk8u2xhlrkxqaxamkr3e2g943 cosmospub1addwnpepqvhs678gh9aqrjc2tg2vezw86csnvgzqq530ujkunt5tkuc7lhjkz5mj629
```
This key will only be accessible while the Ledger is plugged in and unlocked. To send some coins with this key, run the following:

View File

@ -13,7 +13,7 @@ Now these json files need to be aggregated together via Github, a Google form, p
Place all files on one computer in `$HOME/.gaiad/gen-tx/`
```bash
gaiad init --gen-txs -o --chain=<chain-name>
gaiad init --with-txs -o --chain=<chain-name>
```
This will generate a `genesis.json` in `$HOME/.gaiad/config/genesis.json` distribute this file to all validators on your testnet.

View File

@ -186,7 +186,7 @@ data = {
"text": "I hereby claim I am ABC on Keybase!"
}
cosmosSignBytes(data, "cosmosaccaddr1pvsch6cddahhrn5e8ekw0us50dpnugwnlfngt3")
cosmosSignBytes(data, "cosmos1pvsch6cddahhrn5e8ekw0us50dpnugwnlfngt3")
> "0x7fc4a495473045022100dec81a9820df0102381cdbf7e8b0f1e2cb64c58e0ecda1324543742e0388e41a02200df37905a6505c1b56a404e23b7473d2c0bc5bcda96771d2dda59df6ed2b98f8"
```

View File

@ -71,13 +71,13 @@ This API exposes all functionality needed for key creation, signing and manageme
"account":[
{
"name":"monkey",
"address":"cosmosaccaddr1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd",
"pub_key":"cosmosaccpub1zcjduc3q8s8ha96ry4xc5xvjp9tr9w9p0e5lk5y0rpjs5epsfxs4wmf72x3shvus0t"
"address":"cosmos1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd",
"pub_key":"cosmospub1zcjduc3q8s8ha96ry4xc5xvjp9tr9w9p0e5lk5y0rpjs5epsfxs4wmf72x3shvus0t"
},
{
"name":"test",
"address":"cosmosaccaddr1thlqhjqw78zvcy0ua4ldj9gnazqzavyw4eske2",
"pub_key":"cosmosaccpub1zcjduc3qyx6hlf825jcnj39adpkaxjer95q7yvy25yhfj3dmqy2ctev0rxmse9cuak"
"address":"cosmos1thlqhjqw78zvcy0ua4ldj9gnazqzavyw4eske2",
"pub_key":"cosmospub1zcjduc3qyx6hlf825jcnj39adpkaxjer95q7yvy25yhfj3dmqy2ctev0rxmse9cuak"
}
],
"block_height":5241
@ -125,8 +125,8 @@ Returns on success:
"error":"",
"result":{
"name":"test",
"address":"cosmosaccaddr1thlqhjqw78zvcy0ua4ldj9gnazqzavyw4eske2",
"pub_key":"cosmosaccpub1zcjduc3qyx6hlf825jcnj39adpkaxjer95q7yvy25yhfj3dmqy2ctev0rxmse9cuak"
"address":"cosmos1thlqhjqw78zvcy0ua4ldj9gnazqzavyw4eske2",
"pub_key":"cosmospub1zcjduc3qyx6hlf825jcnj39adpkaxjer95q7yvy25yhfj3dmqy2ctev0rxmse9cuak"
}
}
```
@ -588,7 +588,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te
"description": "string",
// PlainTextProposal supported now. SoftwareUpgradeProposal and other types may be supported soon
"proposal_type": "string",
// A cosmosaccaddr address
// A cosmos address
"proposer": "string",
"initial_deposit": [
{
@ -689,7 +689,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te
"error":"",
"result":{
"amount": {"atom": 150},
"depositer": "cosmosaccaddr1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd",
"depositer": "cosmos1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd",
"proposal-id": 16
}
}
@ -731,12 +731,12 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te
"result": [
{
"proposal-id": 1,
"voter": "cosmosaccaddr1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd",
"voter": "cosmos1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd",
"option": "no_with_veto"
},
{
"proposal-id": 1,
"voter": "cosmosaccaddr1849m9wncrqp6v4tkss6a3j8uzvuv0cp7f75lrq",
"voter": "cosmos1849m9wncrqp6v4tkss6a3j8uzvuv0cp7f75lrq",
"option": "yes"
},
]
@ -761,7 +761,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te
"sequence": 0,
"gas": 0
},
// A cosmosaccaddr address
// A cosmos address
"voter": "string",
// Value of the vote option `Yes`, `No` `Abstain`, `NoWithVeto`
"option": "string",
@ -794,7 +794,7 @@ The GovernanceAPI exposes all functionality needed for casting votes on plain te
"error":"",
"result":{
"proposal-id": 1,
"voter": "cosmosaccaddr1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd",
"voter": "cosmos1fedh326uxqlxs8ph9ej7cf854gz7fd5zlym5pd",
"option": "no_with_veto"
}
}

View File

@ -18,17 +18,21 @@
There are three types of key representations that are used:
- `cosmosaccaddr`
- `cosmos`
- Derived from account keys generated by `gaiacli keys add`
- Used to receive funds
- e.g. `cosmosaccaddr15h6vd5f0wqps26zjlwrc6chah08ryu4hzzdwhc`
- `cosmosaccpub`
- e.g. `cosmos15h6vd5f0wqps26zjlwrc6chah08ryu4hzzdwhc`
* `cosmosval`
* Used to associate a validator to it's operator
* Used to invoke staking commands
* e.g. `cosmosval1carzvgq3e6y3z5kz5y6gxp3wpy3qdrv928vyah`
- `cosmospub`
- Derived from account keys generated by `gaiacli keys add`
- e.g. `cosmosaccpub1zcjduc3q7fu03jnlu2xpl75s2nkt7krm6grh4cc5aqth73v0zwmea25wj2hsqhlqzm`
- `cosmosvalpub`
- e.g. `cosmospub1zcjduc3q7fu03jnlu2xpl75s2nkt7krm6grh4cc5aqth73v0zwmea25wj2hsqhlqzm`
- `cosmosconspub`
- Generated when the node is created with `gaiad init`.
- Get this value with `gaiad tendermint show-validator`
- e.g. `cosmosvalpub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c`
- e.g. `cosmosconspub1zcjduepq0ms2738680y72v44tfyqm3c9ppduku8fs6sr73fx7m666sjztznqzp2emf`
#### Generate Keys
@ -48,6 +52,12 @@ If you check your private keys, you'll now see `<account_name>`:
gaiacli keys show <account_name>
```
View the validator operator's address via:
```shell
gaiacli keys show <account_name> --bech=val
```
You can see all your available keys by typing:
```bash
@ -68,29 +78,31 @@ We strongly recommend _NOT_ using the same passphrase for multiple keys. The Ten
#### Get Tokens
The best way to get tokens is from the [Cosmos Testnet Faucet](https://faucetcosmos.network). If the faucet is not working for you, try asking [#cosmos-validators](https://riot.im/app/#/room/#cosmos-validators:matrix.org). The faucet needs the `cosmosaccaddr` from the account you wish to use for staking.
The best way to get tokens is from the [Cosmos Testnet Faucet](https://faucetcosmos.network). If the faucet is not working for you, try asking [#cosmos-validators](https://riot.im/app/#/room/#cosmos-validators:matrix.org). The faucet needs the `cosmos` from the account you wish to use for staking.
#### Query Account balance
After receiving tokens to your address, you can view your account's balance by typing:
```bash
gaiacli account <account_cosmosaccaddr>
gaiacli account <account_cosmos>
```
::: warning Note
When you query an account balance with zero tokens, you will get this error: `No account with address <account_cosmosaccaddr> was found in the state.` This can also happen if you fund the account before your node has fully synced with the chain. These are both normal.
When you query an account balance with zero tokens, you will get this error: `No account with address <account_cosmos> was found in the state.` This can also happen if you fund the account before your node has fully synced with the chain. These are both normal.
:::
### Send Tokens
The following command could be used to send coins from one account to another:
```bash
gaiacli send \
--amount=10faucetToken \
--chain-id=<chain_id> \
--name=<key_name> \
--to=<destination_cosmosaccaddr>
--to=<destination_cosmos>
```
::: warning Note
@ -100,20 +112,31 @@ The `--amount` flag accepts the format `--amount=<value|coin_name>`.
::: tip Note
You may want to cap the maximum gas that can be consumed by the transaction via the `--gas` flag.
If set to 0, the gas limit will be automatically estimated.
Gas estimate might be inaccurate as state changes could occur in between the end of the simulation and the actual execution of a transaction, thus an adjustment is applied on top of the original estimate in order to ensure the transaction is broadcasted successfully. The adjustment can be controlled via the `--gas-adjustment` flag, whose default value is 1.2.
Gas estimate might be inaccurate as state changes could occur in between the end of the simulation and the actual execution of a transaction, thus an adjustment is applied on top of the original estimate in order to ensure the transaction is broadcasted successfully. The adjustment can be controlled via the `--gas-adjustment` flag, whose default value is 1.0.
:::
Now, view the updated balances of the origin and destination accounts:
```bash
gaiacli account <account_cosmosaccaddr>
gaiacli account <destination_cosmosaccaddr>
gaiacli account <account_cosmos>
gaiacli account <destination_cosmos>
```
You can also check your balance at a given block by using the `--block` flag:
```bash
gaiacli account <account_cosmosaccaddr> --block=<block_height>
gaiacli account <account_cosmos> --block=<block_height>
```
You can simulate a transaction without actually broadcasting it by appending the `--dry-run` flag to the command line:
```bash
gaiacli send \
--amount=10faucetToken \
--chain-id=<chain_id> \
--name=<key_name> \
--to=<destination_cosmosaccaddr> \
--dry-run
```
### Staking
@ -137,7 +160,7 @@ gaiacli stake validators
If you want to get the information of a single validator you can check it with:
```bash
gaiacli stake validator <account_cosmosaccaddr>
gaiacli stake validator <account_cosmosval>
```
#### Bond Tokens
@ -164,14 +187,14 @@ Once submitted a delegation to a validator, you can see it's information by usin
```bash
gaiacli stake delegation \
--address-delegator=<account_cosmosaccaddr> \
--address-validator=$(gaiad tendermint show-validator)
--address-delegator=<account_cosmos> \
--validator=<account_cosmosval>
```
Or if you want to check all your current delegations with disctinct validators:
```bash
gaiacli stake delegations <account_cosmosaccaddr>
gaiacli stake delegations <account_cosmos>
```
You can also get previous delegation(s) status by adding the `--height` flag.
@ -182,7 +205,7 @@ If for any reason the validator misbehaves, or you just want to unbond a certain
```bash
gaiacli stake unbond begin \
--address-validator=$(gaiad tendermint show-validator) \
--validator=<account_cosmosval> \
--shares-percent=100 \
--from=<key_name> \
--chain-id=<chain_id>
@ -192,7 +215,7 @@ Later you must complete the unbonding process by using the `gaiacli stake unbond
```bash
gaiacli stake unbond complete \
--address-validator=$(gaiad tendermint show-validator) \
--validator=<account_cosmosval> \
--from=<key_name> \
--chain-id=<chain_id>
```
@ -203,14 +226,14 @@ Once you begin an unbonding-delegation, you can see it's information by using th
```bash
gaiacli stake unbonding-delegation \
--address-delegator=<account_cosmosaccaddr> \
--address-validator=$(gaiad tendermint show-validator) \
--address-delegator=<account_cosmos> \
--validator=<account_cosmosval> \
```
Or if you want to check all your current unbonding-delegations with disctinct validators:
```bash
gaiacli stake unbonding-delegations <account_cosmosaccaddr>
gaiacli stake unbonding-delegations <account_cosmos>
```
You can also get previous unbonding-delegation(s) status by adding the `--height` flag.
@ -221,8 +244,8 @@ A redelegation is a type delegation that allows you to bond illiquid tokens from
```bash
gaiacli stake redelegate begin \
--address-validator-source=$(gaiad tendermint show-validator) \
--address-validator-dest=<account_cosmosaccaddr> \
--address-validator-source=<account_cosmosval> \
--address-validator-dest=<account_cosmosval> \
--shares-percent=50 \
--from=<key_name> \
--chain-id=<chain_id>
@ -234,7 +257,7 @@ Later you must complete the redelegation process by using the `gaiacli stake red
```bash
gaiacli stake unbond complete \
--address-validator=$(gaiad tendermint show-validator) \
--validator=<account_cosmosval> \
--from=<key_name> \
--chain-id=<chain_id>
```
@ -245,15 +268,15 @@ Once you begin an redelegation, you can see it's information by using the follow
```bash
gaiacli stake redelegation \
--address-delegator=<account_cosmosaccaddr> \
--address-validator-source=$(gaiad tendermint show-validator) \
--address-validator-dest=<account_cosmosaccaddr> \
--address-delegator=<account_cosmos> \
--address-validator-source=<account_cosmosval> \
--address-validator-dest=<account_cosmosval> \
```
Or if you want to check all your current unbonding-delegations with disctinct validators:
```bash
gaiacli stake redelegations <account_cosmosaccaddr>
gaiacli stake redelegations <account_cosmos>
```
You can also get previous redelegation(s) status by adding the `--height` flag.
@ -286,7 +309,7 @@ gaiacli gov submit-proposal \
--title=<title> \
--description=<description> \
--type=<Text/ParameterChange/SoftwareUpgrade> \
--proposer=<account_cosmosaccaddr> \
--proposer=<account_cosmos> \
--deposit=<40steak> \
--from=<name> \
--chain-id=<chain_id>
@ -316,7 +339,7 @@ In order for a proposal to be broadcasted to the network, the amount deposited m
```bash
gaiacli gov deposit \
--proposal-id=<proposal_id> \
--depositer=<account_cosmosaccaddr> \
--depositer=<account_cosmos> \
--deposit=<200steak> \
--from=<name> \
--chain-id=<chain_id>
@ -331,7 +354,7 @@ After a proposal's deposit reaches the `MinDeposit` value, the voting period ope
```bash
gaiacli gov vote \
--proposal-id=<proposal_id> \
--voter=<account_cosmosaccaddr> \
--voter=<account_cosmos> \
--option=<Yes/No/NoWithVeto/Abstain> \
--from=<name> \
--chain-id=<chain_id>
@ -344,7 +367,7 @@ Check the vote with the option you just submitted:
```bash
gaiacli gov query-vote \
--proposal-id=<proposal_id> \
--voter=<account_cosmosaccaddr>
--voter=<account_cosmos>
```
#### Query Parameters

View File

@ -1,25 +1,24 @@
# Bech32 on Cosmos
The Cosmos network prefers to use the Bech32 address format whereever users must handle binary data. Bech32 encoding provides robust integrity checks on data and the human readable part(HRP) provides contextual hints that can assist UI developers with providing informative error messages.
The Cosmos network prefers to use the Bech32 address format wherever users must handle binary data. Bech32 encoding provides robust integrity checks on data and the human readable part(HRP) provides contextual hints that can assist UI developers with providing informative error messages.
In the Cosmos network, keys and addresses may refer to a number of different roles in the network like accounts, validators etc.
## HRP table
## HRP table
| HRP | Definition |
| ------------- |:-------------:|
| `cosmos` | Cosmos Account Address |
| `cosmospub` | Cosmos Account Public Key |
| `cosmosval` | Cosmos Validator Consensus Address |
| `cosmosvalpub`| Cosmos Validator Consensus Public Key|
| HRP | Definition |
|---------------|--------------------------------------|
| cosmos | Cosmos Account Address |
| cosmospub | Cosmos Account Public Key |
| cosmoscons | Cosmos Consensus Address |
| cosmosconspub | Cosmos Consensus Public Key |
| cosmosval | Cosmos Validator Operator Address |
| cosmosvalpub | Cosmos Validator Operator Public Key |
## Encoding
While all user facing interfaces to Cosmos software should exposed bech32 interfaces, many internal interfaces encode binary value in hex or base64 encoded form.
While all user facing interfaces to Cosmos software should exposed Bech32 interfaces, many internal interfaces encode binary value in hex or base64 encoded form.
To covert between other binary reprsentation of addresses and keys, it is important to first apply the Amino enocoding process before bech32 encoding.
To covert between other binary representation of addresses and keys, it is important to first apply the Amino encoding process before bech32 encoding.
A complete implementation of the Amino serialization format is unncessary in most cases. Simply prepending bytes from this [table](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography) to the bytestring payload before bech32 encoding will sufficient for compatible representation.
 
A complete implementation of the Amino serialization format is unnecessary in most cases. Simply prepending bytes from this [table](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/encoding.md#public-key-cryptography) to the byte string payload before bech32 encoding will sufficient for compatible representation.

View File

@ -39,3 +39,14 @@ Sentry Nodes should edit their config.toml:
# Comma separated list of peer IDs to keep private (will not be gossiped to other peers)
private_peer_ids = "ipaddress of validator nodes"
```
## Environment Variables
By default, uppercase environment variables with the following prefixes will replace lowercase command-line flags:
- `GA` (for Gaia flags)
- `TM` (for Tendermint flags)
- `BC` (for democli or basecli flags)
For example, the environment variable `GA_CHAIN_ID` will map to the command line flag `--chain-id`. Note that while explicit command-line flags will take precedence over environment variables, environment variables will take precedence over any of your configuration files. For this reason, it's imperative that you lock down your environment such that any critical parameters are defined as flags on the CLI or prevent modification of any environment variables.

View File

@ -77,13 +77,14 @@ We view testnet participation as a great way to signal to the community that you
In short, there are two types of keys:
- **Tendermint Key**: This is a unique key used to sign block hashes. It is associated with a public key `cosmosvalpub`.
+ Generated when the node is created with gaiad init.
+ Get this value with gaiad tendermint show_validator
+M e.g. cosmosvalpub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c
- **Application keys**: These keys are created from the application and used to sign transactions. As a validator, you will probably use one key to sign staking-related transactions, and another key to sign governance-related transactions. Application keys are associated with a public key `cosmosaccpub` and an address `cosmosaccaddr`. Both are derived from account keys generated by `gaiacli keys add`.
* **Tendermint Key**: This is a unique key used to sign block hashes. It is associated with a public key `cosmosconspub`.
* Generated when the node is created with gaiad init.
* Get this value with `gaiad tendermint show-validator`
e.g. `cosmosconspub1zcjduc3qcyj09qc03elte23zwshdx92jm6ce88fgc90rtqhjx8v0608qh5ssp0w94c`
* **Application keys**: These keys are created from the application and used to sign transactions. As a validator, you will probably use one key to sign staking-related transactions, and another key to sign governance-related transactions. Application keys are associated with a public key `cosmospub` and an address `cosmos`. Both are derived from account keys generated by `gaiacli keys add`.
* Note: A validator's operator key is directly tied to an application key, but
uses reserved prefixes solely for this purpose: `cosmosval` and `cosmosvalpub`
### What are the different states a validator can be in?

View File

@ -16,7 +16,7 @@ If you want to become a validator for the Hub's `mainnet`, you should [research
### Create Your Validator
Your `cosmosvalpub` can be used to create a new validator by staking tokens. You can find your validator pubkey by running:
Your `cosmosconspub` can be used to create a new validator by staking tokens. You can find your validator pubkey by running:
```bash
gaiad tendermint show-validator
@ -32,7 +32,7 @@ Don't use more `steak` thank you have! You can always get more by using the [Fau
gaiacli stake create-validator \
--amount=5steak \
--pubkey=$(gaiad tendermint show-validator) \
--address-validator=<account_cosmosaccaddr>
--address-validator=<account_cosmosval>
--moniker="choose a moniker" \
--chain-id=<chain_id> \
--name=<key_name>
@ -46,7 +46,7 @@ The `--identity` can be used as to verify identity with systems like Keybase or
```bash
gaiacli stake edit-validator
--validator=<account_cosmosaccaddr>
--validator=<account_cosmos>
--moniker="choose a moniker" \
--website="https://cosmos.network" \
--identity=6A0D65E29A4CBC8E
@ -60,7 +60,7 @@ gaiacli stake edit-validator
View the validator's information with this command:
```bash
gaiacli stake validator <account_cosmosaccaddr>
gaiacli stake validator <account_cosmos>
```
### Track Validator Signing Information
@ -80,7 +80,7 @@ When a validator is "jailed" for downtime, you must submit an `Unjail` transacti
gaiacli stake unjail \
--from=<key_name> \
--chain-id=<chain_id>
--validator=<account_cosmosaccaddr> \
--validator=<account_cosmosval> \
--chain-id=gaia-6002
```
@ -110,10 +110,10 @@ Here's how you can return the voting power back to your validator. First, if `ga
gaiad start
```
Wait for your full node to catch up to the latest block. Next, run the following command. Note that `<cosmosaccaddr>` is the address of your validator account, and `<name>` is the name of the validator account. You can find this info by running `gaiacli keys list`.
Wait for your full node to catch up to the latest block. Next, run the following command. Note that `<cosmos>` is the address of your validator account, and `<name>` is the name of the validator account. You can find this info by running `gaiacli keys list`.
```bash
gaiacli stake unjail <cosmosaccaddr> --chain-id=<chain_id> --name=<name>
gaiacli stake unjail <cosmos> --chain-id=<chain_id> --name=<name>
```
::: danger Warning

View File

@ -103,10 +103,10 @@ basecli keys list
You should now see alice, bob and charlie's account all show up.
```
NAME: ADDRESS: PUBKEY:
alice cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f cosmosaccpub1addwnpepq0w037u5g7y7lvdvsred2dehg90j84k0weyss5ynysf0nnnax74agrsxns6
bob cosmosaccaddr18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz cosmosaccpub1addwnpepqwe97n8lryxrzvamrvjfj24jys3uzf8wndfvqa2l7mh5nsv4jrvdznvyeg6
charlie cosmosaccaddr13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q cosmosaccpub1addwnpepqdmtxv35rrmv2dvcr3yhfyxj7dzrd4z4rnhmclksq4g55a4wpl54clvx33l
NAME: ADDRESS: PUBKEY:
alice cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f cosmospub1addwnpepq0w037u5g7y7lvdvsred2dehg90j84k0weyss5ynysf0nnnax74agrsxns6
bob cosmos18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz cosmospub1addwnpepqwe97n8lryxrzvamrvjfj24jys3uzf8wndfvqa2l7mh5nsv4jrvdznvyeg6
charlie cosmos13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q cosmospub1addwnpepqdmtxv35rrmv2dvcr3yhfyxj7dzrd4z4rnhmclksq4g55a4wpl54clvx33l
```
@ -115,15 +115,15 @@ charlie cosmosaccaddr13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q cosmosaccpub1addwnp
Lets send bob and charlie some tokens. First, lets query alice's account so we can see what kind of tokens she has:
```
basecli account cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f
basecli account cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f
```
Where `cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f` is alice's address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some!
Where `cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f` is alice's address we got from running `basecli keys list`. You should see a large amount of "mycoin" there. If you search for bob's or charlie's address, the command will fail, because they haven't been added into the blockchain database yet since they have no coins. We need to send them some!
The following command will send coins from alice, to bob:
```
basecli send --from=alice --amount=10000mycoin --to=cosmosaccaddr18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz
basecli send --from=alice --amount=10000mycoin --to=cosmos18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz
--sequence=0 --chain-id=test-chain-AE4XQo
```
@ -136,13 +136,13 @@ Flag Descriptions:
Now if we check bobs account, it should have `10000 mycoin`. You can do so by running :
```
basecli account cosmosaccaddr18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz
basecli account cosmos18se8tz6kwwfga6k2yjsu7n64e9z52nen29rhzz
```
Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail:
```
basecli send --from=bob --amount=5000mycoin --to=cosmosaccaddr13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q
basecli send --from=bob --amount=5000mycoin --to=cosmos13wq5mklhn03ljpd4dkph5rflk5a3ssma2ag07q
--sequence=0 --chain-id=test-chain-AE4XQo
```
@ -151,7 +151,7 @@ Note how we use the ``--from`` flag to select a different account to send from.
Lets now try to send from bob back to alice:
```
basecli send --from=bob --amount=3000mycoin --to=cosmosaccaddr1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f
basecli send --from=bob --amount=3000mycoin --to=cosmos1khygs0qh7gz3p4m39u00mjhvgvc2dcpxhsuh5f
--sequence=1 --chain-id=test-chain-AE4XQo
```

View File

@ -9,7 +9,7 @@ import (
// Validator implements sdk.Validator
type Validator struct {
Address sdk.AccAddress
Address sdk.ValAddress
Power sdk.Dec
}
@ -19,7 +19,7 @@ func (v Validator) GetStatus() sdk.BondStatus {
}
// Implements sdk.Validator
func (v Validator) GetOperator() sdk.AccAddress {
func (v Validator) GetOperator() sdk.ValAddress {
return v.Address
}
@ -78,9 +78,9 @@ func (vs *ValidatorSet) IterateValidatorsBonded(ctx sdk.Context, fn func(index i
}
// Validator implements sdk.ValidatorSet
func (vs *ValidatorSet) Validator(ctx sdk.Context, addr sdk.AccAddress) sdk.Validator {
func (vs *ValidatorSet) Validator(ctx sdk.Context, addr sdk.ValAddress) sdk.Validator {
for _, val := range vs.Validators {
if bytes.Equal(val.Address, addr) {
if bytes.Equal(val.Address.Bytes(), addr.Bytes()) {
return val
}
}
@ -135,3 +135,8 @@ func (vs *ValidatorSet) Jail(ctx sdk.Context, pubkey crypto.PubKey) {
func (vs *ValidatorSet) Unjail(ctx sdk.Context, pubkey crypto.PubKey) {
panic("not implemented")
}
// Implements sdk.ValidatorSet
func (vs *ValidatorSet) Delegation(ctx sdk.Context, addrDel sdk.AccAddress, addrVal sdk.ValAddress) sdk.Delegation {
panic("not implemented")
}

View File

@ -37,7 +37,7 @@ func NewValidatorSet(cdc *wire.Codec, store sdk.KVStore, valset sdk.ValidatorSet
}
// Implements sdk.ValidatorSet
func (valset ValidatorSet) Validator(ctx sdk.Context, addr sdk.AccAddress) (res sdk.Validator) {
func (valset ValidatorSet) Validator(ctx sdk.Context, addr sdk.ValAddress) (res sdk.Validator) {
base := valset.store.Get(GetBaseKey(addr))
res = valset.ValidatorSet.Validator(ctx, base)
if res == nil {
@ -46,23 +46,23 @@ func (valset ValidatorSet) Validator(ctx sdk.Context, addr sdk.AccAddress) (res
return
}
// GetBaseKey :: sdk.AccAddress -> sdk.AccAddress
func GetBaseKey(addr sdk.AccAddress) []byte {
// GetBaseKey :: sdk.ValAddress -> sdk.ValAddress
func GetBaseKey(addr sdk.ValAddress) []byte {
return append([]byte{0x00}, addr...)
}
// GetAssocPrefix :: sdk.AccAddress -> (sdk.AccAddress -> byte)
func GetAssocPrefix(base sdk.AccAddress) []byte {
// GetAssocPrefix :: sdk.ValAddress -> (sdk.ValAddress -> byte)
func GetAssocPrefix(base sdk.ValAddress) []byte {
return append([]byte{0x01}, base...)
}
// GetAssocKey :: (sdk.AccAddress, sdk.AccAddress) -> byte
func GetAssocKey(base sdk.AccAddress, assoc sdk.AccAddress) []byte {
// GetAssocKey :: (sdk.ValAddress, sdk.ValAddress) -> byte
func GetAssocKey(base sdk.ValAddress, assoc sdk.ValAddress) []byte {
return append(append([]byte{0x01}, base...), assoc...)
}
// Associate associates new address with validator address
func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.AccAddress, assoc sdk.AccAddress) bool {
func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
return false
}
@ -76,7 +76,7 @@ func (valset ValidatorSet) Associate(ctx sdk.Context, base sdk.AccAddress, assoc
}
// Dissociate removes association between addresses
func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.AccAddress, assoc sdk.AccAddress) bool {
func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.ValAddress, assoc sdk.ValAddress) bool {
if len(base) != valset.addrLen || len(assoc) != valset.addrLen {
return false
}
@ -90,8 +90,8 @@ func (valset ValidatorSet) Dissociate(ctx sdk.Context, base sdk.AccAddress, asso
}
// Associations returns all associated addresses with a validator
func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.AccAddress) (res []sdk.AccAddress) {
res = make([]sdk.AccAddress, valset.maxAssoc)
func (valset ValidatorSet) Associations(ctx sdk.Context, base sdk.ValAddress) (res []sdk.ValAddress) {
res = make([]sdk.ValAddress, valset.maxAssoc)
iter := sdk.KVStorePrefixIterator(valset.store, GetAssocPrefix(base))
defer iter.Close()
i := 0

View File

@ -88,17 +88,17 @@ func TestMsgQuiz(t *testing.T) {
require.Equal(t, acc1, res1)
// Set the trend, submit a really cool quiz and check for reward
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []int64{0}, []int64{0}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{1}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg1}, []int64{0}, []int64{0}, true, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{1}, true, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{2}, false, priv1) // result without reward
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{2}, false, false, priv1) // result without reward
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(69)}})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{3}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{3}, true, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(138)}})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg2}, []int64{0}, []int64{4}, true, priv1) // reset the trend
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{5}, false, priv1) // the same answer will nolonger do!
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg2}, []int64{0}, []int64{4}, true, true, priv1) // reset the trend
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg1}, []int64{0}, []int64{5}, false, false, priv1) // the same answer will nolonger do!
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"icecold", sdk.NewInt(138)}})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{6}, true, priv1) // earlier answer now relevant again
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{quizMsg2}, []int64{0}, []int64{6}, true, true, priv1) // earlier answer now relevant again
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"badvibesonly", sdk.NewInt(69)}, {"icecold", sdk.NewInt(138)}})
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg3}, []int64{0}, []int64{7}, false, priv1) // expect to fail to set the trend to something which is not cool
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{setTrendMsg3}, []int64{0}, []int64{7}, false, false, priv1) // expect to fail to set the trend to something which is not cool
}

View File

@ -68,8 +68,8 @@ func (keeper Keeper) Handle(h Handler, ctx sdk.Context, o Msg, codespace sdk.Cod
}
info.LastSigned = ctx.BlockHeight()
// Check the signer is a validater
val := valset.Validator(ctx, signer)
// check the signer is a validator
val := valset.Validator(ctx, sdk.ValAddress(signer))
if val == nil {
return ErrNotValidator(codespace, signer).Result()
}

View File

@ -74,13 +74,13 @@ func TestMsgMine(t *testing.T) {
// Mine and check for reward
mineMsg1 := GenerateMsgMine(addr1, 1, 2)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []int64{0}, []int64{0}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg1}, []int64{0}, []int64{0}, true, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(1)}})
// Mine again and check for reward
mineMsg2 := GenerateMsgMine(addr1, 2, 3)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, true, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}})
// Mine again - should be invalid
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, false, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{mineMsg2}, []int64{0}, []int64{1}, false, false, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{{"pow", sdk.NewInt(2)}})
}

View File

@ -55,14 +55,14 @@ func TestMsgMineString(t *testing.T) {
addr := sdk.AccAddress([]byte("sender"))
msg := MsgMine{addr, 0, 0, 0, []byte("abc")}
res := msg.String()
require.Equal(t, res, "MsgMine{Sender: cosmosaccaddr1wdjkuer9wg4wml9c, Difficulty: 0, Count: 0, Nonce: 0, Proof: abc}")
require.Equal(t, res, "MsgMine{Sender: cosmos1wdjkuer9wgh76ts6, Difficulty: 0, Count: 0, Nonce: 0, Proof: abc}")
}
func TestMsgMineGetSignBytes(t *testing.T) {
addr := sdk.AccAddress([]byte("sender"))
msg := MsgMine{addr, 1, 1, 1, []byte("abc")}
res := msg.GetSignBytes()
require.Equal(t, string(res), `{"count":1,"difficulty":1,"nonce":1,"proof":"YWJj","sender":"cosmosaccaddr1wdjkuer9wg4wml9c"}`)
require.Equal(t, string(res), `{"count":1,"difficulty":1,"nonce":1,"proof":"YWJj","sender":"cosmos1wdjkuer9wgh76ts6"}`)
}
func TestMsgMineGetSigners(t *testing.T) {

View File

@ -70,7 +70,7 @@
unarchive: src=files/gen-tx.tgz dest=/home/gaiad/.gaiad/config/gentx owner=gaiad
- name: Generate genesis.json
command: "/usr/bin/gaiad init --gen-txs --name=node{{nodeid.stdout_lines[0]}} --chain-id={{TESTNET_NAME}}"
command: "/usr/bin/gaiad init --with-txs --name=node{{nodeid.stdout_lines[0]}} --chain-id={{TESTNET_NAME}}"
become: yes
become_user: gaiad
args:

View File

@ -31,7 +31,7 @@ api_key: {{DD_API_KEY}}
force_tls_12: yes
# Force the hostname to whatever you want. (default: auto-detected)
hostname: {{inventory_hostname}}
hostname: {{inventory_hostname | replace ("_","-")}}
# Make the agent use "hostname -f" on unix-based systems as a last resort
# way of determining the hostname instead of Golang "os.Hostname()"

View File

@ -41,7 +41,7 @@ var (
//parameter names, init command
var (
FlagOverwrite = "overwrite"
FlagGenTxs = "gen-txs"
FlagWithTxs = "with-txs"
FlagIP = "ip"
FlagChainID = "chain-id"
)
@ -169,7 +169,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
config.SetRoot(viper.GetString(tmcli.HomeFlag))
initConfig := InitConfig{
viper.GetString(FlagChainID),
viper.GetBool(FlagGenTxs),
viper.GetBool(FlagWithTxs),
filepath.Join(config.RootDir, "config", "gentx"),
viper.GetBool(FlagOverwrite),
}
@ -198,7 +198,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
}
cmd.Flags().BoolP(FlagOverwrite, "o", false, "overwrite the genesis.json file")
cmd.Flags().String(FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
cmd.Flags().Bool(FlagGenTxs, false, "apply genesis transactions from [--home]/config/gentx/")
cmd.Flags().Bool(FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/")
cmd.Flags().AddFlagSet(appInit.FlagsAppGenState)
cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided
cmd.AddCommand(GenTxCmd(ctx, cdc, appInit))

View File

@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tendermint/p2p"
@ -32,7 +33,6 @@ func ShowNodeIDCmd(ctx *Context) *cobra.Command {
// ShowValidator - ported from Tendermint, show this node's validator info
func ShowValidatorCmd(ctx *Context) *cobra.Command {
flagJSON := "json"
cmd := cobra.Command{
Use: "show-validator",
Short: "Show this node's tendermint validator info",
@ -42,29 +42,57 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
privValidator := pvm.LoadOrGenFilePV(cfg.PrivValidatorFile())
valPubKey := privValidator.PubKey
if viper.GetBool(flagJSON) {
cdc := wire.NewCodec()
wire.RegisterCrypto(cdc)
pubKeyJSONBytes, err := cdc.MarshalJSON(valPubKey)
if err != nil {
return err
}
fmt.Println(string(pubKeyJSONBytes))
return nil
if viper.GetBool(client.FlagJson) {
return printlnJSON(valPubKey)
}
pubkey, err := sdk.Bech32ifyValPub(valPubKey)
pubkey, err := sdk.Bech32ifyConsPub(valPubKey)
if err != nil {
return err
}
fmt.Println(pubkey)
return nil
},
}
cmd.Flags().Bool(flagJSON, false, "get machine parseable output")
cmd.Flags().Bool(client.FlagJson, false, "get machine parseable output")
return &cmd
}
// ShowAddressCmd - show this node's validator address
func ShowAddressCmd(ctx *Context) *cobra.Command {
cmd := &cobra.Command{
Use: "show-address",
Short: "Shows this node's tendermint validator address",
RunE: func(cmd *cobra.Command, args []string) error {
cfg := ctx.Config
privValidator := pvm.LoadOrGenFilePV(cfg.PrivValidatorFile())
valAddr := (sdk.ValAddress)(privValidator.Address)
if viper.GetBool(client.FlagJson) {
return printlnJSON(valAddr)
}
fmt.Println(valAddr.String())
return nil
},
}
cmd.Flags().Bool(client.FlagJson, false, "get machine parseable output")
return cmd
}
func printlnJSON(v interface{}) error {
cdc := wire.NewCodec()
wire.RegisterCrypto(cdc)
marshalled, err := cdc.MarshalJSON(v)
if err != nil {
return err
}
fmt.Println(string(marshalled))
return nil
}
// UnsafeResetAllCmd - extension of the tendermint command, resets initialization
func UnsafeResetAllCmd(ctx *Context) *cobra.Command {
return &cobra.Command{

View File

@ -112,6 +112,7 @@ func AddCommands(
tendermintCmd.AddCommand(
ShowNodeIDCmd(ctx),
ShowValidatorCmd(ctx),
ShowAddressCmd(ctx),
)
rootCmd.AddCommand(

91
store/multistoreproof.go Normal file
View File

@ -0,0 +1,91 @@
package store
import (
"bytes"
"github.com/pkg/errors"
"github.com/tendermint/iavl"
cmn "github.com/tendermint/tendermint/libs/common"
)
// MultiStoreProof defines a collection of store proofs in a multi-store
type MultiStoreProof struct {
StoreInfos []storeInfo
StoreName string
RangeProof iavl.RangeProof
}
// buildMultiStoreProof build MultiStoreProof based on iavl proof and storeInfos
func buildMultiStoreProof(iavlProof []byte, storeName string, storeInfos []storeInfo) []byte {
var rangeProof iavl.RangeProof
cdc.MustUnmarshalBinary(iavlProof, &rangeProof)
msp := MultiStoreProof{
StoreInfos: storeInfos,
StoreName: storeName,
RangeProof: rangeProof,
}
proof := cdc.MustMarshalBinary(msp)
return proof
}
// VerifyMultiStoreCommitInfo verify multiStoreCommitInfo against appHash
func VerifyMultiStoreCommitInfo(storeName string, storeInfos []storeInfo, appHash []byte) ([]byte, error) {
var substoreCommitHash []byte
var height int64
for _, storeInfo := range storeInfos {
if storeInfo.Name == storeName {
substoreCommitHash = storeInfo.Core.CommitID.Hash
height = storeInfo.Core.CommitID.Version
}
}
if len(substoreCommitHash) == 0 {
return nil, cmn.NewError("failed to get substore root commit hash by store name")
}
ci := commitInfo{
Version: height,
StoreInfos: storeInfos,
}
if !bytes.Equal(appHash, ci.Hash()) {
return nil, cmn.NewError("the merkle root of multiStoreCommitInfo doesn't equal to appHash")
}
return substoreCommitHash, nil
}
// VerifyRangeProof verify iavl RangeProof
func VerifyRangeProof(key, value []byte, substoreCommitHash []byte, rangeProof *iavl.RangeProof) error {
// verify the proof to ensure data integrity.
err := rangeProof.Verify(substoreCommitHash)
if err != nil {
return errors.Wrap(err, "proof root hash doesn't equal to substore commit root hash")
}
if len(value) != 0 {
// verify existence proof
err = rangeProof.VerifyItem(key, value)
if err != nil {
return errors.Wrap(err, "failed in existence verification")
}
} else {
// verify absence proof
err = rangeProof.VerifyAbsence(key)
if err != nil {
return errors.Wrap(err, "failed in absence verification")
}
}
return nil
}
// RequireProof return whether proof is require for the subpath
func RequireProof(subpath string) bool {
// Currently, only when query subpath is "/store" or "/key", will proof be included in response.
// If there are some changes about proof building in iavlstore.go, we must change code here to keep consistency with iavlstore.go:212
if subpath == "/store" || subpath == "/key" {
return true
}
return false
}

View File

@ -0,0 +1,120 @@
package store
import (
"encoding/hex"
"github.com/stretchr/testify/assert"
"github.com/tendermint/iavl"
cmn "github.com/tendermint/tendermint/libs/common"
"testing"
)
func TestVerifyMultiStoreCommitInfo(t *testing.T) {
appHash, _ := hex.DecodeString("ebf3c1fb724d3458023c8fefef7b33add2fc1e84")
substoreRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828")
storeName := "acc"
var storeInfos []storeInfo
gocRootHash, _ := hex.DecodeString("62c171bb022e47d1f745608ff749e676dbd25f78")
storeInfos = append(storeInfos, storeInfo{
Name: "gov",
Core: storeCore{
CommitID: CommitID{
Version: 689,
Hash: gocRootHash,
},
},
})
storeInfos = append(storeInfos, storeInfo{
Name: "main",
Core: storeCore{
CommitID: CommitID{
Version: 689,
Hash: nil,
},
},
})
accRootHash, _ := hex.DecodeString("ea5d468431015c2cd6295e9a0bb1fc0e49033828")
storeInfos = append(storeInfos, storeInfo{
Name: "acc",
Core: storeCore{
CommitID: CommitID{
Version: 689,
Hash: accRootHash,
},
},
})
storeInfos = append(storeInfos, storeInfo{
Name: "ibc",
Core: storeCore{
CommitID: CommitID{
Version: 689,
Hash: nil,
},
},
})
stakeRootHash, _ := hex.DecodeString("987d1d27b8771d93aa3691262f661d2c85af7ca4")
storeInfos = append(storeInfos, storeInfo{
Name: "stake",
Core: storeCore{
CommitID: CommitID{
Version: 689,
Hash: stakeRootHash,
},
},
})
slashingRootHash, _ := hex.DecodeString("388ee6e5b11f367069beb1eefd553491afe9d73e")
storeInfos = append(storeInfos, storeInfo{
Name: "slashing",
Core: storeCore{
CommitID: CommitID{
Version: 689,
Hash: slashingRootHash,
},
},
})
commitHash, err := VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash)
assert.Nil(t, err)
assert.Equal(t, commitHash, substoreRootHash)
appHash, _ = hex.DecodeString("29de216bf5e2531c688de36caaf024cd3bb09ee3")
_, err = VerifyMultiStoreCommitInfo(storeName, storeInfos, appHash)
assert.Error(t, err, "appHash doesn't match to the merkle root of multiStoreCommitInfo")
}
func TestVerifyRangeProof(t *testing.T) {
tree := iavl.NewTree(nil, 0)
rand := cmn.NewRand()
rand.Seed(0) // for determinism
for _, ikey := range []byte{0x11, 0x32, 0x50, 0x72, 0x99} {
key := []byte{ikey}
tree.Set(key, []byte(rand.Str(8)))
}
root := tree.Hash()
key := []byte{0x32}
val, proof, err := tree.GetWithProof(key)
assert.Nil(t, err)
assert.NotEmpty(t, val)
assert.NotEmpty(t, proof)
err = VerifyRangeProof(key, val, root, proof)
assert.Nil(t, err)
key = []byte{0x40}
val, proof, err = tree.GetWithProof(key)
assert.Nil(t, err)
assert.Empty(t, val)
assert.NotEmpty(t, proof)
err = VerifyRangeProof(key, val, root, proof)
assert.Nil(t, err)
}

View File

@ -291,6 +291,18 @@ func (rs *rootMultiStore) Query(req abci.RequestQuery) abci.ResponseQuery {
// trim the path and make the query
req.Path = subpath
res := queryable.Query(req)
if !req.Prove || !RequireProof(subpath) {
return res
}
commitInfo, errMsg := getCommitInfo(rs.db, res.Height)
if errMsg != nil {
return sdk.ErrInternal(errMsg.Error()).QueryResult()
}
res.Proof = buildMultiStoreProof(res.Proof, storeName, commitInfo.StoreInfos)
return res
}

View File

@ -10,6 +10,7 @@ import (
tmclient "github.com/tendermint/tendermint/rpc/client"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
"strings"
)
// Wait for the next tendermint block from the Tendermint RPC
@ -185,6 +186,17 @@ func WaitForRPC(laddr string) {
}
}
// ExtractPortFromAddress extract port from listenAddress
// The listenAddress must be some strings like tcp://0.0.0.0:12345
func ExtractPortFromAddress(listenAddress string) string {
stringList := strings.Split(listenAddress, ":")
length := len(stringList)
if length != 3 {
panic(fmt.Errorf("expected listen address: tcp://0.0.0.0:12345, got %s", listenAddress))
}
return stringList[2]
}
var cdc = amino.NewCodec()
func init() {

View File

@ -13,251 +13,422 @@ import (
"github.com/tendermint/tendermint/libs/bech32"
)
// Bech32 prefixes
const (
// expected address length
// AddrLen defines a valid address length
AddrLen = 20
// Bech32 prefixes
Bech32PrefixAccAddr = "cosmosaccaddr"
Bech32PrefixAccPub = "cosmosaccpub"
Bech32PrefixValAddr = "cosmosvaladdr"
Bech32PrefixValPub = "cosmosvalpub"
// Bech32PrefixAccAddr defines the Bech32 prefix of an account's address
Bech32PrefixAccAddr = "cosmos"
// Bech32PrefixAccPub defines the Bech32 prefix of an account's public key
Bech32PrefixAccPub = "cosmospub"
// Bech32PrefixValAddr defines the Bech32 prefix of a validator's operator address
Bech32PrefixValAddr = "cosmosval"
// Bech32PrefixValPub defines the Bech32 prefix of a validator's operator public key
Bech32PrefixValPub = "cosmosvalpub"
// Bech32PrefixConsAddr defines the Bech32 prefix of a consensus node address
Bech32PrefixConsAddr = "cosmoscons"
// Bech32PrefixConsPub defines the Bech32 prefix of a consensus node public key
Bech32PrefixConsPub = "cosmosconspub"
)
//__________________________________________________________
// ----------------------------------------------------------------------------
// account
// ----------------------------------------------------------------------------
// AccAddress a wrapper around bytes meant to represent an account address
// When marshaled to a string or json, it uses bech32
// AccAddress a wrapper around bytes meant to represent an account address.
// When marshaled to a string or JSON, it uses Bech32.
type AccAddress []byte
// create an AccAddress from a hex string
// AccAddressFromHex creates an AccAddress from a hex string.
func AccAddressFromHex(address string) (addr AccAddress, err error) {
if len(address) == 0 {
return addr, errors.New("decoding bech32 address failed: must provide an address")
return addr, errors.New("decoding Bech32 address failed: must provide an address")
}
bz, err := hex.DecodeString(address)
if err != nil {
return nil, err
}
return AccAddress(bz), nil
}
// create an AccAddress from a bech32 string
// AccAddressFromBech32 creates an AccAddress from a Bech32 string.
func AccAddressFromBech32(address string) (addr AccAddress, err error) {
bz, err := GetFromBech32(address, Bech32PrefixAccAddr)
if err != nil {
return nil, err
}
return AccAddress(bz), nil
}
// Marshal needed for protobuf compatibility
func (bz AccAddress) Marshal() ([]byte, error) {
return bz, nil
// Returns boolean for whether two AccAddresses are Equal
func (aa AccAddress) Equals(aa2 AccAddress) bool {
if aa.Empty() && aa2.Empty() {
return true
}
return bytes.Compare(aa.Bytes(), aa2.Bytes()) == 0
}
// Unmarshal needed for protobuf compatibility
func (bz *AccAddress) Unmarshal(data []byte) error {
*bz = data
// Returns boolean for whether an AccAddress is empty
func (aa AccAddress) Empty() bool {
if aa == nil {
return true
}
aa2 := AccAddress{}
return bytes.Compare(aa.Bytes(), aa2.Bytes()) == 0
}
// Marshal returns the raw address bytes. It is needed for protobuf
// compatibility.
func (aa AccAddress) Marshal() ([]byte, error) {
return aa, nil
}
// Unmarshal sets the address to the given data. It is needed for protobuf
// compatibility.
func (aa *AccAddress) Unmarshal(data []byte) error {
*aa = data
return nil
}
// Marshals to JSON using Bech32
func (bz AccAddress) MarshalJSON() ([]byte, error) {
return json.Marshal(bz.String())
// MarshalJSON marshals to JSON using Bech32.
func (aa AccAddress) MarshalJSON() ([]byte, error) {
return json.Marshal(aa.String())
}
// Unmarshals from JSON assuming Bech32 encoding
func (bz *AccAddress) UnmarshalJSON(data []byte) error {
// UnmarshalJSON unmarshals from JSON assuming Bech32 encoding.
func (aa *AccAddress) UnmarshalJSON(data []byte) error {
var s string
err := json.Unmarshal(data, &s)
if err != nil {
return nil
}
bz2, err := AccAddressFromBech32(s)
aa2, err := AccAddressFromBech32(s)
if err != nil {
return err
}
*bz = bz2
*aa = aa2
return nil
}
// Allow it to fulfill various interfaces in light-client, etc...
func (bz AccAddress) Bytes() []byte {
return bz
// Bytes returns the raw address bytes.
func (aa AccAddress) Bytes() []byte {
return aa
}
func (bz AccAddress) String() string {
bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixAccAddr, bz.Bytes())
// String implements the Stringer interface.
func (aa AccAddress) String() string {
bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixAccAddr, aa.Bytes())
if err != nil {
panic(err)
}
return bech32Addr
}
// For Printf / Sprintf, returns bech32 when using %s
func (bz AccAddress) Format(s fmt.State, verb rune) {
// Format implements the fmt.Formatter interface.
func (aa AccAddress) Format(s fmt.State, verb rune) {
switch verb {
case 's':
s.Write([]byte(fmt.Sprintf("%s", bz.String())))
s.Write([]byte(fmt.Sprintf("%s", aa.String())))
case 'p':
s.Write([]byte(fmt.Sprintf("%p", bz)))
s.Write([]byte(fmt.Sprintf("%p", aa)))
default:
s.Write([]byte(fmt.Sprintf("%X", []byte(bz))))
s.Write([]byte(fmt.Sprintf("%X", []byte(aa))))
}
}
// Returns boolean for whether two AccAddresses are Equal
func (bz AccAddress) Equals(bz2 AccAddress) bool {
if bz.Empty() && bz2.Empty() {
return true
}
return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0
}
// ----------------------------------------------------------------------------
// validator owner
// ----------------------------------------------------------------------------
// Returns boolean for whether an AccAddress is empty
func (bz AccAddress) Empty() bool {
if bz == nil {
return true
}
bz2 := AccAddress{}
return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0
}
//__________________________________________________________
// AccAddress a wrapper around bytes meant to represent a validator address
// (from over ABCI). When marshaled to a string or json, it uses bech32
// ValAddress defines a wrapper around bytes meant to present a validator's
// operator. When marshaled to a string or JSON, it uses Bech32.
type ValAddress []byte
// create a ValAddress from a hex string
// ValAddressFromHex creates a ValAddress from a hex string.
func ValAddressFromHex(address string) (addr ValAddress, err error) {
if len(address) == 0 {
return addr, errors.New("decoding bech32 address failed: must provide an address")
return addr, errors.New("decoding Bech32 address failed: must provide an address")
}
bz, err := hex.DecodeString(address)
if err != nil {
return nil, err
}
return ValAddress(bz), nil
}
// create a ValAddress from a bech32 string
// ValAddressFromBech32 creates a ValAddress from a Bech32 string.
func ValAddressFromBech32(address string) (addr ValAddress, err error) {
bz, err := GetFromBech32(address, Bech32PrefixValAddr)
if err != nil {
return nil, err
}
return ValAddress(bz), nil
}
// Marshal needed for protobuf compatibility
func (bz ValAddress) Marshal() ([]byte, error) {
return bz, nil
// Returns boolean for whether two ValAddresses are Equal
func (va ValAddress) Equals(va2 ValAddress) bool {
if va.Empty() && va2.Empty() {
return true
}
return bytes.Compare(va.Bytes(), va2.Bytes()) == 0
}
// Unmarshal needed for protobuf compatibility
func (bz *ValAddress) Unmarshal(data []byte) error {
*bz = data
// Returns boolean for whether an AccAddress is empty
func (va ValAddress) Empty() bool {
if va == nil {
return true
}
va2 := ValAddress{}
return bytes.Compare(va.Bytes(), va2.Bytes()) == 0
}
// Marshal returns the raw address bytes. It is needed for protobuf
// compatibility.
func (va ValAddress) Marshal() ([]byte, error) {
return va, nil
}
// Unmarshal sets the address to the given data. It is needed for protobuf
// compatibility.
func (va *ValAddress) Unmarshal(data []byte) error {
*va = data
return nil
}
// Marshals to JSON using Bech32
func (bz ValAddress) MarshalJSON() ([]byte, error) {
return json.Marshal(bz.String())
// MarshalJSON marshals to JSON using Bech32.
func (va ValAddress) MarshalJSON() ([]byte, error) {
return json.Marshal(va.String())
}
// Unmarshals from JSON assuming Bech32 encoding
func (bz *ValAddress) UnmarshalJSON(data []byte) error {
// UnmarshalJSON unmarshals from JSON assuming Bech32 encoding.
func (va *ValAddress) UnmarshalJSON(data []byte) error {
var s string
err := json.Unmarshal(data, &s)
if err != nil {
return nil
}
bz2, err := ValAddressFromBech32(s)
va2, err := ValAddressFromBech32(s)
if err != nil {
return err
}
*bz = bz2
*va = va2
return nil
}
// Allow it to fulfill various interfaces in light-client, etc...
func (bz ValAddress) Bytes() []byte {
return bz
// Bytes returns the raw address bytes.
func (va ValAddress) Bytes() []byte {
return va
}
func (bz ValAddress) String() string {
bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixValAddr, bz.Bytes())
// String implements the Stringer interface.
func (va ValAddress) String() string {
bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixValAddr, va.Bytes())
if err != nil {
panic(err)
}
return bech32Addr
}
// For Printf / Sprintf, returns bech32 when using %s
func (bz ValAddress) Format(s fmt.State, verb rune) {
// Format implements the fmt.Formatter interface.
func (va ValAddress) Format(s fmt.State, verb rune) {
switch verb {
case 's':
s.Write([]byte(fmt.Sprintf("%s", bz.String())))
s.Write([]byte(fmt.Sprintf("%s", va.String())))
case 'p':
s.Write([]byte(fmt.Sprintf("%p", bz)))
s.Write([]byte(fmt.Sprintf("%p", va)))
default:
s.Write([]byte(fmt.Sprintf("%X", []byte(bz))))
s.Write([]byte(fmt.Sprintf("%X", []byte(va))))
}
}
// Returns boolean for whether two ValAddresses are Equal
func (bz ValAddress) Equals(bz2 ValAddress) bool {
if bz.Empty() && bz2.Empty() {
// ----------------------------------------------------------------------------
// consensus node
// ----------------------------------------------------------------------------
// ConsAddress defines a wrapper around bytes meant to present a consensus node.
// When marshaled to a string or JSON, it uses Bech32.
type ConsAddress []byte
// ConsAddressFromHex creates a ConsAddress from a hex string.
func ConsAddressFromHex(address string) (addr ConsAddress, err error) {
if len(address) == 0 {
return addr, errors.New("decoding Bech32 address failed: must provide an address")
}
bz, err := hex.DecodeString(address)
if err != nil {
return nil, err
}
return ConsAddress(bz), nil
}
// ConsAddressFromBech32 creates a ConsAddress from a Bech32 string.
func ConsAddressFromBech32(address string) (addr ConsAddress, err error) {
bz, err := GetFromBech32(address, Bech32PrefixConsAddr)
if err != nil {
return nil, err
}
return ConsAddress(bz), nil
}
// Returns boolean for whether two ConsAddress are Equal
func (ca ConsAddress) Equals(ca2 ConsAddress) bool {
if ca.Empty() && ca2.Empty() {
return true
}
return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0
return bytes.Compare(ca.Bytes(), ca2.Bytes()) == 0
}
// Returns boolean for whether an AccAddress is empty
func (bz ValAddress) Empty() bool {
if bz == nil {
// Returns boolean for whether an ConsAddress is empty
func (ca ConsAddress) Empty() bool {
if ca == nil {
return true
}
bz2 := ValAddress{}
return bytes.Compare(bz.Bytes(), bz2.Bytes()) == 0
ca2 := ConsAddress{}
return bytes.Compare(ca.Bytes(), ca2.Bytes()) == 0
}
// Bech32ifyAccPub takes AccountPubKey and returns the bech32 encoded string
// Marshal returns the raw address bytes. It is needed for protobuf
// compatibility.
func (ca ConsAddress) Marshal() ([]byte, error) {
return ca, nil
}
// Unmarshal sets the address to the given data. It is needed for protobuf
// compatibility.
func (ca *ConsAddress) Unmarshal(data []byte) error {
*ca = data
return nil
}
// MarshalJSON marshals to JSON using Bech32.
func (ca ConsAddress) MarshalJSON() ([]byte, error) {
return json.Marshal(ca.String())
}
// UnmarshalJSON unmarshals from JSON assuming Bech32 encoding.
func (ca *ConsAddress) UnmarshalJSON(data []byte) error {
var s string
err := json.Unmarshal(data, &s)
if err != nil {
return nil
}
ca2, err := ConsAddressFromBech32(s)
if err != nil {
return err
}
*ca = ca2
return nil
}
// Bytes returns the raw address bytes.
func (ca ConsAddress) Bytes() []byte {
return ca
}
// String implements the Stringer interface.
func (ca ConsAddress) String() string {
bech32Addr, err := bech32.ConvertAndEncode(Bech32PrefixConsAddr, ca.Bytes())
if err != nil {
panic(err)
}
return bech32Addr
}
// Format implements the fmt.Formatter interface.
func (ca ConsAddress) Format(s fmt.State, verb rune) {
switch verb {
case 's':
s.Write([]byte(fmt.Sprintf("%s", ca.String())))
case 'p':
s.Write([]byte(fmt.Sprintf("%p", ca)))
default:
s.Write([]byte(fmt.Sprintf("%X", []byte(ca))))
}
}
// ----------------------------------------------------------------------------
// auxiliary
// ----------------------------------------------------------------------------
// Bech32ifyAccPub returns a Bech32 encoded string containing the
// Bech32PrefixAccPub prefix for a given account PubKey.
func Bech32ifyAccPub(pub crypto.PubKey) (string, error) {
return bech32.ConvertAndEncode(Bech32PrefixAccPub, pub.Bytes())
}
// MustBech32ifyAccPub panics on bech32-encoding failure
// MustBech32ifyAccPub returns the result of Bech32ifyAccPub panicing on failure.
func MustBech32ifyAccPub(pub crypto.PubKey) string {
enc, err := Bech32ifyAccPub(pub)
if err != nil {
panic(err)
}
return enc
}
// Bech32ifyValPub returns the bech32 encoded string for a validator pubkey
// Bech32ifyValPub returns a Bech32 encoded string containing the
// Bech32PrefixValPub prefix for a given validator operator's PubKey.
func Bech32ifyValPub(pub crypto.PubKey) (string, error) {
return bech32.ConvertAndEncode(Bech32PrefixValPub, pub.Bytes())
}
// MustBech32ifyValPub panics on bech32-encoding failure
// MustBech32ifyValPub returns the result of Bech32ifyValPub panicing on failure.
func MustBech32ifyValPub(pub crypto.PubKey) string {
enc, err := Bech32ifyValPub(pub)
if err != nil {
panic(err)
}
return enc
}
// create a Pubkey from a string
func GetAccPubKeyBech32(address string) (pk crypto.PubKey, err error) {
bz, err := GetFromBech32(address, Bech32PrefixAccPub)
// Bech32ifyConsPub returns a Bech32 encoded string containing the
// Bech32PrefixConsPub prefixfor a given consensus node's PubKey.
func Bech32ifyConsPub(pub crypto.PubKey) (string, error) {
return bech32.ConvertAndEncode(Bech32PrefixConsPub, pub.Bytes())
}
// MustBech32ifyConsPub returns the result of Bech32ifyConsPub panicing on
// failure.
func MustBech32ifyConsPub(pub crypto.PubKey) string {
enc, err := Bech32ifyConsPub(pub)
if err != nil {
panic(err)
}
return enc
}
// GetAccPubKeyBech32 creates a PubKey for an account with a given public key
// string using the Bech32 Bech32PrefixAccPub prefix.
func GetAccPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
bz, err := GetFromBech32(pubkey, Bech32PrefixAccPub)
if err != nil {
return nil, err
}
@ -270,16 +441,19 @@ func GetAccPubKeyBech32(address string) (pk crypto.PubKey, err error) {
return pk, nil
}
// create an Pubkey from a string, panics on error
func MustGetAccPubKeyBech32(address string) (pk crypto.PubKey) {
pk, err := GetAccPubKeyBech32(address)
// MustGetAccPubKeyBech32 returns the result of GetAccPubKeyBech32 panicing on
// failure.
func MustGetAccPubKeyBech32(pubkey string) (pk crypto.PubKey) {
pk, err := GetAccPubKeyBech32(pubkey)
if err != nil {
panic(err)
}
return pk
}
// decode a validator public key into a PubKey
// GetValPubKeyBech32 creates a PubKey for a validator's operator with a given
// public key string using the Bech32 Bech32PrefixValPub prefix.
func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
bz, err := GetFromBech32(pubkey, Bech32PrefixValPub)
if err != nil {
@ -294,27 +468,57 @@ func GetValPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
return pk, nil
}
// create an Pubkey from a string, panics on error
func MustGetValPubKeyBech32(address string) (pk crypto.PubKey) {
pk, err := GetValPubKeyBech32(address)
// MustGetValPubKeyBech32 returns the result of GetValPubKeyBech32 panicing on
// failure.
func MustGetValPubKeyBech32(pubkey string) (pk crypto.PubKey) {
pk, err := GetValPubKeyBech32(pubkey)
if err != nil {
panic(err)
}
return pk
}
// decode a bytestring from a bech32-encoded string
// GetConsPubKeyBech32 creates a PubKey for a consensus node with a given public
// key string using the Bech32 Bech32PrefixConsPub prefix.
func GetConsPubKeyBech32(pubkey string) (pk crypto.PubKey, err error) {
bz, err := GetFromBech32(pubkey, Bech32PrefixConsPub)
if err != nil {
return nil, err
}
pk, err = cryptoAmino.PubKeyFromBytes(bz)
if err != nil {
return nil, err
}
return pk, nil
}
// MustGetConsPubKeyBech32 returns the result of GetConsPubKeyBech32 panicing on
// failure.
func MustGetConsPubKeyBech32(pubkey string) (pk crypto.PubKey) {
pk, err := GetConsPubKeyBech32(pubkey)
if err != nil {
panic(err)
}
return pk
}
// GetFromBech32 decodes a bytestring from a Bech32 encoded string.
func GetFromBech32(bech32str, prefix string) ([]byte, error) {
if len(bech32str) == 0 {
return nil, errors.New("decoding bech32 address failed: must provide an address")
return nil, errors.New("decoding Bech32 address failed: must provide an address")
}
hrp, bz, err := bech32.DecodeAndConvert(bech32str)
if err != nil {
return nil, err
}
if hrp != prefix {
return nil, fmt.Errorf("invalid bech32 prefix. Expected %s, Got %s", prefix, hrp)
return nil, fmt.Errorf("invalid Bech32 prefix; expected %s, got %s", prefix, hrp)
}
return bz, nil

View File

@ -12,7 +12,7 @@ import (
"github.com/cosmos/cosmos-sdk/types"
)
var invalidstrs = []string{
var invalidStrs = []string{
"",
"hello, world!",
"0xAA",
@ -21,6 +21,8 @@ var invalidstrs = []string{
types.Bech32PrefixAccPub + "1234",
types.Bech32PrefixValAddr + "5678",
types.Bech32PrefixValPub + "BBAB",
types.Bech32PrefixConsAddr + "FF04",
types.Bech32PrefixConsPub + "6789",
}
func testMarshal(t *testing.T, original interface{}, res interface{}, marshal func() ([]byte, error), unmarshal func([]byte) error) {
@ -37,27 +39,38 @@ func TestRandBech32PubkeyConsistency(t *testing.T) {
for i := 0; i < 1000; i++ {
rand.Read(pub[:])
mustbech32accpub := types.MustBech32ifyAccPub(pub)
bech32accpub, err := types.Bech32ifyAccPub(pub)
mustBech32AccPub := types.MustBech32ifyAccPub(pub)
bech32AccPub, err := types.Bech32ifyAccPub(pub)
require.Nil(t, err)
require.Equal(t, bech32accpub, mustbech32accpub)
require.Equal(t, bech32AccPub, mustBech32AccPub)
mustbech32valpub := types.MustBech32ifyValPub(pub)
bech32valpub, err := types.Bech32ifyValPub(pub)
mustBech32ValPub := types.MustBech32ifyValPub(pub)
bech32ValPub, err := types.Bech32ifyValPub(pub)
require.Nil(t, err)
require.Equal(t, bech32valpub, mustbech32valpub)
require.Equal(t, bech32ValPub, mustBech32ValPub)
mustaccpub := types.MustGetAccPubKeyBech32(bech32accpub)
accpub, err := types.GetAccPubKeyBech32(bech32accpub)
mustBech32ConsPub := types.MustBech32ifyConsPub(pub)
bech32ConsPub, err := types.Bech32ifyConsPub(pub)
require.Nil(t, err)
require.Equal(t, accpub, mustaccpub)
require.Equal(t, bech32ConsPub, mustBech32ConsPub)
mustvalpub := types.MustGetValPubKeyBech32(bech32valpub)
valpub, err := types.GetValPubKeyBech32(bech32valpub)
mustAccPub := types.MustGetAccPubKeyBech32(bech32AccPub)
accPub, err := types.GetAccPubKeyBech32(bech32AccPub)
require.Nil(t, err)
require.Equal(t, valpub, mustvalpub)
require.Equal(t, accPub, mustAccPub)
require.Equal(t, valpub, accpub)
mustValPub := types.MustGetValPubKeyBech32(bech32ValPub)
valPub, err := types.GetValPubKeyBech32(bech32ValPub)
require.Nil(t, err)
require.Equal(t, valPub, mustValPub)
mustConsPub := types.MustGetConsPubKeyBech32(bech32ConsPub)
consPub, err := types.GetConsPubKeyBech32(bech32ConsPub)
require.Nil(t, err)
require.Equal(t, consPub, mustConsPub)
require.Equal(t, valPub, accPub)
require.Equal(t, valPub, consPub)
}
}
@ -84,7 +97,7 @@ func TestRandBech32AccAddrConsistency(t *testing.T) {
require.Equal(t, acc, res)
}
for _, str := range invalidstrs {
for _, str := range invalidStrs {
_, err := types.AccAddressFromHex(str)
require.NotNil(t, err)
@ -119,7 +132,7 @@ func TestValAddr(t *testing.T) {
require.Equal(t, acc, res)
}
for _, str := range invalidstrs {
for _, str := range invalidStrs {
_, err := types.ValAddressFromHex(str)
require.NotNil(t, err)
@ -130,3 +143,38 @@ func TestValAddr(t *testing.T) {
require.NotNil(t, err)
}
}
func TestConsAddress(t *testing.T) {
var pub ed25519.PubKeyEd25519
for i := 0; i < 20; i++ {
rand.Read(pub[:])
acc := types.ConsAddress(pub.Address())
res := types.ConsAddress{}
testMarshal(t, &acc, &res, acc.MarshalJSON, (&res).UnmarshalJSON)
testMarshal(t, &acc, &res, acc.Marshal, (&res).Unmarshal)
str := acc.String()
res, err := types.ConsAddressFromBech32(str)
require.Nil(t, err)
require.Equal(t, acc, res)
str = hex.EncodeToString(acc)
res, err = types.ConsAddressFromHex(str)
require.Nil(t, err)
require.Equal(t, acc, res)
}
for _, str := range invalidStrs {
_, err := types.ConsAddressFromHex(str)
require.NotNil(t, err)
_, err = types.ConsAddressFromBech32(str)
require.NotNil(t, err)
err = (*types.ConsAddress)(nil).UnmarshalJSON([]byte("\"" + str + "\""))
require.NotNil(t, err)
}
}

View File

@ -415,6 +415,14 @@ func MinDec(d1, d2 Dec) Dec {
return d2
}
// maximum decimal between two
func MaxDec(d1, d2 Dec) Dec {
if d1.LT(d2) {
return d2
}
return d1
}
// intended to be used with require/assert: require.True(DecEq(...))
func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, Dec, Dec) {
return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp, got

View File

@ -40,7 +40,7 @@ type Validator interface {
GetJailed() bool // whether the validator is jailed
GetMoniker() string // moniker of the validator
GetStatus() BondStatus // status of the validator
GetOperator() AccAddress // owner AccAddress to receive/return validators coins
GetOperator() ValAddress // owner address to receive/return validators coins
GetPubKey() crypto.PubKey // validation pubkey
GetPower() Dec // validation power
GetTokens() Dec // validation tokens
@ -67,7 +67,7 @@ type ValidatorSet interface {
IterateValidatorsBonded(Context,
func(index int64, validator Validator) (stop bool))
Validator(Context, AccAddress) Validator // get a particular validator by owner AccAddress
Validator(Context, ValAddress) Validator // get a particular validator by operator
ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by signing PubKey
TotalPower(Context) Dec // total power of the validator set
@ -75,6 +75,10 @@ type ValidatorSet interface {
Slash(Context, crypto.PubKey, int64, int64, Dec)
Jail(Context, crypto.PubKey) // jail a validator
Unjail(Context, crypto.PubKey) // unjail a validator
// Delegation allows for getting a particular delegation for a given validator
// and delegator outside the scope of the staking module.
Delegation(Context, AccAddress, ValAddress) Delegation
}
//_______________________________________________________________________________
@ -82,7 +86,7 @@ type ValidatorSet interface {
// delegation bond for a delegated proof of stake system
type Delegation interface {
GetDelegator() AccAddress // delegator AccAddress for the bond
GetValidator() AccAddress // validator owner AccAddress for the bond
GetValidator() ValAddress // validator operator address
GetBondShares() Dec // amount of validator's shares
}
@ -95,3 +99,13 @@ type DelegationSet interface {
IterateDelegations(ctx Context, delegator AccAddress,
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 {
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
}

View File

@ -65,7 +65,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
return newCtx, err.Result(), true
}
sigs := stdTx.GetSignatures()
sigs := stdTx.GetSignatures() // When simulating, this would just be a 0-length slice.
signerAddrs := stdTx.GetSigners()
msgs := tx.GetMsgs()
@ -88,10 +88,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
// check signature, return account with incremented nonce
signBytes := StdSignBytes(newCtx.ChainID(), accNums[i], sequences[i], fee, msgs, stdTx.GetMemo())
signerAcc, res := processSig(
newCtx, am,
signerAddr, sig, signBytes,
)
signerAcc, res := processSig(newCtx, am, signerAddr, sig, signBytes, simulate)
if !res.IsOK() {
return newCtx, res, true
}
@ -149,24 +146,24 @@ func validateBasic(tx StdTx) (err sdk.Error) {
// if the account doesn't have a pubkey, set it.
func processSig(
ctx sdk.Context, am AccountMapper,
addr sdk.AccAddress, sig StdSignature, signBytes []byte) (
addr sdk.AccAddress, sig StdSignature, signBytes []byte, simulate bool) (
acc Account, res sdk.Result) {
// Get the account.
acc = am.GetAccount(ctx, addr)
if acc == nil {
return nil, sdk.ErrUnknownAddress(addr.String()).Result()
}
// Check account number.
accnum := acc.GetAccountNumber()
seq := acc.GetSequence()
// Check account number.
if accnum != sig.AccountNumber {
return nil, sdk.ErrInvalidSequence(
fmt.Sprintf("Invalid account number. Got %d, expected %d", sig.AccountNumber, accnum)).Result()
}
// Check and increment sequence number.
seq := acc.GetSequence()
// Check sequence number.
if seq != sig.Sequence {
return nil, sdk.ErrInvalidSequence(
fmt.Sprintf("Invalid sequence. Got %d, expected %d", sig.Sequence, seq)).Result()
@ -176,31 +173,48 @@ func processSig(
// Handle w/ #870
panic(err)
}
pubKey, res := processPubKey(acc, sig, simulate)
if !res.IsOK() {
return nil, res
}
err = acc.SetPubKey(pubKey)
if err != nil {
return nil, sdk.ErrInternal("setting PubKey on signer's account").Result()
}
consumeSignatureVerificationGas(ctx.GasMeter(), pubKey)
if !simulate && !pubKey.VerifyBytes(signBytes, sig.Signature) {
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
}
return
}
func processPubKey(acc Account, sig StdSignature, simulate bool) (crypto.PubKey, sdk.Result) {
// If pubkey is not known for account,
// set it from the StdSignature.
pubKey := acc.GetPubKey()
if simulate {
// In simulate mode the transaction comes with no signatures, thus
// if the account's pubkey is nil, both signature verification
// and gasKVStore.Set() shall consume the largest amount, i.e.
// it takes more gas to verifiy secp256k1 keys than ed25519 ones.
if pubKey == nil {
return secp256k1.GenPrivKey().PubKey(), sdk.Result{}
}
return pubKey, sdk.Result{}
}
if pubKey == nil {
pubKey = sig.PubKey
if pubKey == nil {
return nil, sdk.ErrInvalidPubKey("PubKey not found").Result()
}
if !bytes.Equal(pubKey.Address(), addr) {
if !bytes.Equal(pubKey.Address(), acc.GetAddress()) {
return nil, sdk.ErrInvalidPubKey(
fmt.Sprintf("PubKey does not match Signer address %v", addr)).Result()
}
err = acc.SetPubKey(pubKey)
if err != nil {
return nil, sdk.ErrInternal("setting PubKey on signer's account").Result()
fmt.Sprintf("PubKey does not match Signer address %v", acc.GetAddress())).Result()
}
}
// Check sig.
consumeSignatureVerificationGas(ctx.GasMeter(), pubKey)
if !pubKey.VerifyBytes(signBytes, sig.Signature) {
return nil, sdk.ErrUnauthorized("signature verification failed").Result()
}
return
return pubKey, sdk.Result{}
}
func consumeSignatureVerificationGas(meter sdk.GasMeter, pubkey crypto.PubKey) {

View File

@ -4,14 +4,14 @@ import (
"fmt"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
wire "github.com/cosmos/cosmos-sdk/wire"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/tendermint/tendermint/libs/log"
sdk "github.com/cosmos/cosmos-sdk/types"
wire "github.com/cosmos/cosmos-sdk/wire"
)
func newTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg {
@ -567,3 +567,63 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
acc2 = mapper.GetAccount(ctx, addr2)
require.Nil(t, acc2.GetPubKey())
}
func TestProcessPubKey(t *testing.T) {
ms, capKey, _ := setupMultiStore()
cdc := wire.NewCodec()
RegisterBaseAccount(cdc)
mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount)
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
// keys
_, addr1 := privAndAddr()
priv2, _ := privAndAddr()
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
type args struct {
acc Account
sig StdSignature
simulate bool
}
tests := []struct {
name string
args args
wantErr bool
}{
{"no sigs, simulate off", args{acc1, StdSignature{}, false}, true},
{"no sigs, simulate on", args{acc1, StdSignature{}, true}, false},
{"pubkey doesn't match addr, simulate off", args{acc1, StdSignature{PubKey: priv2.PubKey()}, false}, true},
{"pubkey doesn't match addr, simulate on", args{acc1, StdSignature{PubKey: priv2.PubKey()}, true}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := processPubKey(tt.args.acc, tt.args.sig, tt.args.simulate)
require.Equal(t, tt.wantErr, !err.IsOK())
})
}
}
func TestConsumeSignatureVerificationGas(t *testing.T) {
type args struct {
meter sdk.GasMeter
pubkey crypto.PubKey
}
tests := []struct {
name string
args args
gasConsumed int64
wantPanic bool
}{
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), ed25519.GenPrivKey().PubKey()}, ed25519VerifyCost, false},
{"PubKeySecp256k1", args{sdk.NewInfiniteGasMeter(), secp256k1.GenPrivKey().PubKey()}, secp256k1VerifyCost, false},
{"unknown key", args{sdk.NewInfiniteGasMeter(), nil}, 0, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.wantPanic {
require.Panics(t, func() { consumeSignatureVerificationGas(tt.args.meter, tt.args.pubkey) })
} else {
consumeSignatureVerificationGas(tt.args.meter, tt.args.pubkey)
require.Equal(t, tt.args.meter.GasConsumed(), tt.gasConsumed)
}
})
}
}

View File

@ -148,3 +148,32 @@ func (ctx TxContext) BuildAndSign(name, passphrase string, msgs []sdk.Msg) ([]by
return ctx.Sign(name, passphrase, msg)
}
// BuildWithPubKey builds a single message to be signed from a TxContext given a set of
// messages and attach the public key associated to the given name.
// It returns an error if a fee is supplied but cannot be parsed or the key cannot be
// retrieved.
func (ctx TxContext) BuildWithPubKey(name string, msgs []sdk.Msg) ([]byte, error) {
msg, err := ctx.Build(msgs)
if err != nil {
return nil, err
}
keybase, err := keys.GetKeyBase()
if err != nil {
return nil, err
}
info, err := keybase.Get(name)
if err != nil {
return nil, err
}
sigs := []auth.StdSignature{{
AccountNumber: msg.AccountNumber,
Sequence: msg.Sequence,
PubKey: info.GetPubKey(),
}}
return ctx.Codec.MarshalBinary(auth.NewStdTx(msg.Msgs, msg.Fee, sigs, msg.Memo))
}

View File

@ -33,13 +33,13 @@ func QueryAccountRequestHandlerFn(
addr, err := sdk.AccAddressFromBech32(bech32addr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
res, err := cliCtx.QueryStore(auth.AddressStoreKey(addr), storeName)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("couldn't query account. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("couldn't query account. Error: %s", err.Error()))
return
}
@ -52,14 +52,14 @@ func QueryAccountRequestHandlerFn(
// decode the value
account, err := decoder(res)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("couldn't parse query result. Result: %s. Error: %s", res, err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("couldn't parse query result. Result: %s. Error: %s", res, err.Error()))
return
}
// print out whole account
output, err := cdc.MarshalJSON(account)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("couldn't marshall query result. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("couldn't marshall query result. Error: %s", err.Error()))
return
}

View File

@ -21,6 +21,7 @@ type (
}
appTestCase struct {
expSimPass bool
expPass bool
msgs []sdk.Msg
accNums []int64
@ -107,27 +108,29 @@ func TestMsgSendWithAccounts(t *testing.T) {
testCases := []appTestCase{
{
msgs: []sdk.Msg{sendMsg1},
accNums: []int64{0},
accSeqs: []int64{0},
expPass: true,
privKeys: []crypto.PrivKey{priv1},
msgs: []sdk.Msg{sendMsg1},
accNums: []int64{0},
accSeqs: []int64{0},
expSimPass: true,
expPass: true,
privKeys: []crypto.PrivKey{priv1},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 57)}},
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
},
},
{
msgs: []sdk.Msg{sendMsg1, sendMsg2},
accNums: []int64{0},
accSeqs: []int64{0},
expPass: false,
privKeys: []crypto.PrivKey{priv1},
msgs: []sdk.Msg{sendMsg1, sendMsg2},
accNums: []int64{0},
accSeqs: []int64{0},
expSimPass: false,
expPass: false,
privKeys: []crypto.PrivKey{priv1},
},
}
for _, tc := range testCases {
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...)
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
for _, eb := range tc.expectedBalances {
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
@ -144,7 +147,7 @@ func TestMsgSendWithAccounts(t *testing.T) {
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
// resigning the tx with the bumped sequence should work
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1, sendMsg2}, []int64{0}, []int64{1}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{sendMsg1, sendMsg2}, []int64{0}, []int64{1}, true, true, priv1)
}
func TestMsgSendMultipleOut(t *testing.T) {
@ -163,11 +166,12 @@ func TestMsgSendMultipleOut(t *testing.T) {
testCases := []appTestCase{
{
msgs: []sdk.Msg{sendMsg2},
accNums: []int64{0},
accSeqs: []int64{0},
expPass: true,
privKeys: []crypto.PrivKey{priv1},
msgs: []sdk.Msg{sendMsg2},
accNums: []int64{0},
accSeqs: []int64{0},
expSimPass: true,
expPass: true,
privKeys: []crypto.PrivKey{priv1},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 47)}},
@ -177,7 +181,7 @@ func TestMsgSendMultipleOut(t *testing.T) {
}
for _, tc := range testCases {
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...)
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
for _, eb := range tc.expectedBalances {
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
@ -205,11 +209,12 @@ func TestSengMsgMultipleInOut(t *testing.T) {
testCases := []appTestCase{
{
msgs: []sdk.Msg{sendMsg3},
accNums: []int64{0, 2},
accSeqs: []int64{0, 0},
expPass: true,
privKeys: []crypto.PrivKey{priv1, priv4},
msgs: []sdk.Msg{sendMsg3},
accNums: []int64{0, 2},
accSeqs: []int64{0, 0},
expSimPass: true,
expPass: true,
privKeys: []crypto.PrivKey{priv1, priv4},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
{addr4, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
@ -220,7 +225,7 @@ func TestSengMsgMultipleInOut(t *testing.T) {
}
for _, tc := range testCases {
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...)
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
for _, eb := range tc.expectedBalances {
mock.CheckBalance(t, mapp, eb.addr, eb.coins)
@ -240,22 +245,24 @@ func TestMsgSendDependent(t *testing.T) {
testCases := []appTestCase{
{
msgs: []sdk.Msg{sendMsg1},
accNums: []int64{0},
accSeqs: []int64{0},
expPass: true,
privKeys: []crypto.PrivKey{priv1},
msgs: []sdk.Msg{sendMsg1},
accNums: []int64{0},
accSeqs: []int64{0},
expSimPass: true,
expPass: true,
privKeys: []crypto.PrivKey{priv1},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 32)}},
{addr2, sdk.Coins{sdk.NewInt64Coin("foocoin", 10)}},
},
},
{
msgs: []sdk.Msg{sendMsg4},
accNums: []int64{1},
accSeqs: []int64{0},
expPass: true,
privKeys: []crypto.PrivKey{priv2},
msgs: []sdk.Msg{sendMsg4},
accNums: []int64{1},
accSeqs: []int64{0},
expSimPass: true,
expPass: true,
privKeys: []crypto.PrivKey{priv2},
expectedBalances: []expectedBalance{
{addr1, sdk.Coins{sdk.NewInt64Coin("foocoin", 42)}},
},
@ -263,7 +270,7 @@ func TestMsgSendDependent(t *testing.T) {
}
for _, tc := range testCases {
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expPass, tc.privKeys...)
mock.SignCheckDeliver(t, mapp.BaseApp, tc.msgs, tc.accNums, tc.accSeqs, tc.expSimPass, tc.expPass, tc.privKeys...)
for _, eb := range tc.expectedBalances {
mock.CheckBalance(t, mapp, eb.addr, eb.coins)

View File

@ -4,6 +4,7 @@ import (
"io/ioutil"
"net/http"
cliclient "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/crypto/keys"
@ -31,6 +32,7 @@ type sendBody struct {
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas int64 `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
}
var msgCdc = wire.NewCodec()
@ -40,6 +42,7 @@ func init() {
}
// SendRequestHandlerFn - http request handler to send coins to a address
// nolint: gocyclo
func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// collect data
@ -48,32 +51,32 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo
to, err := sdk.AccAddressFromBech32(bech32addr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
var m sendBody
body, err := ioutil.ReadAll(r.Body)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
err = msgCdc.UnmarshalJSON(body, &m)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
info, err := kb.Get(m.LocalAccountName)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
// build message
msg := client.BuildMsg(sdk.AccAddress(info.GetPubKey().Address()), to, m.Amount)
if err != nil { // XXX rechecking same error ?
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
@ -85,10 +88,20 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo
Sequence: m.Sequence,
}
if m.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg})
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, cliclient.DefaultGasAdjustment)
if !ok {
return
}
cliCtx = cliCtx.WithGasAdjustment(adjustment)
if utils.HasDryRunArg(r) || m.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, txCtx.Gas)
return
}
txCtx = newCtx
@ -96,19 +109,19 @@ func SendRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLICo
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := wire.MarshalJSONIndent(cdc, res)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

View File

@ -187,7 +187,7 @@ func TestMsgSendGetSignBytes(t *testing.T) {
}
res := msg.GetSignBytes()
expected := `{"inputs":[{"address":"cosmosaccaddr1d9h8qat5e4ehc5","coins":[{"amount":"10","denom":"atom"}]}],"outputs":[{"address":"cosmosaccaddr1da6hgur4wse3jx32","coins":[{"amount":"10","denom":"atom"}]}]}`
expected := `{"inputs":[{"address":"cosmos1d9h8qat57ljhcm","coins":[{"amount":"10","denom":"atom"}]}],"outputs":[{"address":"cosmos1da6hgur4wsmpnjyg","coins":[{"amount":"10","denom":"atom"}]}]}`
require.Equal(t, expected, string(res))
}
@ -257,7 +257,7 @@ func TestMsgIssueGetSignBytes(t *testing.T) {
}
res := msg.GetSignBytes()
expected := `{"banker":"cosmosaccaddr1d9h8qat5e4ehc5","outputs":[{"address":"cosmosaccaddr1d3hkzm3dveex7mfdvfsku6cwsauqd","coins":[{"amount":"10","denom":"atom"}]}]}`
expected := `{"banker":"cosmos1d9h8qat57ljhcm","outputs":[{"address":"cosmos1d3hkzm3dveex7mfdvfsku6cjngpcj","coins":[{"amount":"10","denom":"atom"}]}]}`
require.Equal(t, expected, string(res))
}

View File

@ -77,11 +77,11 @@ func postProposalHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.Hand
msg := gov.NewMsgSubmitProposal(req.Title, req.Description, req.ProposalType, req.Proposer, req.InitialDeposit)
err = msg.ValidateBasic()
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
signAndBuild(w, cliCtx, req.BaseReq, msg, cdc)
signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc)
}
}
@ -92,7 +92,7 @@ func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFu
if len(strProposalID) == 0 {
err := errors.New("proposalId required but not specified")
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -114,11 +114,11 @@ func depositHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFu
msg := gov.NewMsgDeposit(req.Depositer, proposalID, req.Amount)
err = msg.ValidateBasic()
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
signAndBuild(w, cliCtx, req.BaseReq, msg, cdc)
signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc)
}
}
@ -129,7 +129,7 @@ func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc
if len(strProposalID) == 0 {
err := errors.New("proposalId required but not specified")
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -151,11 +151,11 @@ func voteHandlerFn(cdc *wire.Codec, cliCtx context.CLIContext) http.HandlerFunc
msg := gov.NewMsgVote(req.Voter, proposalID, req.Option)
err = msg.ValidateBasic()
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
signAndBuild(w, cliCtx, req.BaseReq, msg, cdc)
signAndBuild(w, r, cliCtx, req.BaseReq, msg, cdc)
}
}
@ -166,7 +166,7 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if len(strProposalID) == 0 {
err := errors.New("proposalId required but not specified")
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -183,13 +183,13 @@ func queryProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
bz, err := cdc.MarshalJSON(params)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
res, err := cliCtx.QueryWithData("custom/gov/proposal", bz)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
@ -205,7 +205,7 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if len(strProposalID) == 0 {
err := errors.New("proposalId required but not specified")
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -216,14 +216,14 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if len(bechDepositerAddr) == 0 {
err := errors.New("depositer address required but not specified")
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
depositerAddr, err := sdk.AccAddressFromBech32(bechDepositerAddr)
if err != nil {
err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer)
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -236,13 +236,13 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
bz, err := cdc.MarshalJSON(params)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
res, err := cliCtx.QueryWithData("custom/gov/deposit", bz)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
@ -252,11 +252,11 @@ func queryDepositHandlerFn(cdc *wire.Codec) http.HandlerFunc {
res, err := cliCtx.QueryWithData("custom/gov/proposal", cdc.MustMarshalBinary(gov.QueryProposalParams{params.ProposalID}))
if err != nil || len(res) == 0 {
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error())
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
return
}
err = errors.Errorf("depositer [%s] did not deposit on proposalID [%d]", bechDepositerAddr, proposalID)
utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error())
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
return
}
@ -272,7 +272,7 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if len(strProposalID) == 0 {
err := errors.New("proposalId required but not specified")
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -283,14 +283,14 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if len(bechVoterAddr) == 0 {
err := errors.New("voter address required but not specified")
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
voterAddr, err := sdk.AccAddressFromBech32(bechVoterAddr)
if err != nil {
err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter)
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -302,13 +302,13 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
}
bz, err := cdc.MarshalJSON(params)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
res, err := cliCtx.QueryWithData("custom/gov/vote", bz)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
@ -317,17 +317,17 @@ func queryVoteHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if vote.Empty() {
bz, err := cdc.MarshalJSON(gov.QueryProposalParams{params.ProposalID})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
res, err := cliCtx.QueryWithData("custom/gov/proposal", bz)
if err != nil || len(res) == 0 {
err := errors.Errorf("proposalID [%d] does not exist", proposalID)
utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error())
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
return
}
err = errors.Errorf("voter [%s] did not deposit on proposalID [%d]", bechVoterAddr, proposalID)
utils.WriteErrorResponse(&w, http.StatusNotFound, err.Error())
utils.WriteErrorResponse(w, http.StatusNotFound, err.Error())
return
}
w.Write(res)
@ -343,7 +343,7 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
if len(strProposalID) == 0 {
err := errors.New("proposalId required but not specified")
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -359,13 +359,13 @@ func queryVotesOnProposalHandlerFn(cdc *wire.Codec) http.HandlerFunc {
}
bz, err := cdc.MarshalJSON(params)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
res, err := cliCtx.QueryWithData("custom/gov/votes", bz)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
@ -388,7 +388,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
voterAddr, err := sdk.AccAddressFromBech32(bechVoterAddr)
if err != nil {
err := errors.Errorf("'%s' needs to be bech32 encoded", RestVoter)
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
params.Voter = voterAddr
@ -398,7 +398,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
depositerAddr, err := sdk.AccAddressFromBech32(bechDepositerAddr)
if err != nil {
err := errors.Errorf("'%s' needs to be bech32 encoded", RestDepositer)
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
params.Depositer = depositerAddr
@ -408,7 +408,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
proposalStatus, err := gov.ProposalStatusFromString(strProposalStatus)
if err != nil {
err := errors.Errorf("'%s' is not a valid Proposal Status", strProposalStatus)
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
params.ProposalStatus = proposalStatus
@ -423,7 +423,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
bz, err := cdc.MarshalJSON(params)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
@ -431,7 +431,7 @@ func queryProposalsWithParameterFn(cdc *wire.Codec) http.HandlerFunc {
res, err := cliCtx.QueryWithData("custom/gov/proposals", bz)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

View File

@ -6,6 +6,7 @@ import (
"net/http"
"strconv"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -20,17 +21,18 @@ type baseReq struct {
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas int64 `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
}
func buildReq(w http.ResponseWriter, r *http.Request, cdc *wire.Codec, req interface{}) error {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return err
}
err = cdc.UnmarshalJSON(body, req)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return err
}
return nil
@ -38,27 +40,27 @@ func buildReq(w http.ResponseWriter, r *http.Request, cdc *wire.Codec, req inter
func (req baseReq) baseReqValidate(w http.ResponseWriter) bool {
if len(req.Name) == 0 {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Name required but not specified")
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Name required but not specified")
return false
}
if len(req.Password) == 0 {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Password required but not specified")
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Password required but not specified")
return false
}
if len(req.ChainID) == 0 {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "ChainID required but not specified")
utils.WriteErrorResponse(w, http.StatusUnauthorized, "ChainID required but not specified")
return false
}
if req.AccountNumber < 0 {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Account Number required but not specified")
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Account Number required but not specified")
return false
}
if req.Sequence < 0 {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Sequence required but not specified")
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Sequence required but not specified")
return false
}
return true
@ -66,7 +68,7 @@ func (req baseReq) baseReqValidate(w http.ResponseWriter) bool {
// TODO: Build this function out into a more generic base-request
// (probably should live in client/lcd).
func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) {
func signAndBuild(w http.ResponseWriter, r *http.Request, cliCtx context.CLIContext, baseReq baseReq, msg sdk.Msg, cdc *wire.Codec) {
var err error
txCtx := authctx.TxContext{
Codec: cdc,
@ -76,29 +78,39 @@ func signAndBuild(w http.ResponseWriter, cliCtx context.CLIContext, baseReq base
Gas: baseReq.Gas,
}
if baseReq.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, baseReq.Name, baseReq.Password, []sdk.Msg{msg})
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, baseReq.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
cliCtx = cliCtx.WithGasAdjustment(adjustment)
if utils.HasDryRunArg(r) || baseReq.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, baseReq.Name, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, txCtx.Gas)
return
}
txCtx = newCtx
}
txBytes, err := txCtx.BuildAndSign(baseReq.Name, baseReq.Password, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := wire.MarshalJSONIndent(cdc, res)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

View File

@ -178,12 +178,17 @@ func TestSlashing(t *testing.T) {
govHandler := NewHandler(keeper)
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{25, 6, 7})
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{25, 6, 7})
initTotalPower := keeper.ds.GetValidatorSet().TotalPower(ctx)
val0Initial := keeper.ds.GetValidatorSet().Validator(ctx, addrs[0]).GetPower().Quo(initTotalPower)
val1Initial := keeper.ds.GetValidatorSet().Validator(ctx, addrs[1]).GetPower().Quo(initTotalPower)
val2Initial := keeper.ds.GetValidatorSet().Validator(ctx, addrs[2]).GetPower().Quo(initTotalPower)
val0Initial := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[0])).GetPower().Quo(initTotalPower)
val1Initial := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[1])).GetPower().Quo(initTotalPower)
val2Initial := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[2])).GetPower().Quo(initTotalPower)
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 15)})
@ -209,9 +214,9 @@ func TestSlashing(t *testing.T) {
require.False(t, keeper.GetProposal(ctx, proposalID).GetTallyResult().Equals(EmptyTallyResult()))
endTotalPower := keeper.ds.GetValidatorSet().TotalPower(ctx)
val0End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[0]).GetPower().Quo(endTotalPower)
val1End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[1]).GetPower().Quo(endTotalPower)
val2End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[2]).GetPower().Quo(endTotalPower)
val0End := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[0])).GetPower().Quo(endTotalPower)
val1End := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[1])).GetPower().Quo(endTotalPower)
val2End := keeper.ds.GetValidatorSet().Validator(ctx, sdk.ValAddress(addrs[2])).GetPower().Quo(endTotalPower)
require.True(t, val0End.GTE(val0Initial))
require.True(t, val1End.LT(val1Initial))

View File

@ -114,8 +114,8 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
resTags.AppendTag(tags.Action, tags.ActionProposalDropped)
resTags.AppendTag(tags.ProposalID, proposalIDBytes)
logger.Info("Proposal %d - \"%s\" - didn't mean minimum deposit (had only %s), deleted",
inactiveProposal.GetProposalID(), inactiveProposal.GetTitle(), inactiveProposal.GetTotalDeposit())
logger.Info(fmt.Sprintf("Proposal %d - \"%s\" - didn't mean minimum deposit (had only %s), deleted",
inactiveProposal.GetProposalID(), inactiveProposal.GetTitle(), inactiveProposal.GetTotalDeposit()))
}
// Check if earliest Active Proposal ended voting period yet
@ -143,8 +143,8 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
activeProposal.SetTallyResult(tallyResults)
keeper.SetProposal(ctx, activeProposal)
logger.Info("Proposal %d - \"%s\" - tallied, passed: %v",
activeProposal.GetProposalID(), activeProposal.GetTitle(), passes)
logger.Info(fmt.Sprintf("Proposal %d - \"%s\" - tallied, passed: %v",
activeProposal.GetProposalID(), activeProposal.GetTitle(), passes))
for _, valAddr := range nonVotingVals {
val := keeper.ds.GetValidatorSet().Validator(ctx, valAddr)

View File

@ -6,14 +6,14 @@ import (
// validatorGovInfo used for tallying
type validatorGovInfo struct {
Address sdk.AccAddress // sdk.AccAddress of the validator owner
Address sdk.ValAddress // address of the validator operator
Power sdk.Dec // Power of a Validator
DelegatorShares sdk.Dec // Total outstanding delegator shares
Minus sdk.Dec // Minus of validator, used to compute validator's voting power
Vote VoteOption // Vote of the validator
}
func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tallyResults TallyResult, nonVoting []sdk.AccAddress) {
func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tallyResults TallyResult, nonVoting []sdk.ValAddress) {
results := make(map[VoteOption]sdk.Dec)
results[OptionYes] = sdk.ZeroDec()
results[OptionAbstain] = sdk.ZeroDec()
@ -43,15 +43,18 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
// if validator, just record it in the map
// if delegator tally voting power
if val, ok := currValidators[vote.Voter.String()]; ok {
valAddrStr := sdk.ValAddress(vote.Voter).String()
if val, ok := currValidators[valAddrStr]; ok {
val.Vote = vote.Option
currValidators[vote.Voter.String()] = val
currValidators[valAddrStr] = val
} else {
keeper.ds.IterateDelegations(ctx, vote.Voter, func(index int64, delegation sdk.Delegation) (stop bool) {
if val, ok := currValidators[delegation.GetValidator().String()]; ok {
valAddrStr := delegation.GetValidator().String()
if val, ok := currValidators[valAddrStr]; ok {
val.Minus = val.Minus.Add(delegation.GetBondShares())
currValidators[delegation.GetValidator().String()] = val
currValidators[valAddrStr] = val
delegatorShare := delegation.GetBondShares().Quo(val.DelegatorShares)
votingPower := val.Power.Mul(delegatorShare)
@ -59,6 +62,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
results[vote.Option] = results[vote.Option].Add(votingPower)
totalVotingPower = totalVotingPower.Add(votingPower)
}
return false
})
}
@ -66,13 +70,15 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
keeper.deleteVote(ctx, vote.ProposalID, vote.Voter)
}
// Iterate over the validators again to tally their voting power and see who didn't vote
nonVoting = []sdk.AccAddress{}
// iterate over the validators again to tally their voting power and see
// who didn't vote
nonVoting = []sdk.ValAddress{}
for _, val := range currValidators {
if val.Vote == OptionEmpty {
nonVoting = append(nonVoting, val.Address)
continue
}
sharesAfterMinus := val.DelegatorShares.Sub(val.Minus)
percentAfterMinus := sharesAfterMinus.Quo(val.DelegatorShares)
votingPower := val.Power.Mul(percentAfterMinus)
@ -104,7 +110,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
}
// If more than 1/2 of non-abstaining voters vote No, proposal fails
SortAddresses(nonVoting)
SortValAddresses(nonVoting)
return false, tallyResults, nonVoting
}

View File

@ -17,7 +17,7 @@ var (
pubkeys = []crypto.PubKey{ed25519.GenPrivKey().PubKey(), ed25519.GenPrivKey().PubKey(), ed25519.GenPrivKey().PubKey()}
)
func createValidators(t *testing.T, stakeHandler sdk.Handler, ctx sdk.Context, addrs []sdk.AccAddress, coinAmt []int64) {
func createValidators(t *testing.T, stakeHandler sdk.Handler, ctx sdk.Context, addrs []sdk.ValAddress, coinAmt []int64) {
require.True(t, len(addrs) <= len(pubkeys), "Not enough pubkeys specified at top of file.")
dummyDescription := stake.NewDescription("T", "E", "S", "T")
for i := 0; i < len(addrs); i++ {
@ -33,7 +33,12 @@ func TestTallyNoOneVotes(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:2], []int64{5, 5})
valAddrs := make([]sdk.ValAddress, len(addrs[:2]))
for i, addr := range addrs[:2] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 5})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID()
@ -52,7 +57,12 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:2], []int64{5, 5})
valAddrs := make([]sdk.ValAddress, len(addrs[:2]))
for i, addr := range addrs[:2] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 5})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID()
@ -76,7 +86,12 @@ func TestTallyOnlyValidators51No(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:2], []int64{5, 6})
valAddrs := make([]sdk.ValAddress, len(addrs[:2]))
for i, addr := range addrs[:2] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID()
@ -99,7 +114,12 @@ func TestTallyOnlyValidators51Yes(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7})
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID()
@ -125,7 +145,12 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7})
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID()
@ -151,7 +176,12 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7})
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID()
@ -177,7 +207,12 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7})
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID()
@ -203,7 +238,12 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{6, 6, 7})
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{6, 6, 7})
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposalID := proposal.GetProposalID()
@ -219,7 +259,7 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) {
require.False(t, passes)
require.Equal(t, 1, len(nonVoting))
require.Equal(t, addrs[0], nonVoting[0])
require.Equal(t, sdk.ValAddress(addrs[0]), nonVoting[0])
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}
@ -229,9 +269,14 @@ func TestTallyDelgatorOverride(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{5, 6, 7})
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 30))
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7})
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30))
stakeHandler(ctx, delegator1Msg)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
@ -260,9 +305,14 @@ func TestTallyDelgatorInherit(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{5, 6, 7})
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 30))
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7})
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 30))
stakeHandler(ctx, delegator1Msg)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
@ -290,11 +340,16 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{5, 6, 7})
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 10))
createValidators(t, stakeHandler, ctx, valAddrs, []int64{5, 6, 7})
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10))
stakeHandler(ctx, delegator1Msg)
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], addrs[1], sdk.NewInt64Coin("steak", 10))
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10))
stakeHandler(ctx, delegator1Msg2)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
@ -324,16 +379,26 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) {
stakeHandler := stake.NewHandler(sk)
dummyDescription := stake.NewDescription("T", "E", "S", "T")
val1CreateMsg := stake.NewMsgCreateValidator(addrs[0], ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 25), dummyDescription)
val1CreateMsg := stake.NewMsgCreateValidator(
sdk.ValAddress(addrs[0]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 25), dummyDescription,
)
stakeHandler(ctx, val1CreateMsg)
val2CreateMsg := stake.NewMsgCreateValidator(addrs[1], ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 6), dummyDescription)
val2CreateMsg := stake.NewMsgCreateValidator(
sdk.ValAddress(addrs[1]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 6), dummyDescription,
)
stakeHandler(ctx, val2CreateMsg)
val3CreateMsg := stake.NewMsgCreateValidator(addrs[2], ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 7), dummyDescription)
val3CreateMsg := stake.NewMsgCreateValidator(
sdk.ValAddress(addrs[2]), ed25519.GenPrivKey().PubKey(), sdk.NewInt64Coin("steak", 7), dummyDescription,
)
stakeHandler(ctx, val3CreateMsg)
delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 10))
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10))
stakeHandler(ctx, delegator1Msg)
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], addrs[1], sdk.NewInt64Coin("steak", 10))
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10))
stakeHandler(ctx, delegator1Msg2)
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
@ -360,13 +425,20 @@ func TestTallyJailedValidator(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{})
stakeHandler := stake.NewHandler(sk)
createValidators(t, stakeHandler, ctx, addrs[:3], []int64{25, 6, 7})
delegator1Msg := stake.NewMsgDelegate(addrs[3], addrs[2], sdk.NewInt64Coin("steak", 10))
valAddrs := make([]sdk.ValAddress, len(addrs[:3]))
for i, addr := range addrs[:3] {
valAddrs[i] = sdk.ValAddress(addr)
}
createValidators(t, stakeHandler, ctx, valAddrs, []int64{25, 6, 7})
delegator1Msg := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[2]), sdk.NewInt64Coin("steak", 10))
stakeHandler(ctx, delegator1Msg)
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], addrs[1], sdk.NewInt64Coin("steak", 10))
delegator1Msg2 := stake.NewMsgDelegate(addrs[3], sdk.ValAddress(addrs[1]), sdk.NewInt64Coin("steak", 10))
stakeHandler(ctx, delegator1Msg2)
val2, found := sk.GetValidator(ctx, addrs[1])
val2, found := sk.GetValidator(ctx, sdk.ValAddress(addrs[1]))
require.True(t, found)
sk.Jail(ctx, val2.PubKey)

View File

@ -77,6 +77,20 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakeKeeper stake.Keeper) sdk
}
}
// TODO: Remove once address interface has been implemented (ref: #2186)
func SortValAddresses(addrs []sdk.ValAddress) {
var byteAddrs [][]byte
for _, addr := range addrs {
byteAddrs = append(byteAddrs, addr.Bytes())
}
SortByteArrays(byteAddrs)
for i, byteAddr := range byteAddrs {
addrs[i] = byteAddr
}
}
// Sorts Addresses
func SortAddresses(addrs []sdk.AccAddress) {
var byteAddrs [][]byte

View File

@ -70,10 +70,10 @@ func TestIBCMsgs(t *testing.T) {
Sequence: 0,
}
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{0}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{0}, true, true, priv1)
mock.CheckBalance(t, mapp, addr1, emptyCoins)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{1}, false, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{transferMsg}, []int64{0}, []int64{1}, false, false, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, true, true, priv1)
mock.CheckBalance(t, mapp, addr1, coins)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, false, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{receiveMsg}, []int64{0}, []int64{2}, false, false, priv1)
}

View File

@ -4,6 +4,7 @@ import (
"io/ioutil"
"net/http"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/crypto/keys"
@ -29,10 +30,12 @@ type transferBody struct {
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas int64 `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
}
// TransferRequestHandler - http request handler to transfer coins to a address
// on a different chain via IBC
// nolint: gocyclo
func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
@ -41,26 +44,26 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C
to, err := sdk.AccAddressFromBech32(bech32addr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
var m transferBody
body, err := ioutil.ReadAll(r.Body)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
err = cdc.UnmarshalJSON(body, &m)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
info, err := kb.Get(m.LocalAccountName)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
@ -76,10 +79,20 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C
Gas: m.Gas,
}
if m.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg})
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
cliCtx = cliCtx.WithGasAdjustment(adjustment)
if utils.HasDryRunArg(r) || m.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, txCtx.Gas)
return
}
txCtx = newCtx
@ -87,19 +100,19 @@ func TransferRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.C
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := cdc.MarshalJSON(res)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

View File

@ -61,14 +61,14 @@ func TestCheckAndDeliverGenTx(t *testing.T) {
SignCheckDeliver(
t, mApp.BaseApp, []sdk.Msg{msg},
[]int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence()},
true, privKeys[0],
true, true, privKeys[0],
)
// Signing a tx with the wrong privKey should result in an auth error
res := SignCheckDeliver(
t, mApp.BaseApp, []sdk.Msg{msg},
[]int64{accs[1].GetAccountNumber()}, []int64{accs[1].GetSequence() + 1},
false, privKeys[1],
true, false, privKeys[1],
)
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
@ -76,7 +76,7 @@ func TestCheckAndDeliverGenTx(t *testing.T) {
SignCheckDeliver(
t, mApp.BaseApp, []sdk.Msg{msg},
[]int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence() + 1},
true, privKeys[0],
true, true, privKeys[0],
)
}

View File

@ -76,9 +76,10 @@ func SimulateFromSeed(
header := abci.Header{Height: 0, Time: timestamp}
opCount := 0
request := abci.RequestBeginBlock{Header: header}
var pastTimes []time.Time
var pastSigningValidators [][]abci.SigningValidator
request := RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log)
// These are operations which have been queued by previous operations
operationQueue := make(map[int][]Operation)
@ -90,6 +91,7 @@ func SimulateFromSeed(
for i := 0; i < numBlocks; i++ {
// Log the header time for future lookup
pastTimes = append(pastTimes, header.Time)
pastSigningValidators = append(pastSigningValidators, request.LastCommitInfo.Validators)
// Run the BeginBlock handler
app.BeginBlock(request)
@ -124,7 +126,7 @@ func SimulateFromSeed(
}
// Generate a random RequestBeginBlock with the current validator set for the next block
request = RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, event, header, log)
request = RandomRequestBeginBlock(r, validators, livenessTransitionMatrix, evidenceFraction, pastTimes, pastSigningValidators, event, header, log)
// Update the validator set
validators = updateValidators(tb, r, validators, res.ValidatorUpdates, event)
@ -242,13 +244,12 @@ func getKeys(validators map[string]mockValidator) []string {
// RandomRequestBeginBlock generates a list of signing validators according to the provided list of validators, signing fraction, and evidence fraction
func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator, livenessTransitions TransitionMatrix, evidenceFraction float64,
pastTimes []time.Time, event func(string), header abci.Header, log string) abci.RequestBeginBlock {
pastTimes []time.Time, pastSigningValidators [][]abci.SigningValidator, event func(string), header abci.Header, log string) abci.RequestBeginBlock {
if len(validators) == 0 {
return abci.RequestBeginBlock{Header: header}
}
signingValidators := make([]abci.SigningValidator, len(validators))
i := 0
for _, key := range getKeys(validators) {
mVal := validators[key]
mVal.livenessState = livenessTransitions.NextState(r, mVal.livenessState)
@ -276,26 +277,31 @@ func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator,
}
// TODO: Determine capacity before allocation
evidence := make([]abci.Evidence, 0)
for r.Float64() < evidenceFraction {
height := header.Height
time := header.Time
if r.Float64() < pastEvidenceFraction {
height = int64(r.Intn(int(header.Height)))
time = pastTimes[height]
// Anything but the first block
if len(pastTimes) > 0 {
for r.Float64() < evidenceFraction {
height := header.Height
time := header.Time
vals := signingValidators
if r.Float64() < pastEvidenceFraction {
height = int64(r.Intn(int(header.Height)))
time = pastTimes[height]
vals = pastSigningValidators[height]
}
validator := vals[r.Intn(len(vals))].Validator
var totalVotingPower int64
for _, val := range vals {
totalVotingPower += val.Validator.Power
}
evidence = append(evidence, abci.Evidence{
Type: tmtypes.ABCIEvidenceTypeDuplicateVote,
Validator: validator,
Height: height,
Time: time,
TotalVotingPower: totalVotingPower,
})
event("beginblock/evidence")
}
validator := signingValidators[r.Intn(len(signingValidators))].Validator
var currentTotalVotingPower int64
for _, mVal := range validators {
currentTotalVotingPower += mVal.val.Power
}
evidence = append(evidence, abci.Evidence{
Type: tmtypes.ABCIEvidenceTypeDuplicateVote,
Validator: validator,
Height: height,
Time: time,
TotalVotingPower: currentTotalVotingPower,
})
event("beginblock/evidence")
}
return abci.RequestBeginBlock{
Header: header,

View File

@ -71,13 +71,13 @@ func CheckGenTx(
// returned.
func SignCheckDeliver(
t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []int64,
seq []int64, expPass bool, priv ...crypto.PrivKey,
seq []int64, expSimPass, expPass bool, priv ...crypto.PrivKey,
) sdk.Result {
tx := GenTx(msgs, accNums, seq, priv...)
// Must simulate now as CheckTx doesn't run Msgs anymore
res := app.Simulate(tx)
if expPass {
if expSimPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)

View File

@ -73,13 +73,13 @@ func getInitChainer(mapp *mock.App, keeper stake.Keeper) sdk.InitChainer {
func checkValidator(t *testing.T, mapp *mock.App, keeper stake.Keeper,
addr sdk.AccAddress, expFound bool) stake.Validator {
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
validator, found := keeper.GetValidator(ctxCheck, addr1)
validator, found := keeper.GetValidator(ctxCheck, sdk.ValAddress(addr1))
require.Equal(t, expFound, found)
return validator
}
func checkValidatorSigningInfo(t *testing.T, mapp *mock.App, keeper Keeper,
addr sdk.ValAddress, expFound bool) ValidatorSigningInfo {
addr sdk.ConsAddress, expFound bool) ValidatorSigningInfo {
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
signingInfo, found := keeper.getValidatorSigningInfo(ctxCheck, addr)
require.Equal(t, expFound, found)
@ -100,22 +100,22 @@ func TestSlashingMsgs(t *testing.T) {
mock.SetGenesis(mapp, accs)
description := stake.NewDescription("foo_moniker", "", "", "")
createValidatorMsg := stake.NewMsgCreateValidator(
addr1, priv1.PubKey(), bondCoin, description,
sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description,
)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin.Minus(bondCoin)})
mapp.BeginBlock(abci.RequestBeginBlock{})
validator := checkValidator(t, mapp, stakeKeeper, addr1, true)
require.Equal(t, addr1, validator.Operator)
require.Equal(t, sdk.ValAddress(addr1), validator.Operator)
require.Equal(t, sdk.Bonded, validator.Status)
require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens()))
unjailMsg := MsgUnjail{ValidatorAddr: sdk.AccAddress(validator.PubKey.Address())}
unjailMsg := MsgUnjail{ValidatorAddr: sdk.ValAddress(validator.PubKey.Address())}
// no signing info yet
checkValidatorSigningInfo(t, mapp, keeper, sdk.ValAddress(addr1), false)
checkValidatorSigningInfo(t, mapp, keeper, sdk.ConsAddress(addr1), false)
// unjail should fail with unknown validator
res := mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{unjailMsg}, []int64{0}, []int64{1}, false, priv1)
res := mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{unjailMsg}, []int64{0}, []int64{1}, false, false, priv1)
require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), res.Code)
}

View File

@ -20,12 +20,12 @@ func GetCmdQuerySigningInfo(storeName string, cdc *wire.Codec) *cobra.Command {
Short: "Query a validator's signing information",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
pk, err := sdk.GetValPubKeyBech32(args[0])
pk, err := sdk.GetConsPubKeyBech32(args[0])
if err != nil {
return err
}
key := slashing.GetValidatorSigningInfoKey(sdk.ValAddress(pk.Address()))
key := slashing.GetValidatorSigningInfoKey(sdk.ConsAddress(pk.Address()))
cliCtx := context.NewCLIContext().WithCodec(cdc)
res, err := cliCtx.QueryStore(key, storeName)

View File

@ -27,12 +27,12 @@ func GetCmdUnjail(cdc *wire.Codec) *cobra.Command {
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
validatorAddr, err := cliCtx.GetFromAddress()
valAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
msg := slashing.NewMsgUnjail(validatorAddr)
msg := slashing.NewMsgUnjail(sdk.ValAddress(valAddr))
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
},

View File

@ -23,14 +23,14 @@ func signingInfoHandlerFn(cliCtx context.CLIContext, storeName string, cdc *wire
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
pk, err := sdk.GetValPubKeyBech32(vars["validator"])
pk, err := sdk.GetConsPubKeyBech32(vars["validator"])
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
key := slashing.GetValidatorSigningInfoKey(sdk.ValAddress(pk.Address()))
key := slashing.GetValidatorSigningInfoKey(sdk.ConsAddress(pk.Address()))
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {

View File

@ -7,6 +7,7 @@ import (
"io/ioutil"
"net/http"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/crypto/keys"
@ -33,37 +34,39 @@ type UnjailBody struct {
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas int64 `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
ValidatorAddr string `json:"validator_addr"`
}
// nolint: gocyclo
func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var m UnjailBody
body, err := ioutil.ReadAll(r.Body)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
err = json.Unmarshal(body, &m)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusBadRequest, err.Error())
utils.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
info, err := kb.Get(m.LocalAccountName)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
validatorAddr, err := sdk.AccAddressFromBech32(m.ValidatorAddr)
valAddr, err := sdk.ValAddressFromBech32(m.ValidatorAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
if !bytes.Equal(info.GetPubKey().Address(), validatorAddr) {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own validator address")
if !bytes.Equal(info.GetPubKey().Address(), valAddr) {
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own validator address")
return
}
@ -75,12 +78,22 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI
Gas: m.Gas,
}
msg := slashing.NewMsgUnjail(validatorAddr)
msg := slashing.NewMsgUnjail(valAddr)
if m.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg})
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
cliCtx = cliCtx.WithGasAdjustment(adjustment)
if utils.HasDryRunArg(r) || m.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, txCtx.Gas)
return
}
txCtx = newCtx
@ -88,19 +101,19 @@ func unjailRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx context.CLI
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own validator address")
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own validator address")
return
}
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
output, err := json.MarshalIndent(res, "", " ")
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

View File

@ -12,20 +12,28 @@ const (
// Default slashing codespace
DefaultCodespace sdk.CodespaceType = 10
CodeInvalidValidator CodeType = 101
CodeValidatorJailed CodeType = 102
CodeValidatorNotJailed CodeType = 103
CodeInvalidValidator CodeType = 101
CodeValidatorJailed CodeType = 102
CodeValidatorNotJailed CodeType = 103
CodeMissingSelfDelegation CodeType = 104
)
func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "that address is not associated with any known validator")
}
func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address")
}
func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeValidatorJailed, "validator still jailed, cannot yet be unjailed")
}
func ErrValidatorNotJailed(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeValidatorNotJailed, "validator not jailed, cannot be unjailed")
}
func ErrMissingSelfDelegation(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeMissingSelfDelegation, "validator has no self-delegation; cannot be unjailed")
}

View File

@ -19,35 +19,38 @@ func NewHandler(k Keeper) sdk.Handler {
// Validators must submit a transaction to unjail itself after
// having been jailed (and thus unbonded) for downtime
func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result {
// Validator must exist
validator := k.validatorSet.Validator(ctx, msg.ValidatorAddr)
if validator == nil {
return ErrNoValidatorForAddress(k.codespace).Result()
}
// cannot be unjailed if no self-delegation exists
selfDel := k.validatorSet.Delegation(ctx, sdk.AccAddress(msg.ValidatorAddr), msg.ValidatorAddr)
if selfDel == nil {
return ErrMissingSelfDelegation(k.codespace).Result()
}
if !validator.GetJailed() {
return ErrValidatorNotJailed(k.codespace).Result()
}
addr := sdk.ValAddress(validator.GetPubKey().Address())
addr := sdk.ConsAddress(validator.GetPubKey().Address())
// Signing info must exist
info, found := k.getValidatorSigningInfo(ctx, addr)
if !found {
return ErrNoValidatorForAddress(k.codespace).Result()
}
// Cannot be unjailed until out of jail
// cannot be unjailed until out of jail
if ctx.BlockHeader().Time.Before(info.JailedUntil) {
return ErrValidatorJailed(k.codespace).Result()
}
// Update the starting height (so the validator can't be immediately jailed again)
// update the starting height so the validator can't be immediately jailed
// again
info.StartHeight = ctx.BlockHeight()
k.setValidatorSigningInfo(ctx, addr, info)
// Unjail the validator
k.validatorSet.Unjail(ctx, validator.GetPubKey())
tags := sdk.NewTags("action", []byte("unjail"), "validator", []byte(msg.ValidatorAddr.String()))

View File

@ -2,6 +2,7 @@ package slashing
import (
"testing"
"time"
"github.com/stretchr/testify/require"
@ -15,15 +16,76 @@ func TestCannotUnjailUnlessJailed(t *testing.T) {
slh := NewHandler(keeper)
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
msg := newTestMsgCreateValidator(addr, val, amt)
msg := newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt)
got := stake.NewHandler(sk)(ctx, msg)
require.True(t, got.IsOK())
stake.EndBlocker(ctx, sk)
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()))
// assert non-jailed validator can't be unjailed
got = slh(ctx, NewMsgUnjail(addr))
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
require.False(t, got.IsOK(), "allowed unjail of non-jailed validator")
require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotJailed), got.Code)
}
func TestJailedValidatorDelegations(t *testing.T) {
ctx, _, stakeKeeper, _, slashingKeeper := createTestInput(t)
stakeParams := stakeKeeper.GetParams(ctx)
stakeParams.UnbondingTime = 0
stakeKeeper.SetParams(ctx, stakeParams)
// create a validator
amount := int64(10)
valPubKey, bondAmount := pks[0], sdk.NewInt(amount)
valAddr, consAddr := sdk.ValAddress(addrs[1]), sdk.ConsAddress(addrs[0])
msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount)
got := stake.NewHandler(stakeKeeper)(ctx, msgCreateVal)
require.True(t, got.IsOK(), "expected create validator msg to be ok, got: %v", got)
// set dummy signing info
newInfo := ValidatorSigningInfo{
StartHeight: int64(0),
IndexOffset: int64(0),
JailedUntil: time.Unix(0, 0),
SignedBlocksCounter: int64(0),
}
slashingKeeper.setValidatorSigningInfo(ctx, consAddr, newInfo)
// delegate tokens to the validator
delAddr := sdk.AccAddress(addrs[2])
msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount)
got = stake.NewHandler(stakeKeeper)(ctx, msgDelegate)
require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got)
unbondShares := sdk.NewDec(10)
// unbond validator total self-delegations (which should jail the validator)
msgBeginUnbonding := stake.NewMsgBeginUnbonding(sdk.AccAddress(valAddr), valAddr, unbondShares)
got = stake.NewHandler(stakeKeeper)(ctx, msgBeginUnbonding)
require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got: %v", got)
msgCompleteUnbonding := stake.NewMsgCompleteUnbonding(sdk.AccAddress(valAddr), valAddr)
got = stake.NewHandler(stakeKeeper)(ctx, msgCompleteUnbonding)
require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got: %v", got)
// verify validator still exists and is jailed
validator, found := stakeKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
require.True(t, validator.GetJailed())
// verify the validator cannot unjail itself
got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr))
require.False(t, got.IsOK(), "expected jailed validator to not be able to unjail, got: %v", got)
// self-delegate to validator
msgSelfDelegate := newTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount)
got = stake.NewHandler(stakeKeeper)(ctx, msgSelfDelegate)
require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got)
// verify the validator can now unjail itself
got = NewHandler(slashingKeeper)(ctx, NewMsgUnjail(valAddr))
require.True(t, got.IsOK(), "expected jailed validator to be able to unjail, got: %v", got)
}

46
x/slashing/hooks.go Normal file
View File

@ -0,0 +1,46 @@
package slashing
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Create a new slashing period when a validator is bonded
func (k Keeper) onValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) {
slashingPeriod := ValidatorSlashingPeriod{
ValidatorAddr: address,
StartHeight: ctx.BlockHeight(),
EndHeight: 0,
SlashedSoFar: sdk.ZeroDec(),
}
k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod)
}
// Mark the slashing period as having ended when a validator begins unbonding
func (k Keeper) onValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) {
slashingPeriod := k.getValidatorSlashingPeriodForHeight(ctx, address, ctx.BlockHeight())
slashingPeriod.EndHeight = ctx.BlockHeight()
k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod)
}
// Wrapper struct for sdk.ValidatorHooks
type ValidatorHooks struct {
k Keeper
}
// Assert implementation
var _ sdk.ValidatorHooks = ValidatorHooks{}
// Return a sdk.ValidatorHooks interface over the wrapper struct
func (k Keeper) ValidatorHooks() sdk.ValidatorHooks {
return ValidatorHooks{k}
}
// Implements sdk.ValidatorHooks
func (v ValidatorHooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) {
v.k.onValidatorBonded(ctx, address)
}
// Implements sdk.ValidatorHooks
func (v ValidatorHooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) {
v.k.onValidatorBeginUnbonding(ctx, address)
}

26
x/slashing/hooks_test.go Normal file
View File

@ -0,0 +1,26 @@
package slashing
import (
"testing"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func TestHookOnValidatorBonded(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
addr := sdk.ConsAddress(addrs[0])
keeper.onValidatorBonded(ctx, addr)
period := keeper.getValidatorSlashingPeriodForHeight(ctx, addr, ctx.BlockHeight())
require.Equal(t, ValidatorSlashingPeriod{addr, ctx.BlockHeight(), 0, sdk.ZeroDec()}, period)
}
func TestHookOnValidatorBeginUnbonding(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
addr := sdk.ConsAddress(addrs[0])
keeper.onValidatorBonded(ctx, addr)
keeper.onValidatorBeginUnbonding(ctx, addr)
period := keeper.getValidatorSlashingPeriodForHeight(ctx, addr, ctx.BlockHeight())
require.Equal(t, ValidatorSlashingPeriod{addr, ctx.BlockHeight(), ctx.BlockHeight(), sdk.ZeroDec()}, period)
}

View File

@ -40,7 +40,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
logger := ctx.Logger().With("module", "x/slashing")
time := ctx.BlockHeader().Time
age := time.Sub(timestamp)
address := sdk.ValAddress(addr)
address := sdk.ConsAddress(addr)
pubkey, err := k.getPubkey(ctx, addr)
if err != nil {
panic(fmt.Sprintf("Validator address %v not found", addr))
@ -56,8 +56,14 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
// 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))
// Cap the amount slashed to the penalty for the worst infraction
// within the slashing period when this infraction was committed
fraction := k.SlashFractionDoubleSign(ctx)
revisedFraction := k.capBySlashingPeriod(ctx, address, fraction, infractionHeight)
logger.Info(fmt.Sprintf("Fraction slashed capped by slashing period from %v to %v", fraction, revisedFraction))
// Slash validator
k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, k.SlashFractionDoubleSign(ctx))
k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, revisedFraction)
// Jail validator
k.validatorSet.Jail(ctx, pubkey)
@ -76,7 +82,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, power int64, signed bool) {
logger := ctx.Logger().With("module", "x/slashing")
height := ctx.BlockHeight()
address := sdk.ValAddress(addr)
address := sdk.ConsAddress(addr)
pubkey, err := k.getPubkey(ctx, addr)
if err != nil {
panic(fmt.Sprintf("Validator address %v not found", addr))
@ -169,7 +175,3 @@ func (k Keeper) deleteAddrPubkeyRelation(ctx sdk.Context, addr crypto.Address) {
store := ctx.KVStore(k.storeKey)
store.Delete(getAddrPubkeyRelationKey(addr))
}
func getAddrPubkeyRelationKey(address []byte) []byte {
return append([]byte{0x03}, address...)
}

View File

@ -24,13 +24,55 @@ func TestHandleDoubleSign(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()))
// handle a signature to set signing info
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true)
// double sign less than max age
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
// should be jailed
require.True(t, sk.Validator(ctx, sdk.ValAddress(addr)).GetJailed())
// unjail to measure power
sk.Unjail(ctx, val)
// power should be reduced
require.Equal(
t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))),
sk.Validator(ctx, sdk.ValAddress(addr)).GetPower(),
)
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.MaxEvidenceAge(ctx))})
// double sign past max age
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
require.Equal(
t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))),
sk.Validator(ctx, sdk.ValAddress(addr)).GetPower(),
)
}
// Test that the amount a validator is slashed for multiple double signs
// is correctly capped by the slashing period in which they were committed
func TestSlashingPeriodCap(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
// handle a signature to set signing info
@ -41,15 +83,35 @@ func TestHandleDoubleSign(t *testing.T) {
// should be jailed
require.True(t, sk.Validator(ctx, addr).GetJailed())
// update block height
ctx = ctx.WithBlockHeight(int64(1))
// unjail to measure power
sk.Unjail(ctx, val)
// power should be reduced
require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower())
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.MaxEvidenceAge(ctx))})
expectedPower := sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20)))
require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower())
// double sign past max age
// double sign again, same slashing period
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
require.Equal(t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))), sk.Validator(ctx, addr).GetPower())
// should be jailed
require.True(t, sk.Validator(ctx, addr).GetJailed())
// update block height
ctx = ctx.WithBlockHeight(int64(2))
// unjail to measure power
sk.Unjail(ctx, val)
// power should be equal, no more should have been slashed
expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20)))
require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower())
// double sign again, new slashing period
keeper.handleDoubleSign(ctx, val.Address(), 2, time.Unix(0, 0), amtInt)
// should be jailed
require.True(t, sk.Validator(ctx, addr).GetJailed())
// unjail to measure power
sk.Unjail(ctx, val)
// power should be reduced
expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(18).Quo(sdk.NewDec(20)))
require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower())
}
// Test a validator through uptime, downtime, revocation,
@ -58,17 +120,18 @@ func TestHandleAbsentValidator(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
sh := stake.NewHandler(sk)
slh := NewHandler(keeper)
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()))
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.False(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, int64(0), info.IndexOffset)
@ -83,7 +146,7 @@ func TestHandleAbsentValidator(t *testing.T) {
ctx = ctx.WithBlockHeight(height)
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true)
}
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, keeper.SignedBlocksWindow(ctx), info.SignedBlocksCounter)
@ -93,7 +156,7 @@ func TestHandleAbsentValidator(t *testing.T) {
ctx = ctx.WithBlockHeight(height)
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
}
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.SignedBlocksCounter)
@ -107,7 +170,7 @@ func TestHandleAbsentValidator(t *testing.T) {
// 501st block missed
ctx = ctx.WithBlockHeight(height)
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter)
@ -117,12 +180,12 @@ func TestHandleAbsentValidator(t *testing.T) {
require.Equal(t, sdk.Unbonded, validator.GetStatus())
// unrevocation should fail prior to jail expiration
got = slh(ctx, NewMsgUnjail(addr))
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
require.False(t, got.IsOK())
// unrevocation should succeed after jail expiration
ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(1, 0).Add(keeper.DowntimeUnbondDuration(ctx))})
got = slh(ctx, NewMsgUnjail(addr))
got = slh(ctx, NewMsgUnjail(sdk.ValAddress(addr)))
require.True(t, got.IsOK())
// validator should be rebonded now
@ -135,7 +198,7 @@ func TestHandleAbsentValidator(t *testing.T) {
require.Equal(t, int64(amtInt)-slashAmt, pool.BondedTokens.RoundInt64())
// validator start height should have been changed
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.True(t, found)
require.Equal(t, height, info.StartHeight)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter)
@ -172,12 +235,12 @@ func TestHandleNewValidator(t *testing.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)))
got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, sdk.NewInt(amt)))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}})
require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, addr).GetPower())
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.SubRaw(amt)}})
require.Equal(t, sdk.NewDec(amt), sk.Validator(ctx, sdk.ValAddress(addr)).GetPower())
// 1000 first blocks not a validator
ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 1)
@ -187,7 +250,7 @@ func TestHandleNewValidator(t *testing.T) {
ctx = ctx.WithBlockHeight(keeper.SignedBlocksWindow(ctx) + 2)
keeper.handleValidatorSignature(ctx, val.Address(), 100, false)
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(val.Address()))
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(keeper.SignedBlocksWindow(ctx)+1), info.StartHeight)
require.Equal(t, int64(2), info.IndexOffset)
@ -210,7 +273,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
sh := stake.NewHandler(sk)
got := sh(ctx, newTestMsgCreateValidator(addr, val, amt))
got := sh(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), val, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)

43
x/slashing/keys.go Normal file
View File

@ -0,0 +1,43 @@
package slashing
import (
"encoding/binary"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// key prefix bytes
var (
ValidatorSigningInfoKey = []byte{0x01} // Prefix for signing info
ValidatorSigningBitArrayKey = []byte{0x02} // Prefix for signature bit array
ValidatorSlashingPeriodKey = []byte{0x03} // Prefix for slashing period
AddrPubkeyRelationKey = []byte{0x04} // Prefix for address-pubkey relation
)
// stored by *Tendermint* address (not owner address)
func GetValidatorSigningInfoKey(v sdk.ConsAddress) []byte {
return append(ValidatorSigningInfoKey, v.Bytes()...)
}
// stored by *Tendermint* address (not owner address)
func GetValidatorSigningBitArrayKey(v sdk.ConsAddress, i int64) []byte {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(i))
return append(ValidatorSigningBitArrayKey, append(v.Bytes(), b...)...)
}
// stored by *Tendermint* address (not owner address)
func GetValidatorSlashingPeriodPrefix(v sdk.ConsAddress) []byte {
return append(ValidatorSlashingPeriodKey, v.Bytes()...)
}
// stored by *Tendermint* address (not owner address) followed by start height
func GetValidatorSlashingPeriodKey(v sdk.ConsAddress, startHeight int64) []byte {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(startHeight))
return append(GetValidatorSlashingPeriodPrefix(v), b...)
}
func getAddrPubkeyRelationKey(address []byte) []byte {
return append(AddrPubkeyRelationKey, address...)
}

View File

@ -15,18 +15,20 @@ var _ sdk.Msg = &MsgUnjail{}
// MsgUnjail - struct for unjailing jailed validator
type MsgUnjail struct {
ValidatorAddr sdk.AccAddress `json:"address"` // address of the validator owner
ValidatorAddr sdk.ValAddress `json:"address"` // address of the validator owner
}
func NewMsgUnjail(validatorAddr sdk.AccAddress) MsgUnjail {
func NewMsgUnjail(validatorAddr sdk.ValAddress) MsgUnjail {
return MsgUnjail{
ValidatorAddr: validatorAddr,
}
}
//nolint
func (msg MsgUnjail) Type() string { return MsgType }
func (msg MsgUnjail) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{msg.ValidatorAddr} }
func (msg MsgUnjail) Type() string { return MsgType }
func (msg MsgUnjail) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{sdk.AccAddress(msg.ValidatorAddr)}
}
// get the bytes for the message signer to sign on
func (msg MsgUnjail) GetSignBytes() []byte {

View File

@ -10,7 +10,7 @@ import (
func TestMsgUnjailGetSignBytes(t *testing.T) {
addr := sdk.AccAddress("abcd")
msg := NewMsgUnjail(addr)
msg := NewMsgUnjail(sdk.ValAddress(addr))
bytes := msg.GetSignBytes()
require.Equal(t, string(bytes), `{"address":"cosmosaccaddr1v93xxeqhyqz5v"}`)
require.Equal(t, string(bytes), `{"address":"cosmosval1v93xxeq7xkcrf"}`)
}

View File

@ -1,7 +1,6 @@
package slashing
import (
"encoding/binary"
"fmt"
"time"
@ -9,7 +8,7 @@ import (
)
// Stored by *validator* address (not owner address)
func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.ValAddress) (info ValidatorSigningInfo, found bool) {
func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress) (info ValidatorSigningInfo, found bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(GetValidatorSigningInfoKey(address))
if bz == nil {
@ -22,14 +21,14 @@ func (k Keeper) getValidatorSigningInfo(ctx sdk.Context, address sdk.ValAddress)
}
// Stored by *validator* address (not owner address)
func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.ValAddress, info ValidatorSigningInfo) {
func (k Keeper) setValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress, info ValidatorSigningInfo) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(info)
store.Set(GetValidatorSigningInfoKey(address), bz)
}
// Stored by *validator* address (not owner address)
func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.ValAddress, index int64) (signed bool) {
func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64) (signed bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(GetValidatorSigningBitArrayKey(address, index))
if bz == nil {
@ -42,7 +41,7 @@ func (k Keeper) getValidatorSigningBitArray(ctx sdk.Context, address sdk.ValAddr
}
// Stored by *validator* address (not owner address)
func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.ValAddress, index int64, signed bool) {
func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.ConsAddress, index int64, signed bool) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(signed)
store.Set(GetValidatorSigningBitArrayKey(address, index), bz)
@ -71,15 +70,3 @@ func (i ValidatorSigningInfo) HumanReadableString() string {
return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %v, signed blocks counter: %d",
i.StartHeight, i.IndexOffset, i.JailedUntil, i.SignedBlocksCounter)
}
// Stored by *validator* address (not owner address)
func GetValidatorSigningInfoKey(v sdk.ValAddress) []byte {
return append([]byte{0x01}, v.Bytes()...)
}
// Stored by *validator* address (not owner address)
func GetValidatorSigningBitArrayKey(v sdk.ValAddress, i int64) []byte {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(i))
return append([]byte{0x02}, append(v.Bytes(), b...)...)
}

View File

@ -11,7 +11,7 @@ import (
func TestGetSetValidatorSigningInfo(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(addrs[0]))
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0]))
require.False(t, found)
newInfo := ValidatorSigningInfo{
StartHeight: int64(4),
@ -19,8 +19,8 @@ func TestGetSetValidatorSigningInfo(t *testing.T) {
JailedUntil: time.Unix(2, 0),
SignedBlocksCounter: int64(10),
}
keeper.setValidatorSigningInfo(ctx, sdk.ValAddress(addrs[0]), newInfo)
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(addrs[0]))
keeper.setValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0]), newInfo)
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0]))
require.True(t, found)
require.Equal(t, info.StartHeight, int64(4))
require.Equal(t, info.IndexOffset, int64(3))
@ -30,9 +30,9 @@ func TestGetSetValidatorSigningInfo(t *testing.T) {
func TestGetSetValidatorSigningBitArray(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
signed := keeper.getValidatorSigningBitArray(ctx, sdk.ValAddress(addrs[0]), 0)
signed := keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0)
require.False(t, signed) // treat empty key as unsigned
keeper.setValidatorSigningBitArray(ctx, sdk.ValAddress(addrs[0]), 0, true)
signed = keeper.getValidatorSigningBitArray(ctx, sdk.ValAddress(addrs[0]), 0)
keeper.setValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0, true)
signed = keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0)
require.True(t, signed) // now should be signed
}

View File

@ -17,7 +17,7 @@ import (
func SimulateMsgUnjail(k slashing.Keeper) simulation.Operation {
return func(tb testing.TB, r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, log string, event func(string)) (action string, fOp []simulation.FutureOperation, err sdk.Error) {
key := simulation.RandomKey(r, keys)
address := sdk.AccAddress(key.PubKey().Address())
address := sdk.ValAddress(key.PubKey().Address())
msg := slashing.NewMsgUnjail(address)
if msg.ValidateBasic() != nil {
tb.Fatalf("expected msg to pass ValidateBasic: %s, log %s", msg.GetSignBytes(), log)

View File

@ -0,0 +1,107 @@
package slashing
import (
"encoding/binary"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Cap an infraction's slash amount by the slashing period in which it was committed
func (k Keeper) capBySlashingPeriod(ctx sdk.Context, address sdk.ConsAddress, fraction sdk.Dec, infractionHeight int64) (revisedFraction sdk.Dec) {
// Fetch the newest slashing period starting before this infraction was committed
slashingPeriod := k.getValidatorSlashingPeriodForHeight(ctx, address, infractionHeight)
// Sanity check
if slashingPeriod.EndHeight > 0 && slashingPeriod.EndHeight < infractionHeight {
panic(fmt.Sprintf("slashing period ended before infraction: infraction height %d, slashing period ended at %d", infractionHeight, slashingPeriod.EndHeight))
}
// Calculate the updated total slash amount
// This is capped at the slashing fraction for the worst infraction within this slashing period
totalToSlash := sdk.MaxDec(slashingPeriod.SlashedSoFar, fraction)
// Calculate the remainder which we now must slash
revisedFraction = totalToSlash.Sub(slashingPeriod.SlashedSoFar)
// Update the slashing period struct
slashingPeriod.SlashedSoFar = totalToSlash
k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod)
return
}
// Stored by validator Tendermint address (not owner address)
// This function retrieves the most recent slashing period starting
// before a particular height - so the slashing period that was "in effect"
// at the time of an infraction committed at that height.
func (k Keeper) getValidatorSlashingPeriodForHeight(ctx sdk.Context, address sdk.ConsAddress, height int64) (slashingPeriod ValidatorSlashingPeriod) {
store := ctx.KVStore(k.storeKey)
// Get the most recent slashing period at or before the infraction height
start := GetValidatorSlashingPeriodPrefix(address)
end := sdk.PrefixEndBytes(GetValidatorSlashingPeriodKey(address, height))
iterator := store.ReverseIterator(start, end)
if !iterator.Valid() {
panic("expected to find slashing period, but none was found")
}
slashingPeriod = k.unmarshalSlashingPeriodKeyValue(iterator.Key(), iterator.Value())
return
}
// Stored by validator Tendermint address (not owner address)
// This function sets a validator slashing period for a particular validator,
// start height, end height, and current slashed-so-far total, or updates
// an existing slashing period for the same validator and start height.
func (k Keeper) addOrUpdateValidatorSlashingPeriod(ctx sdk.Context, slashingPeriod ValidatorSlashingPeriod) {
slashingPeriodValue := ValidatorSlashingPeriodValue{
EndHeight: slashingPeriod.EndHeight,
SlashedSoFar: slashingPeriod.SlashedSoFar,
}
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(slashingPeriodValue)
store.Set(GetValidatorSlashingPeriodKey(slashingPeriod.ValidatorAddr, slashingPeriod.StartHeight), bz)
}
// Unmarshal key/value into a ValidatorSlashingPeriod
func (k Keeper) unmarshalSlashingPeriodKeyValue(key []byte, value []byte) ValidatorSlashingPeriod {
var slashingPeriodValue ValidatorSlashingPeriodValue
k.cdc.MustUnmarshalBinary(value, &slashingPeriodValue)
address := sdk.ConsAddress(key[1 : 1+sdk.AddrLen])
startHeight := int64(binary.LittleEndian.Uint64(key[1+sdk.AddrLen : 1+sdk.AddrLen+8]))
return ValidatorSlashingPeriod{
ValidatorAddr: address,
StartHeight: startHeight,
EndHeight: slashingPeriodValue.EndHeight,
SlashedSoFar: slashingPeriodValue.SlashedSoFar,
}
}
// Construct a new `ValidatorSlashingPeriod` struct
func NewValidatorSlashingPeriod(startHeight int64, endHeight int64, slashedSoFar sdk.Dec) ValidatorSlashingPeriod {
return ValidatorSlashingPeriod{
StartHeight: startHeight,
EndHeight: endHeight,
SlashedSoFar: slashedSoFar,
}
}
// Slashing period for a validator
type ValidatorSlashingPeriod struct {
ValidatorAddr sdk.ConsAddress `json:"validator_addr"` // validator which this slashing period is for
StartHeight int64 `json:"start_height"` // starting height of the slashing period
EndHeight int64 `json:"end_height"` // ending height of the slashing period, or sentinel value of 0 for in-progress
SlashedSoFar sdk.Dec `json:"slashed_so_far"` // fraction of validator stake slashed so far in this slashing period
}
// Value part of slashing period (validator address & start height are stored in the key)
type ValidatorSlashingPeriodValue struct {
EndHeight int64 `json:"end_height"`
SlashedSoFar sdk.Dec `json:"slashed_so_far"`
}
// Return human readable slashing period
func (p ValidatorSlashingPeriod) HumanReadableString() string {
return fmt.Sprintf("Start height: %d, end height: %d, slashed so far: %v",
p.StartHeight, p.EndHeight, p.SlashedSoFar)
}

View File

@ -0,0 +1,86 @@
package slashing
import (
"testing"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func TestGetSetValidatorSlashingPeriod(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
addr := sdk.ConsAddress(addrs[0])
height := int64(5)
require.Panics(t, func() { keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height) })
newPeriod := ValidatorSlashingPeriod{
ValidatorAddr: addr,
StartHeight: height,
EndHeight: height + 10,
SlashedSoFar: sdk.ZeroDec(),
}
keeper.addOrUpdateValidatorSlashingPeriod(ctx, newPeriod)
// Get at start height
retrieved := keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height)
require.Equal(t, newPeriod, retrieved)
// Get after start height (works)
retrieved = keeper.getValidatorSlashingPeriodForHeight(ctx, addr, int64(6))
require.Equal(t, newPeriod, retrieved)
// Get before start height (panic)
require.Panics(t, func() { keeper.getValidatorSlashingPeriodForHeight(ctx, addr, int64(0)) })
// Get after end height (panic)
newPeriod.EndHeight = int64(4)
keeper.addOrUpdateValidatorSlashingPeriod(ctx, newPeriod)
require.Panics(t, func() { keeper.capBySlashingPeriod(ctx, addr, sdk.ZeroDec(), height) })
// Back to old end height
newPeriod.EndHeight = height + 10
keeper.addOrUpdateValidatorSlashingPeriod(ctx, newPeriod)
// Set a new, later period
anotherPeriod := ValidatorSlashingPeriod{
ValidatorAddr: addr,
StartHeight: height + 1,
EndHeight: height + 11,
SlashedSoFar: sdk.ZeroDec(),
}
keeper.addOrUpdateValidatorSlashingPeriod(ctx, anotherPeriod)
// Old period retrieved for prior height
retrieved = keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height)
require.Equal(t, newPeriod, retrieved)
// New period retrieved at new height
retrieved = keeper.getValidatorSlashingPeriodForHeight(ctx, addr, height+1)
require.Equal(t, anotherPeriod, retrieved)
}
func TestValidatorSlashingPeriodCap(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
addr := sdk.ConsAddress(addrs[0])
height := int64(5)
newPeriod := ValidatorSlashingPeriod{
ValidatorAddr: addr,
StartHeight: height,
EndHeight: height + 10,
SlashedSoFar: sdk.ZeroDec(),
}
keeper.addOrUpdateValidatorSlashingPeriod(ctx, newPeriod)
half := sdk.NewDec(1).Quo(sdk.NewDec(2))
// First slash should be full
fractionA := keeper.capBySlashingPeriod(ctx, addr, half, height)
require.True(t, fractionA.Equal(half))
// Second slash should be capped
fractionB := keeper.capBySlashingPeriod(ctx, addr, half, height)
require.True(t, fractionB.Equal(sdk.ZeroDec()))
// Third slash should be capped to difference
fractionC := keeper.capBySlashingPeriod(ctx, addr, sdk.OneDec(), height)
require.True(t, fractionC.Equal(half))
}

View File

@ -4,6 +4,7 @@ import (
"encoding/hex"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
@ -30,10 +31,10 @@ var (
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"),
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"),
}
addrs = []sdk.AccAddress{
sdk.AccAddress(pks[0].Address()),
sdk.AccAddress(pks[1].Address()),
sdk.AccAddress(pks[2].Address()),
addrs = []sdk.ValAddress{
sdk.ValAddress(pks[0].Address()),
sdk.ValAddress(pks[1].Address()),
sdk.ValAddress(pks[2].Address()),
}
initCoins = sdk.NewInt(200)
)
@ -61,7 +62,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
ctx := sdk.NewContext(ms, abci.Header{}, false, log.NewTMLogger(os.Stdout))
ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout))
cdc := createTestCodec()
accountMapper := auth.NewAccountMapper(cdc, keyAcc, auth.ProtoBaseAccount)
ck := bank.NewKeeper(accountMapper)
@ -75,7 +76,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, para
require.Nil(t, err)
for _, addr := range addrs {
_, _, err = ck.AddCoins(ctx, addr, sdk.Coins{
_, _, err = ck.AddCoins(ctx, sdk.AccAddress(addr), sdk.Coins{
{sk.GetParams(ctx).BondDenom, initCoins},
})
}
@ -99,12 +100,20 @@ func testAddr(addr string) sdk.AccAddress {
return res
}
func newTestMsgCreateValidator(address sdk.AccAddress, pubKey crypto.PubKey, amt sdk.Int) stake.MsgCreateValidator {
func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt sdk.Int) stake.MsgCreateValidator {
return stake.MsgCreateValidator{
Description: stake.Description{},
DelegatorAddr: address,
DelegatorAddr: sdk.AccAddress(address),
ValidatorAddr: address,
PubKey: pubKey,
Delegation: sdk.Coin{"steak", amt},
}
}
func newTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, delAmount sdk.Int) stake.MsgDelegate {
return stake.MsgDelegate{
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
Delegation: sdk.Coin{"steak", delAmount},
}
}

View File

@ -17,12 +17,12 @@ func TestBeginBlocker(t *testing.T) {
addr, pk, amt := addrs[2], pks[2], sdk.NewInt(100)
// bond the validator
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, pk, amt))
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(sdk.ValAddress(addr), pk, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
require.Equal(t, ck.GetCoins(ctx, sdk.AccAddress(addr)), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, sdk.ValAddress(addr)).GetPower()))
val := abci.Validator{
Address: pk.Address(),
@ -40,7 +40,7 @@ func TestBeginBlocker(t *testing.T) {
}
BeginBlocker(ctx, req, keeper)
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ValAddress(pk.Address()))
info, found := keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(pk.Address()))
require.True(t, found)
require.Equal(t, ctx.BlockHeight(), info.StartHeight)
require.Equal(t, int64(1), info.IndexOffset)

View File

@ -79,7 +79,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer {
//__________________________________________________________________________________________
func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper,
addr sdk.AccAddress, expFound bool) Validator {
addr sdk.ValAddress, expFound bool) Validator {
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
validator, found := keeper.GetValidator(ctxCheck, addr)
@ -89,8 +89,8 @@ func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper,
}
func checkDelegation(
t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr,
validatorAddr sdk.AccAddress, expFound bool, expShares sdk.Dec,
t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr sdk.AccAddress,
validatorAddr sdk.ValAddress, expFound bool, expShares sdk.Dec,
) {
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
@ -128,55 +128,57 @@ func TestStakeMsgs(t *testing.T) {
// create validator
description := NewDescription("foo_moniker", "", "", "")
createValidatorMsg := NewMsgCreateValidator(
addr1, priv1.PubKey(), bondCoin, description,
sdk.ValAddress(addr1), priv1.PubKey(), bondCoin, description,
)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, true, priv1)
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin)})
mApp.BeginBlock(abci.RequestBeginBlock{})
validator := checkValidator(t, mApp, keeper, addr1, true)
require.Equal(t, addr1, validator.Operator)
validator := checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true)
require.Equal(t, sdk.ValAddress(addr1), validator.Operator)
require.Equal(t, sdk.Bonded, validator.Status)
require.True(sdk.DecEq(t, sdk.NewDec(10), validator.BondedTokens()))
// addr1 create validator on behalf of addr2
createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(addr1, addr2, priv2.PubKey(), bondCoin, description)
createValidatorMsgOnBehalfOf := NewMsgCreateValidatorOnBehalfOf(
addr1, sdk.ValAddress(addr2), priv2.PubKey(), bondCoin, description,
)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, priv1, priv2)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, true, priv1, priv2)
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin).Minus(bondCoin)})
mApp.BeginBlock(abci.RequestBeginBlock{})
validator = checkValidator(t, mApp, keeper, addr2, true)
require.Equal(t, addr2, validator.Operator)
validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr2), true)
require.Equal(t, sdk.ValAddress(addr2), validator.Operator)
require.Equal(t, sdk.Bonded, validator.Status)
require.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens))
// check the bond that should have been created as well
checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewDec(10))
checkDelegation(t, mApp, keeper, addr1, sdk.ValAddress(addr1), true, sdk.NewDec(10))
// edit the validator
description = NewDescription("bar_moniker", "", "", "")
editValidatorMsg := NewMsgEditValidator(addr1, description)
editValidatorMsg := NewMsgEditValidator(sdk.ValAddress(addr1), description)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{2}, true, priv1)
validator = checkValidator(t, mApp, keeper, addr1, true)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{2}, true, true, priv1)
validator = checkValidator(t, mApp, keeper, sdk.ValAddress(addr1), true)
require.Equal(t, description, validator.Description)
// delegate
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
delegateMsg := NewMsgDelegate(addr2, addr1, bondCoin)
delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, priv2)
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, true, priv2)
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewDec(10))
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, sdk.NewDec(10))
// begin unbonding
beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewDec(10))
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, priv2)
beginUnbondingMsg := NewMsgBeginUnbonding(addr2, sdk.ValAddress(addr1), sdk.NewDec(10))
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, true, priv2)
// delegation should exist anymore
checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Dec{})
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{})
// balance should be the same because bonding not yet complete
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})

View File

@ -17,11 +17,11 @@ import (
// GetCmdQueryValidator implements the validator query command.
func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "validator [owner-addr]",
Use: "validator [operator-addr]",
Short: "Query a validator",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
addr, err := sdk.AccAddressFromBech32(args[0])
addr, err := sdk.ValAddressFromBech32(args[0])
if err != nil {
return err
}
@ -120,7 +120,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
Use: "delegation",
Short: "Query a delegation based on address and validator address",
RunE: func(cmd *cobra.Command, args []string) error {
valAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
}
@ -222,7 +222,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
Use: "unbonding-delegation",
Short: "Query an unbonding-delegation record based on delegator and validator address",
RunE: func(cmd *cobra.Command, args []string) error {
valAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
}
@ -321,12 +321,12 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
Use: "redelegation",
Short: "Query a redelegation record based on delegator and a source and destination validator address",
RunE: func(cmd *cobra.Command, args []string) error {
valSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
valSrcAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
if err != nil {
return err
}
valDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
valDstAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
if err != nil {
return err
}

View File

@ -40,7 +40,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
return err
}
validatorAddr, err := cliCtx.GetFromAddress()
valAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
@ -50,7 +50,7 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
return fmt.Errorf("must use --pubkey flag")
}
pk, err := sdk.GetValPubKeyBech32(pkStr)
pk, err := sdk.GetConsPubKeyBech32(pkStr)
if err != nil {
return err
}
@ -68,14 +68,14 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
var msg sdk.Msg
if viper.GetString(FlagAddressDelegator) != "" {
delegatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator))
delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator))
if err != nil {
return err
}
msg = stake.NewMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, amount, description)
msg = stake.NewMsgCreateValidatorOnBehalfOf(delAddr, sdk.ValAddress(valAddr), pk, amount, description)
} else {
msg = stake.NewMsgCreateValidator(validatorAddr, pk, amount, description)
msg = stake.NewMsgCreateValidator(sdk.ValAddress(valAddr), pk, amount, description)
}
// build and sign the transaction, then broadcast to Tendermint
@ -103,7 +103,7 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
validatorAddr, err := cliCtx.GetFromAddress()
valAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
@ -114,7 +114,8 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
Website: viper.GetString(FlagWebsite),
Details: viper.GetString(FlagDetails),
}
msg := stake.NewMsgEditValidator(validatorAddr, description)
msg := stake.NewMsgEditValidator(sdk.ValAddress(valAddr), description)
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
@ -143,17 +144,17 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
return err
}
delegatorAddr, err := cliCtx.GetFromAddress()
delAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
}
msg := stake.NewMsgDelegate(delegatorAddr, validatorAddr, amount)
msg := stake.NewMsgDelegate(delAddr, valAddr, amount)
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
@ -195,17 +196,18 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
var err error
delegatorAddr, err := cliCtx.GetFromAddress()
delAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
valSrcAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
if err != nil {
return err
}
validatorDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
valDstAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
if err != nil {
return err
}
@ -215,13 +217,13 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
sharesPercentStr := viper.GetString(FlagSharesPercent)
sharesAmount, err := getShares(
storeName, cdc, sharesAmountStr, sharesPercentStr,
delegatorAddr, validatorSrcAddr,
delAddr, valSrcAddr,
)
if err != nil {
return err
}
msg := stake.NewMsgBeginRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr, sharesAmount)
msg := stake.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, sharesAmount)
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
@ -238,7 +240,7 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
// TODO: Make this pass gocyclo linting
func getShares(
storeName string, cdc *wire.Codec, sharesAmountStr,
sharesPercentStr string, delegatorAddr, validatorAddr sdk.AccAddress,
sharesPercentStr string, delAddr sdk.AccAddress, valAddr sdk.ValAddress,
) (sharesAmount sdk.Dec, err error) {
switch {
case sharesAmountStr != "" && sharesPercentStr != "":
@ -264,7 +266,7 @@ func getShares(
}
// make a query to get the existing delegation shares
key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
key := stake.GetDelegationKey(delAddr, valAddr)
cliCtx := context.NewCLIContext().
WithCodec(cdc).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
@ -294,22 +296,22 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command {
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
delegatorAddr, err := cliCtx.GetFromAddress()
delAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorSrcAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
valSrcAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorSrc))
if err != nil {
return err
}
validatorDstAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
valDstAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidatorDst))
if err != nil {
return err
}
msg := stake.NewMsgCompleteRedelegate(delegatorAddr, validatorSrcAddr, validatorDstAddr)
msg := stake.NewMsgCompleteRedelegate(delAddr, valSrcAddr, valDstAddr)
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
@ -349,12 +351,12 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
delegatorAddr, err := cliCtx.GetFromAddress()
delAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
}
@ -364,13 +366,13 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
sharesPercentStr := viper.GetString(FlagSharesPercent)
sharesAmount, err := getShares(
storeName, cdc, sharesAmountStr, sharesPercentStr,
delegatorAddr, validatorAddr,
delAddr, valAddr,
)
if err != nil {
return err
}
msg := stake.NewMsgBeginUnbonding(delegatorAddr, validatorAddr, sharesAmount)
msg := stake.NewMsgBeginUnbonding(delAddr, valAddr, sharesAmount)
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})
@ -395,17 +397,17 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command {
WithLogger(os.Stdout).
WithAccountDecoder(authcmd.GetAccountDecoder(cdc))
delegatorAddr, err := cliCtx.GetFromAddress()
delAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
validatorAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressValidator))
valAddr, err := sdk.ValAddressFromBech32(viper.GetString(FlagAddressValidator))
if err != nil {
return err
}
msg := stake.NewMsgCompleteUnbonding(delegatorAddr, validatorAddr)
msg := stake.NewMsgCompleteUnbonding(delAddr, valAddr)
// build and sign the transaction, then broadcast to Tendermint
return utils.SendTx(txCtx, cliCtx, []sdk.Msg{msg})

View File

@ -87,7 +87,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router, cdc *wire.Cod
// defines a delegation without type Rat for shares
type DelegationWithoutRat struct {
DelegatorAddr sdk.AccAddress `json:"delegator_addr"`
ValidatorAddr sdk.AccAddress `json:"validator_addr"`
ValidatorAddr sdk.ValAddress `json:"validator_addr"`
Shares string `json:"shares"`
Height int64 `json:"height"`
}
@ -103,14 +103,14 @@ type DelegationSummary struct {
func delegatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var validatorAddr sdk.AccAddress
var valAddr sdk.ValAddress
var delegationSummary = DelegationSummary{}
// read parameters
vars := mux.Vars(r)
bech32delegator := vars["delegatorAddr"]
delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator)
delAddr, err := sdk.AccAddressFromBech32(bech32delegator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
@ -126,10 +126,10 @@ func delegatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler
}
for _, validator := range validators {
validatorAddr = validator.Operator
valAddr = validator.Operator
// Delegations
delegations, statusCode, errMsg, err := getDelegatorDelegations(cliCtx, cdc, delegatorAddr, validatorAddr)
delegations, statusCode, errMsg, err := getDelegatorDelegations(cliCtx, cdc, delAddr, valAddr)
if err != nil {
w.WriteHeader(statusCode)
w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error())))
@ -140,7 +140,7 @@ func delegatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler
}
// Undelegations
unbondingDelegation, statusCode, errMsg, err := getDelegatorUndelegations(cliCtx, cdc, delegatorAddr, validatorAddr)
unbondingDelegation, statusCode, errMsg, err := getDelegatorUndelegations(cliCtx, cdc, delAddr, valAddr)
if err != nil {
w.WriteHeader(statusCode)
w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error())))
@ -153,7 +153,7 @@ func delegatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler
// Redelegations
// only querying redelegations to a validator as this should give us already all relegations
// if we also would put in redelegations from, we would have every redelegation double
redelegations, statusCode, errMsg, err := getDelegatorRedelegations(cliCtx, cdc, delegatorAddr, validatorAddr)
redelegations, statusCode, errMsg, err := getDelegatorRedelegations(cliCtx, cdc, delAddr, valAddr)
if err != nil {
w.WriteHeader(statusCode)
w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error())))
@ -259,22 +259,21 @@ func unbondingDelegationsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) h
bech32delegator := vars["delegatorAddr"]
bech32validator := vars["validatorAddr"]
delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator)
delAddr, err := sdk.AccAddressFromBech32(bech32delegator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
validatorAddr, err := sdk.AccAddressFromBech32(bech32validator)
valAddr, err := sdk.ValAddressFromBech32(bech32validator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
validatorAddrAcc := sdk.AccAddress(validatorAddr)
key := stake.GetUBDKey(delegatorAddr, validatorAddrAcc)
key := stake.GetUBDKey(delAddr, valAddr)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
@ -318,22 +317,21 @@ func delegationHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handle
bech32delegator := vars["delegatorAddr"]
bech32validator := vars["validatorAddr"]
delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator)
delAddr, err := sdk.AccAddressFromBech32(bech32delegator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
validatorAddr, err := sdk.AccAddressFromBech32(bech32validator)
valAddr, err := sdk.ValAddressFromBech32(bech32validator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return
}
validatorAddrAcc := sdk.AccAddress(validatorAddr)
key := stake.GetDelegationKey(delegatorAddr, validatorAddrAcc)
key := stake.GetDelegationKey(delAddr, valAddr)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
@ -377,7 +375,7 @@ func delegationHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handle
func delegatorValidatorsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var validatorAccAddr sdk.AccAddress
var valAddr sdk.ValAddress
var bondedValidators []types.BechValidator
// read parameters
@ -412,9 +410,9 @@ func delegatorValidatorsHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) ht
for _, validator := range validators {
// get all transactions from the delegator to val and append
validatorAccAddr = validator.Operator
valAddr = validator.Operator
validator, statusCode, errMsg, errRes := getDelegatorValidator(cliCtx, cdc, delegatorAddr, validatorAccAddr)
validator, statusCode, errMsg, errRes := getDelegatorValidator(cliCtx, cdc, delegatorAddr, valAddr)
if errRes != nil {
w.WriteHeader(statusCode)
w.Write([]byte(fmt.Sprintf("%s%s", errMsg, errRes.Error())))
@ -444,8 +442,8 @@ func delegatorValidatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) htt
bech32delegator := vars["delegatorAddr"]
bech32validator := vars["validatorAddr"]
delegatorAddr, err := sdk.AccAddressFromBech32(bech32delegator)
validatorAccAddr, err := sdk.AccAddressFromBech32(bech32validator)
delAddr, err := sdk.AccAddressFromBech32(bech32delegator)
valAddr, err := sdk.ValAddressFromBech32(bech32validator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(fmt.Sprintf("Error: %s", err.Error())))
@ -454,7 +452,7 @@ func delegatorValidatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) htt
// Check if there if the delegator is bonded or redelegated to the validator
validator, statusCode, errMsg, err := getDelegatorValidator(cliCtx, cdc, delegatorAddr, validatorAccAddr)
validator, statusCode, errMsg, err := getDelegatorValidator(cliCtx, cdc, delAddr, valAddr)
if err != nil {
w.WriteHeader(statusCode)
w.Write([]byte(fmt.Sprintf("%s%s", errMsg, err.Error())))
@ -516,14 +514,15 @@ func validatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler
// read parameters
vars := mux.Vars(r)
bech32validatorAddr := vars["addr"]
valAddress, err := sdk.AccAddressFromBech32(bech32validatorAddr)
valAddr, err := sdk.ValAddressFromBech32(bech32validatorAddr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(fmt.Sprintf("error: %s", err.Error())))
return
}
key := stake.GetValidatorKey(valAddress)
key := stake.GetValidatorKey(valAddr)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
@ -538,7 +537,7 @@ func validatorHandlerFn(cliCtx context.CLIContext, cdc *wire.Codec) http.Handler
return
}
validator, err := types.UnmarshalValidator(cdc, valAddress, res)
validator, err := types.UnmarshalValidator(cdc, valAddr, res)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))

View File

@ -6,6 +6,7 @@ import (
"io/ioutil"
"net/http"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/crypto/keys"
@ -60,6 +61,7 @@ type EditDelegationsBody struct {
AccountNumber int64 `json:"account_number"`
Sequence int64 `json:"sequence"`
Gas int64 `json:"gas"`
GasAdjustment string `json:"gas_adjustment"`
Delegations []msgDelegationsInput `json:"delegations"`
BeginUnbondings []msgBeginUnbondingInput `json:"begin_unbondings"`
CompleteUnbondings []msgCompleteUnbondingInput `json:"complete_unbondings"`
@ -104,26 +106,26 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
i := 0
for _, msg := range m.Delegations {
delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
return
}
validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr)
valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
return
}
messages[i] = stake.MsgDelegate{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
Delegation: msg.Delegation,
}
@ -131,38 +133,38 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
}
for _, msg := range m.BeginRedelegates {
delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
return
}
validatorSrcAddr, err := sdk.AccAddressFromBech32(msg.ValidatorSrcAddr)
valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
validatorDstAddr, err := sdk.AccAddressFromBech32(msg.ValidatorDstAddr)
valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
shares, err := sdk.NewDecFromStr(msg.SharesAmount)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))
return
}
messages[i] = stake.MsgBeginRedelegate{
DelegatorAddr: delegatorAddr,
ValidatorSrcAddr: validatorSrcAddr,
ValidatorDstAddr: validatorDstAddr,
DelegatorAddr: delAddr,
ValidatorSrcAddr: valSrcAddr,
ValidatorDstAddr: valDstAddr,
SharesAmount: shares,
}
@ -170,64 +172,65 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
}
for _, msg := range m.CompleteRedelegates {
delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
return
}
validatorSrcAddr, err := sdk.AccAddressFromBech32(msg.ValidatorSrcAddr)
valSrcAddr, err := sdk.ValAddressFromBech32(msg.ValidatorSrcAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
validatorDstAddr, err := sdk.AccAddressFromBech32(msg.ValidatorDstAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
valDstAddr, err := sdk.ValAddressFromBech32(msg.ValidatorDstAddr)
if err != nil {
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
return
}
messages[i] = stake.MsgCompleteRedelegate{
DelegatorAddr: delegatorAddr,
ValidatorSrcAddr: validatorSrcAddr,
ValidatorDstAddr: validatorDstAddr,
DelegatorAddr: delAddr,
ValidatorSrcAddr: valSrcAddr,
ValidatorDstAddr: valDstAddr,
}
i++
}
for _, msg := range m.BeginUnbondings {
delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
return
}
validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr)
valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
shares, err := sdk.NewDecFromStr(msg.SharesAmount)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode shares amount. Error: %s", err.Error()))
return
}
messages[i] = stake.MsgBeginUnbonding{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
SharesAmount: shares,
}
@ -235,26 +238,26 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
}
for _, msg := range m.CompleteUnbondings {
delegatorAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
delAddr, err := sdk.AccAddressFromBech32(msg.DelegatorAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode delegator. Error: %s", err.Error()))
return
}
validatorAddr, err := sdk.AccAddressFromBech32(msg.ValidatorAddr)
valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddr)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
utils.WriteErrorResponse(w, http.StatusInternalServerError, fmt.Sprintf("Couldn't decode validator. Error: %s", err.Error()))
return
}
if !bytes.Equal(info.GetPubKey().Address(), delegatorAddr) {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, "Must use own delegator address")
if !bytes.Equal(info.GetPubKey().Address(), delAddr) {
utils.WriteErrorResponse(w, http.StatusUnauthorized, "Must use own delegator address")
return
}
messages[i] = stake.MsgCompleteUnbonding{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
}
i++
@ -275,10 +278,20 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
m.Sequence++
if m.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, m.Password, []sdk.Msg{msg})
adjustment, ok := utils.ParseFloat64OrReturnBadRequest(w, m.GasAdjustment, client.DefaultGasAdjustment)
if !ok {
return
}
cliCtx = cliCtx.WithGasAdjustment(adjustment)
if utils.HasDryRunArg(r) || m.Gas == 0 {
newCtx, err := utils.EnrichCtxWithGas(txCtx, cliCtx, m.LocalAccountName, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
if utils.HasDryRunArg(r) {
utils.WriteSimulationResponse(w, txCtx.Gas)
return
}
txCtx = newCtx
@ -286,7 +299,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
txBytes, err := txCtx.BuildAndSign(m.LocalAccountName, m.Password, []sdk.Msg{msg})
if err != nil {
utils.WriteErrorResponse(&w, http.StatusUnauthorized, err.Error())
utils.WriteErrorResponse(w, http.StatusUnauthorized, err.Error())
return
}
@ -300,7 +313,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
for i, txBytes := range signedTxs {
res, err := cliCtx.BroadcastTx(txBytes)
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
@ -309,7 +322,7 @@ func delegationsRequestHandlerFn(cdc *wire.Codec, kb keys.Keybase, cliCtx contex
output, err := wire.MarshalJSONIndent(cdc, results[:])
if err != nil {
utils.WriteErrorResponse(&w, http.StatusInternalServerError, err.Error())
utils.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}

View File

@ -24,10 +24,10 @@ func contains(stringSlice []string, txType string) bool {
return false
}
func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) (
func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (
bech32Validator types.BechValidator, httpStatusCode int, errMsg string, err error) {
key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
key := stake.GetDelegationKey(delAddr, valAddr)
res, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return types.BechValidator{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err
@ -36,7 +36,7 @@ func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegator
return types.BechValidator{}, http.StatusNoContent, "", nil
}
key = stake.GetValidatorKey(validatorAddr)
key = stake.GetValidatorKey(valAddr)
res, err = cliCtx.QueryStore(key, storeName)
if err != nil {
return types.BechValidator{}, http.StatusInternalServerError, "couldn't query validator. Error: ", err
@ -44,7 +44,7 @@ func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegator
if len(res) == 0 {
return types.BechValidator{}, http.StatusNoContent, "", nil
}
validator, err := types.UnmarshalValidator(cdc, validatorAddr, res)
validator, err := types.UnmarshalValidator(cdc, valAddr, res)
if err != nil {
return types.BechValidator{}, http.StatusBadRequest, "", err
}
@ -56,9 +56,11 @@ func getDelegatorValidator(cliCtx context.CLIContext, cdc *wire.Codec, delegator
return bech32Validator, http.StatusOK, "", nil
}
func getDelegatorDelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) (
func getDelegatorDelegations(
cliCtx context.CLIContext, cdc *wire.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (
outputDelegation DelegationWithoutRat, httpStatusCode int, errMsg string, err error) {
delegationKey := stake.GetDelegationKey(delegatorAddr, validatorAddr)
delegationKey := stake.GetDelegationKey(delAddr, valAddr)
marshalledDelegation, err := cliCtx.QueryStore(delegationKey, storeName)
if err != nil {
return DelegationWithoutRat{}, http.StatusInternalServerError, "couldn't query delegation. Error: ", err
@ -83,9 +85,11 @@ func getDelegatorDelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegat
return outputDelegation, http.StatusOK, "", nil
}
func getDelegatorUndelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) (
func getDelegatorUndelegations(
cliCtx context.CLIContext, cdc *wire.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (
unbonds types.UnbondingDelegation, httpStatusCode int, errMsg string, err error) {
undelegationKey := stake.GetUBDKey(delegatorAddr, validatorAddr)
undelegationKey := stake.GetUBDKey(delAddr, valAddr)
marshalledUnbondingDelegation, err := cliCtx.QueryStore(undelegationKey, storeName)
if err != nil {
return types.UnbondingDelegation{}, http.StatusInternalServerError, "couldn't query unbonding-delegation. Error: ", err
@ -102,10 +106,11 @@ func getDelegatorUndelegations(cliCtx context.CLIContext, cdc *wire.Codec, deleg
return unbondingDelegation, http.StatusOK, "", nil
}
func getDelegatorRedelegations(cliCtx context.CLIContext, cdc *wire.Codec, delegatorAddr sdk.AccAddress, validatorAddr sdk.AccAddress) (
func getDelegatorRedelegations(
cliCtx context.CLIContext, cdc *wire.Codec, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (
regelegations types.Redelegation, httpStatusCode int, errMsg string, err error) {
key := stake.GetREDsByDelToValDstIndexKey(delegatorAddr, validatorAddr)
key := stake.GetREDsByDelToValDstIndexKey(delAddr, valAddr)
marshalledRedelegations, err := cliCtx.QueryStore(key, storeName)
if err != nil {
return types.Redelegation{}, http.StatusInternalServerError, "couldn't query redelegation. Error: ", err

View File

@ -23,8 +23,8 @@ func TestInitGenesis(t *testing.T) {
var delegations []Delegation
validators := []Validator{
NewValidator(keep.Addrs[0], keep.PKs[0], Description{Moniker: "hoop"}),
NewValidator(keep.Addrs[1], keep.PKs[1], Description{Moniker: "bloop"}),
NewValidator(sdk.ValAddress(keep.Addrs[0]), keep.PKs[0], Description{Moniker: "hoop"}),
NewValidator(sdk.ValAddress(keep.Addrs[1]), keep.PKs[1], Description{Moniker: "bloop"}),
}
genesisState := types.NewGenesisState(pool, params, validators, delegations)
_, err := InitGenesis(ctx, keeper, genesisState)
@ -43,12 +43,12 @@ func TestInitGenesis(t *testing.T) {
require.NoError(t, err)
// now make sure the validators are bonded and intra-tx counters are correct
resVal, found := keeper.GetValidator(ctx, keep.Addrs[0])
resVal, found := keeper.GetValidator(ctx, sdk.ValAddress(keep.Addrs[0]))
require.True(t, found)
require.Equal(t, sdk.Bonded, resVal.Status)
require.Equal(t, int16(0), resVal.BondIntraTxCounter)
resVal, found = keeper.GetValidator(ctx, keep.Addrs[1])
resVal, found = keeper.GetValidator(ctx, sdk.ValAddress(keep.Addrs[1]))
require.True(t, found)
require.Equal(t, sdk.Bonded, resVal.Status)
require.Equal(t, int16(1), resVal.BondIntraTxCounter)
@ -76,7 +76,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) {
validators := make([]Validator, size)
for i := range validators {
validators[i] = NewValidator(keep.Addrs[i], keep.PKs[i], Description{Moniker: fmt.Sprintf("#%d", i)})
validators[i] = NewValidator(sdk.ValAddress(keep.Addrs[i]), keep.PKs[i], Description{Moniker: fmt.Sprintf("#%d", i)})
validators[i].Status = sdk.Bonded
if i < 100 {

View File

@ -1,6 +1,7 @@
package stake
import (
"bytes"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -128,17 +129,19 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe
}
func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper) sdk.Result {
validator, found := k.GetValidator(ctx, msg.ValidatorAddr)
if !found {
return ErrNoValidatorFound(k.Codespace()).Result()
}
if msg.Delegation.Denom != k.GetParams(ctx).BondDenom {
return ErrBadDenom(k.Codespace()).Result()
}
if validator.Jailed {
if validator.Jailed && !bytes.Equal(validator.Operator, msg.DelegatorAddr) {
return ErrValidatorJailed(k.Codespace()).Result()
}
_, err := k.Delegate(ctx, msg.DelegatorAddr, msg.Delegation, validator, true)
if err != nil {
return err.Result()
@ -149,6 +152,7 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper)
tags.Delegator, []byte(msg.DelegatorAddr.String()),
tags.DstValidator, []byte(msg.ValidatorAddr.String()),
)
return sdk.Result{
Tags: tags,
}

View File

@ -16,23 +16,23 @@ import (
//______________________________________________________________________
func newTestMsgCreateValidator(address sdk.AccAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator {
func newTestMsgCreateValidator(address sdk.ValAddress, pubKey crypto.PubKey, amt int64) MsgCreateValidator {
return types.NewMsgCreateValidator(address, pubKey, sdk.Coin{"steak", sdk.NewInt(amt)}, Description{})
}
func newTestMsgDelegate(delegatorAddr, validatorAddr sdk.AccAddress, amt int64) MsgDelegate {
func newTestMsgDelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amt int64) MsgDelegate {
return MsgDelegate{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
Delegation: sdk.Coin{"steak", sdk.NewInt(amt)},
}
}
func newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr sdk.AccAddress, valPubKey crypto.PubKey, amt int64) MsgCreateValidator {
func newTestMsgCreateValidatorOnBehalfOf(delAddr sdk.AccAddress, valAddr sdk.ValAddress, valPubKey crypto.PubKey, amt int64) MsgCreateValidator {
return MsgCreateValidator{
Description: Description{},
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
PubKey: valPubKey,
Delegation: sdk.Coin{"steak", sdk.NewInt(amt)},
}
@ -49,7 +49,7 @@ func setInstantUnbondPeriod(keeper keep.Keeper, ctx sdk.Context) types.Params {
//______________________________________________________________________
func TestValidatorByPowerIndex(t *testing.T) {
validatorAddr, validatorAddr3 := keep.Addrs[0], keep.Addrs[1]
validatorAddr, validatorAddr3 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
initBond := int64(1000000)
ctx, _, keeper := keep.CreateTestInput(t, false, initBond)
@ -61,7 +61,7 @@ func TestValidatorByPowerIndex(t *testing.T) {
require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
// verify the self-delegation exists
bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr)
bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
require.True(t, found)
gotBond := bond.Shares.RoundInt64()
require.Equal(t, initBond, gotBond,
@ -110,8 +110,8 @@ func TestValidatorByPowerIndex(t *testing.T) {
require.Equal(t, power2, power3)
// unbond self-delegation
msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(1000000))
msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr)
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(1000000))
msgCompleteUnbonding := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr)
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
require.True(t, got.IsOK(), "expected msg to be ok, got %v", got)
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
@ -126,7 +126,7 @@ func TestValidatorByPowerIndex(t *testing.T) {
func TestDuplicatesMsgCreateValidator(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
addr1, addr2 := keep.Addrs[0], keep.Addrs[1]
addr1, addr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
pk1, pk2 := keep.PKs[0], keep.PKs[1]
msgCreateValidator1 := newTestMsgCreateValidator(addr1, pk1, 10)
@ -170,7 +170,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) {
func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr := keep.Addrs[0]
validatorAddr := sdk.ValAddress(keep.Addrs[0])
delegatorAddr := keep.Addrs[1]
pk := keep.PKs[0]
msgCreateValidatorOnBehalfOf := newTestMsgCreateValidatorOnBehalfOf(delegatorAddr, validatorAddr, pk, 10)
@ -193,13 +193,104 @@ func TestDuplicatesMsgCreateValidatorOnBehalfOf(t *testing.T) {
require.False(t, got.IsOK(), "%v", got)
}
func TestLegacyValidatorDelegations(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, int64(1000))
setInstantUnbondPeriod(keeper, ctx)
bondAmount := int64(10)
valAddr, valPubKey := sdk.ValAddress(keep.Addrs[0]), keep.PKs[0]
delAddr := keep.Addrs[1]
// create validator
msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount)
got := handleMsgCreateValidator(ctx, msgCreateVal, keeper)
require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got)
// verify the validator exists and has the correct attributes
validator, found := keeper.GetValidator(ctx, valAddr)
require.True(t, found)
require.Equal(t, sdk.Bonded, validator.Status)
require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64())
require.Equal(t, bondAmount, validator.BondedTokens().RoundInt64())
// delegate tokens to the validator
msgDelegate := newTestMsgDelegate(delAddr, valAddr, bondAmount)
got = handleMsgDelegate(ctx, msgDelegate, keeper)
require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got)
// verify validator bonded shares
validator, found = keeper.GetValidator(ctx, valAddr)
require.True(t, found)
require.Equal(t, bondAmount*2, validator.DelegatorShares.RoundInt64())
require.Equal(t, bondAmount*2, validator.BondedTokens().RoundInt64())
// unbond validator total self-delegations (which should jail the validator)
unbondShares := sdk.NewDec(10)
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(valAddr), valAddr, unbondShares)
msgCompleteUnbonding := NewMsgCompleteUnbonding(sdk.AccAddress(valAddr), valAddr)
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got %v", got)
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
require.True(t, got.IsOK(), "expected complete unbonding validator msg to be ok, got %v", got)
// verify the validator record still exists, is jailed, and has correct tokens
validator, found = keeper.GetValidator(ctx, valAddr)
require.True(t, found)
require.True(t, validator.Jailed)
require.Equal(t, sdk.NewDec(10), validator.Tokens)
// verify delegation still exists
bond, found := keeper.GetDelegation(ctx, delAddr, valAddr)
require.True(t, found)
require.Equal(t, bondAmount, bond.Shares.RoundInt64())
require.Equal(t, bondAmount, validator.DelegatorShares.RoundInt64())
// verify a delegator cannot create a new delegation to the now jailed validator
msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount)
got = handleMsgDelegate(ctx, msgDelegate, keeper)
require.False(t, got.IsOK(), "expected delegation to not be ok, got %v", got)
// verify the validator can still self-delegate
msgSelfDelegate := newTestMsgDelegate(sdk.AccAddress(valAddr), valAddr, bondAmount)
got = handleMsgDelegate(ctx, msgSelfDelegate, keeper)
require.True(t, got.IsOK(), "expected delegation to not be ok, got %v", got)
// verify validator bonded shares
validator, found = keeper.GetValidator(ctx, valAddr)
require.True(t, found)
require.Equal(t, bondAmount*2, validator.DelegatorShares.RoundInt64())
require.Equal(t, bondAmount*2, validator.Tokens.RoundInt64())
// unjail the validator now that is has non-zero self-delegated shares
keeper.Unjail(ctx, valPubKey)
// verify the validator can now accept delegations
msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount)
got = handleMsgDelegate(ctx, msgDelegate, keeper)
require.True(t, got.IsOK(), "expected delegation to be ok, got %v", got)
// verify validator bonded shares
validator, found = keeper.GetValidator(ctx, valAddr)
require.True(t, found)
require.Equal(t, bondAmount*3, validator.DelegatorShares.RoundInt64())
require.Equal(t, bondAmount*3, validator.Tokens.RoundInt64())
// verify new delegation
bond, found = keeper.GetDelegation(ctx, delAddr, valAddr)
require.True(t, found)
require.Equal(t, bondAmount*2, bond.Shares.RoundInt64())
require.Equal(t, bondAmount*3, validator.DelegatorShares.RoundInt64())
}
func TestIncrementsMsgDelegate(t *testing.T) {
initBond := int64(1000)
ctx, accMapper, keeper := keep.CreateTestInput(t, false, initBond)
params := keeper.GetParams(ctx)
bondAmount := int64(10)
validatorAddr, delegatorAddr := keep.Addrs[0], keep.Addrs[1]
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
// first create validator
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], bondAmount)
@ -215,7 +306,7 @@ func TestIncrementsMsgDelegate(t *testing.T) {
_, found = keeper.GetDelegation(ctx, delegatorAddr, validatorAddr)
require.False(t, found)
bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr)
bond, found := keeper.GetDelegation(ctx, sdk.AccAddress(validatorAddr), validatorAddr)
require.True(t, found)
require.Equal(t, bondAmount, bond.Shares.RoundInt64())
@ -271,7 +362,7 @@ func TestIncrementsMsgUnbond(t *testing.T) {
denom := params.BondDenom
// create validator, delegate
validatorAddr, delegatorAddr := keep.Addrs[0], keep.Addrs[1]
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], initBond)
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
@ -367,7 +458,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) {
ctx, accMapper, keeper := keep.CreateTestInput(t, false, initBond)
params := setInstantUnbondPeriod(keeper, ctx)
validatorAddrs := []sdk.AccAddress{keep.Addrs[0], keep.Addrs[1], keep.Addrs[2]}
validatorAddrs := []sdk.ValAddress{sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), sdk.ValAddress(keep.Addrs[2])}
delegatorAddrs := []sdk.AccAddress{keep.Addrs[3], keep.Addrs[4], keep.Addrs[5]}
// bond them all
@ -414,7 +505,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) {
func TestMultipleMsgDelegate(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr, delegatorAddrs := keep.Addrs[0], keep.Addrs[1:]
validatorAddr, delegatorAddrs := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1:]
_ = setInstantUnbondPeriod(keeper, ctx)
//first make a validator
@ -451,7 +542,7 @@ func TestMultipleMsgDelegate(t *testing.T) {
func TestJailValidator(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr, delegatorAddr := keep.Addrs[0], keep.Addrs[1]
validatorAddr, delegatorAddr := sdk.ValAddress(keep.Addrs[0]), keep.Addrs[1]
_ = setInstantUnbondPeriod(keeper, ctx)
// create the validator
@ -467,8 +558,8 @@ func TestJailValidator(t *testing.T) {
validator, _ := keeper.GetValidator(ctx, validatorAddr)
// unbond the validators bond portion
msgBeginUnbondingValidator := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10))
msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(validatorAddr, validatorAddr)
msgBeginUnbondingValidator := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
msgCompleteUnbondingValidator := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr)
got = handleMsgBeginUnbonding(ctx, msgBeginUnbondingValidator, keeper)
require.True(t, got.IsOK(), "expected no error")
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbondingValidator, keeper)
@ -497,7 +588,7 @@ func TestJailValidator(t *testing.T) {
func TestUnbondingPeriod(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr := keep.Addrs[0]
validatorAddr := sdk.ValAddress(keep.Addrs[0])
// set the unbonding time
params := keeper.GetParams(ctx)
@ -510,12 +601,12 @@ func TestUnbondingPeriod(t *testing.T) {
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
// begin unbonding
msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr, validatorAddr, sdk.NewDec(10))
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr), validatorAddr, sdk.NewDec(10))
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
require.True(t, got.IsOK(), "expected no error")
// cannot complete unbonding at same time
msgCompleteUnbonding := NewMsgCompleteUnbonding(validatorAddr, validatorAddr)
msgCompleteUnbonding := NewMsgCompleteUnbonding(sdk.AccAddress(validatorAddr), validatorAddr)
got = handleMsgCompleteUnbonding(ctx, msgCompleteUnbonding, keeper)
require.True(t, !got.IsOK(), "expected an error")
@ -537,7 +628,7 @@ func TestUnbondingPeriod(t *testing.T) {
func TestRedelegationPeriod(t *testing.T) {
ctx, AccMapper, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr, validatorAddr2 := keep.Addrs[0], keep.Addrs[1]
validatorAddr, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
denom := keeper.GetParams(ctx).BondDenom
// set the unbonding time
@ -549,32 +640,32 @@ func TestRedelegationPeriod(t *testing.T) {
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, keep.PKs[0], 10)
// initial balance
amt1 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins().AmountOf(denom)
amt1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom)
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
// balance should have been subtracted after creation
amt2 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins().AmountOf(denom)
amt2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins().AmountOf(denom)
require.Equal(t, amt1.Sub(sdk.NewInt(10)).Int64(), amt2.Int64(), "expected coins to be subtracted")
msgCreateValidator = newTestMsgCreateValidator(validatorAddr2, keep.PKs[1], 10)
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
bal1 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins()
bal1 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins()
// begin redelegate
msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10))
msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, sdk.NewDec(10))
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
require.True(t, got.IsOK(), "expected no error, %v", got)
// origin account should not lose tokens as with a regular delegation
bal2 := AccMapper.GetAccount(ctx, validatorAddr).GetCoins()
bal2 := AccMapper.GetAccount(ctx, sdk.AccAddress(validatorAddr)).GetCoins()
require.Equal(t, bal1, bal2)
// cannot complete redelegation at same time
msgCompleteRedelegate := NewMsgCompleteRedelegate(validatorAddr, validatorAddr, validatorAddr2)
msgCompleteRedelegate := NewMsgCompleteRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper)
require.True(t, !got.IsOK(), "expected an error")
@ -596,7 +687,9 @@ func TestRedelegationPeriod(t *testing.T) {
func TestTransitiveRedelegation(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr, validatorAddr2, validatorAddr3 := keep.Addrs[0], keep.Addrs[1], keep.Addrs[2]
validatorAddr := sdk.ValAddress(keep.Addrs[0])
validatorAddr2 := sdk.ValAddress(keep.Addrs[1])
validatorAddr3 := sdk.ValAddress(keep.Addrs[2])
// set the unbonding time
params := keeper.GetParams(ctx)
@ -617,17 +710,17 @@ func TestTransitiveRedelegation(t *testing.T) {
require.True(t, got.IsOK(), "expected no error on runMsgCreateValidator")
// begin redelegate
msgBeginRedelegate := NewMsgBeginRedelegate(validatorAddr, validatorAddr, validatorAddr2, sdk.NewDec(10))
msgBeginRedelegate := NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2, sdk.NewDec(10))
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
require.True(t, got.IsOK(), "expected no error, %v", got)
// cannot redelegation to next validator while first delegation exists
msgBeginRedelegate = NewMsgBeginRedelegate(validatorAddr, validatorAddr2, validatorAddr3, sdk.NewDec(10))
msgBeginRedelegate = NewMsgBeginRedelegate(sdk.AccAddress(validatorAddr), validatorAddr2, validatorAddr3, sdk.NewDec(10))
got = handleMsgBeginRedelegate(ctx, msgBeginRedelegate, keeper)
require.True(t, !got.IsOK(), "expected an error, msg: %v", msgBeginRedelegate)
// complete first redelegation
msgCompleteRedelegate := NewMsgCompleteRedelegate(validatorAddr, validatorAddr, validatorAddr2)
msgCompleteRedelegate := NewMsgCompleteRedelegate(sdk.AccAddress(validatorAddr), validatorAddr, validatorAddr2)
got = handleMsgCompleteRedelegate(ctx, msgCompleteRedelegate, keeper)
require.True(t, got.IsOK(), "expected no error")
@ -638,7 +731,9 @@ func TestTransitiveRedelegation(t *testing.T) {
func TestUnbondingWhenExcessValidators(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr1, validatorAddr2, validatorAddr3 := keep.Addrs[0], keep.Addrs[1], keep.Addrs[2]
validatorAddr1 := sdk.ValAddress(keep.Addrs[0])
validatorAddr2 := sdk.ValAddress(keep.Addrs[1])
validatorAddr3 := sdk.ValAddress(keep.Addrs[2])
// set the unbonding time
params := keeper.GetParams(ctx)
@ -663,7 +758,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
require.Equal(t, 2, len(keeper.GetValidatorsBonded(ctx)))
// unbond the valdator-2
msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30))
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30))
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding")
@ -679,7 +774,7 @@ func TestUnbondingWhenExcessValidators(t *testing.T) {
func TestJoiningAsCliffValidator(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr1, validatorAddr2 := keep.Addrs[0], keep.Addrs[1]
validatorAddr1, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
// make sure that the cliff validator is nil to begin with
cliffVal := keeper.GetCliffValidator(ctx)
@ -712,7 +807,7 @@ func TestJoiningAsCliffValidator(t *testing.T) {
func TestJoiningToCreateFirstCliffValidator(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr1, validatorAddr2 := keep.Addrs[0], keep.Addrs[1]
validatorAddr1, validatorAddr2 := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1])
// make sure that the cliff validator is nil to begin with
cliffVal := keeper.GetCliffValidator(ctx)
@ -745,7 +840,9 @@ func TestJoiningToCreateFirstCliffValidator(t *testing.T) {
func TestCliffValidator(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
validatorAddr1, validatorAddr2, validatorAddr3 := keep.Addrs[0], keep.Addrs[1], keep.Addrs[2]
validatorAddr1 := sdk.ValAddress(keep.Addrs[0])
validatorAddr2 := sdk.ValAddress(keep.Addrs[1])
validatorAddr3 := sdk.ValAddress(keep.Addrs[2])
// make sure that the cliff validator is nil to begin with
cliffVal := keeper.GetCliffValidator(ctx)
@ -785,7 +882,7 @@ func TestCliffValidator(t *testing.T) {
require.Equal(t, validatorAddr2.Bytes(), cliffVal)
// unbond valdator-2
msgBeginUnbonding := NewMsgBeginUnbonding(validatorAddr2, validatorAddr2, sdk.NewDec(30))
msgBeginUnbonding := NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr2), validatorAddr2, sdk.NewDec(30))
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding")
@ -798,7 +895,7 @@ func TestCliffValidator(t *testing.T) {
require.Equal(t, validatorAddr3.Bytes(), cliffVal)
// unbond valdator-1
msgBeginUnbonding = NewMsgBeginUnbonding(validatorAddr1, validatorAddr1, sdk.NewDec(50))
msgBeginUnbonding = NewMsgBeginUnbonding(sdk.AccAddress(validatorAddr1), validatorAddr1, sdk.NewDec(50))
got = handleMsgBeginUnbonding(ctx, msgBeginUnbonding, keeper)
require.True(t, got.IsOK(), "expected no error on runMsgBeginUnbonding")
@ -813,7 +910,7 @@ func TestCliffValidator(t *testing.T) {
func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
valA, valB, del := keep.Addrs[0], keep.Addrs[1], keep.Addrs[2]
valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2]
msgCreateValidator := newTestMsgCreateValidator(valA, keep.PKs[0], 10)
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)

View File

@ -9,10 +9,11 @@ import (
// load a delegation
func (k Keeper) GetDelegation(ctx sdk.Context,
delegatorAddr, validatorAddr sdk.AccAddress) (delegation types.Delegation, found bool) {
delAddr sdk.AccAddress, valAddr sdk.ValAddress) (
delegation types.Delegation, found bool) {
store := ctx.KVStore(k.storeKey)
key := GetDelegationKey(delegatorAddr, validatorAddr)
key := GetDelegationKey(delAddr, valAddr)
value := store.Get(key)
if value == nil {
return delegation, false
@ -79,10 +80,10 @@ func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) {
// load a unbonding delegation
func (k Keeper) GetUnbondingDelegation(ctx sdk.Context,
DelegatorAddr, ValidatorAddr sdk.AccAddress) (ubd types.UnbondingDelegation, found bool) {
delAddr sdk.AccAddress, valAddr sdk.ValAddress) (ubd types.UnbondingDelegation, found bool) {
store := ctx.KVStore(k.storeKey)
key := GetUBDKey(DelegatorAddr, ValidatorAddr)
key := GetUBDKey(delAddr, valAddr)
value := store.Get(key)
if value == nil {
return ubd, false
@ -93,7 +94,7 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context,
}
// load all unbonding delegations from a particular validator
func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.AccAddress) (ubds []types.UnbondingDelegation) {
func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (ubds []types.UnbondingDelegation) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr))
for {
@ -147,10 +148,10 @@ func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDe
// load a redelegation
func (k Keeper) GetRedelegation(ctx sdk.Context,
DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr sdk.AccAddress) (red types.Redelegation, found bool) {
delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) (red types.Redelegation, found bool) {
store := ctx.KVStore(k.storeKey)
key := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr)
key := GetREDKey(delAddr, valSrcAddr, valDstAddr)
value := store.Get(key)
if value == nil {
return red, false
@ -161,7 +162,7 @@ func (k Keeper) GetRedelegation(ctx sdk.Context,
}
// load all redelegations from a particular validator
func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.AccAddress) (reds []types.Redelegation) {
func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.ValAddress) (reds []types.Redelegation) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr))
for {
@ -180,10 +181,10 @@ func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.AccAd
// has a redelegation
func (k Keeper) HasReceivingRedelegation(ctx sdk.Context,
DelegatorAddr, ValidatorDstAddr sdk.AccAddress) bool {
delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) bool {
store := ctx.KVStore(k.storeKey)
prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr)
prefix := GetREDsByDelToValDstIndexKey(delAddr, valDstAddr)
iterator := sdk.KVStorePrefixIterator(store, prefix) //smallest to largest
found := false
@ -217,14 +218,14 @@ func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) {
//_____________________________________________________________________________________
// Perform a delegation, set/update everything necessary within the store.
func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt sdk.Coin,
func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Coin,
validator types.Validator, subtractAccount bool) (newShares sdk.Dec, err sdk.Error) {
// Get or create the delegator delegation
delegation, found := k.GetDelegation(ctx, delegatorAddr, validator.Operator)
delegation, found := k.GetDelegation(ctx, delAddr, validator.Operator)
if !found {
delegation = types.Delegation{
DelegatorAddr: delegatorAddr,
DelegatorAddr: delAddr,
ValidatorAddr: validator.Operator,
Shares: sdk.ZeroDec(),
}
@ -253,11 +254,11 @@ func (k Keeper) Delegate(ctx sdk.Context, delegatorAddr sdk.AccAddress, bondAmt
}
// unbond the the delegation return
func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress,
func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress,
shares sdk.Dec) (amount sdk.Dec, err sdk.Error) {
// check if delegation has any shares in it unbond
delegation, found := k.GetDelegation(ctx, delegatorAddr, validatorAddr)
delegation, found := k.GetDelegation(ctx, delAddr, valAddr)
if !found {
err = types.ErrNoDelegatorForAddress(k.Codespace())
return
@ -270,7 +271,7 @@ func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddr
}
// get validator
validator, found := k.GetValidator(ctx, validatorAddr)
validator, found := k.GetValidator(ctx, valAddr)
if !found {
err = types.ErrNoValidatorFound(k.Codespace())
return
@ -287,6 +288,7 @@ func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddr
if bytes.Equal(delegation.DelegatorAddr, validator.Operator) && validator.Jailed == false {
validator.Jailed = true
}
k.RemoveDelegation(ctx, delegation)
} else {
// Update height
@ -306,21 +308,22 @@ func (k Keeper) unbond(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddr
k.RemoveValidator(ctx, validator.Operator)
}
return
return amount, nil
}
//______________________________________________________________________________________________________
// complete unbonding an unbonding record
func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error {
func (k Keeper) BeginUnbonding(ctx sdk.Context,
delAddr sdk.AccAddress, valAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error {
// TODO quick fix, instead we should use an index, see https://github.com/cosmos/cosmos-sdk/issues/1402
_, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr)
_, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr)
if found {
return types.ErrExistingUnbondingDelegation(k.Codespace())
}
returnAmount, err := k.unbond(ctx, delegatorAddr, validatorAddr, sharesAmount)
returnAmount, err := k.unbond(ctx, delAddr, valAddr, sharesAmount)
if err != nil {
return err
}
@ -331,8 +334,8 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk
balance := sdk.Coin{params.BondDenom, returnAmount.RoundInt()}
ubd := types.UnbondingDelegation{
DelegatorAddr: delegatorAddr,
ValidatorAddr: validatorAddr,
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
MinTime: minTime,
Balance: balance,
InitialBalance: balance,
@ -342,9 +345,9 @@ func (k Keeper) BeginUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk
}
// complete unbonding an unbonding record
func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr sdk.AccAddress) sdk.Error {
func (k Keeper) CompleteUnbonding(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) sdk.Error {
ubd, found := k.GetUnbondingDelegation(ctx, delegatorAddr, validatorAddr)
ubd, found := k.GetUnbondingDelegation(ctx, delAddr, valAddr)
if !found {
return types.ErrNoUnbondingDelegation(k.Codespace())
}
@ -364,26 +367,26 @@ func (k Keeper) CompleteUnbonding(ctx sdk.Context, delegatorAddr, validatorAddr
}
// complete unbonding an unbonding record
func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAddr,
validatorDstAddr sdk.AccAddress, sharesAmount sdk.Dec) sdk.Error {
func (k Keeper) BeginRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
valSrcAddr, valDstAddr sdk.ValAddress, sharesAmount sdk.Dec) sdk.Error {
// check if this is a transitive redelegation
if k.HasReceivingRedelegation(ctx, delegatorAddr, validatorSrcAddr) {
if k.HasReceivingRedelegation(ctx, delAddr, valSrcAddr) {
return types.ErrTransitiveRedelegation(k.Codespace())
}
returnAmount, err := k.unbond(ctx, delegatorAddr, validatorSrcAddr, sharesAmount)
returnAmount, err := k.unbond(ctx, delAddr, valSrcAddr, sharesAmount)
if err != nil {
return err
}
params := k.GetParams(ctx)
returnCoin := sdk.Coin{params.BondDenom, returnAmount.RoundInt()}
dstValidator, found := k.GetValidator(ctx, validatorDstAddr)
dstValidator, found := k.GetValidator(ctx, valDstAddr)
if !found {
return types.ErrBadRedelegationDst(k.Codespace())
}
sharesCreated, err := k.Delegate(ctx, delegatorAddr, returnCoin, dstValidator, false)
sharesCreated, err := k.Delegate(ctx, delAddr, returnCoin, dstValidator, false)
if err != nil {
return err
}
@ -392,9 +395,9 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAd
minTime := ctx.BlockHeader().Time.Add(params.UnbondingTime)
red := types.Redelegation{
DelegatorAddr: delegatorAddr,
ValidatorSrcAddr: validatorSrcAddr,
ValidatorDstAddr: validatorDstAddr,
DelegatorAddr: delAddr,
ValidatorSrcAddr: valSrcAddr,
ValidatorDstAddr: valDstAddr,
MinTime: minTime,
SharesDst: sharesCreated,
SharesSrc: sharesAmount,
@ -406,9 +409,10 @@ func (k Keeper) BeginRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAd
}
// complete unbonding an ongoing redelegation
func (k Keeper) CompleteRedelegation(ctx sdk.Context, delegatorAddr, validatorSrcAddr, validatorDstAddr sdk.AccAddress) sdk.Error {
func (k Keeper) CompleteRedelegation(ctx sdk.Context, delAddr sdk.AccAddress,
valSrcAddr, valDstAddr sdk.ValAddress) sdk.Error {
red, found := k.GetRedelegation(ctx, delegatorAddr, validatorSrcAddr, validatorDstAddr)
red, found := k.GetRedelegation(ctx, delAddr, valSrcAddr, valDstAddr)
if !found {
return types.ErrNoRedelegation(k.Codespace())
}

Some files were not shown because too many files have changed in this diff Show More