diff --git a/examples/gaia/client.go b/examples/gaia/client.go deleted file mode 100644 index 6344fc3489..0000000000 --- a/examples/gaia/client.go +++ /dev/null @@ -1,97 +0,0 @@ -package main - -import ( - "github.com/spf13/cobra" - - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/commits" - "github.com/cosmos/cosmos-sdk/client/commands/keys" - "github.com/cosmos/cosmos-sdk/client/commands/proxy" - "github.com/cosmos/cosmos-sdk/client/commands/query" - rpccmd "github.com/cosmos/cosmos-sdk/client/commands/rpc" - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - authcmd "github.com/cosmos/cosmos-sdk/modules/auth/commands" - basecmd "github.com/cosmos/cosmos-sdk/modules/base/commands" - coincmd "github.com/cosmos/cosmos-sdk/modules/coin/commands" - feecmd "github.com/cosmos/cosmos-sdk/modules/fee/commands" - ibccmd "github.com/cosmos/cosmos-sdk/modules/ibc/commands" - noncecmd "github.com/cosmos/cosmos-sdk/modules/nonce/commands" - rolecmd "github.com/cosmos/cosmos-sdk/modules/roles/commands" - - stakecmd "github.com/cosmos/gaia/modules/stake/commands" -) - -// clientCmd is the entry point for this binary -var clientCmd = &cobra.Command{ - Use: "client", - Short: "Gaia light client", - Run: func(cmd *cobra.Command, args []string) { - cmd.Help() - }, -} - -func prepareClientCommands() { - commands.AddBasicFlags(clientCmd) - - // Prepare queries - query.RootCmd.AddCommand( - // These are default parsers, but optional in your app (you can remove key) - query.TxQueryCmd, - query.KeyQueryCmd, - coincmd.AccountQueryCmd, - noncecmd.NonceQueryCmd, - rolecmd.RoleQueryCmd, - ibccmd.IBCQueryCmd, - - //stakecmd.CmdQueryValidator, - stakecmd.CmdQueryCandidates, - stakecmd.CmdQueryCandidate, - stakecmd.CmdQueryDelegatorBond, - stakecmd.CmdQueryDelegatorCandidates, - ) - - // set up the middleware - txcmd.Middleware = txcmd.Wrappers{ - feecmd.FeeWrapper{}, - rolecmd.RoleWrapper{}, - noncecmd.NonceWrapper{}, - basecmd.ChainWrapper{}, - authcmd.SigWrapper{}, - } - txcmd.Middleware.Register(txcmd.RootCmd.PersistentFlags()) - - // you will always want this for the base send command - txcmd.RootCmd.AddCommand( - // This is the default transaction, optional in your app - coincmd.SendTxCmd, - coincmd.CreditTxCmd, - // this enables creating roles - rolecmd.CreateRoleTxCmd, - // these are for handling ibc - ibccmd.RegisterChainTxCmd, - ibccmd.UpdateChainTxCmd, - ibccmd.PostPacketTxCmd, - - stakecmd.CmdDeclareCandidacy, - stakecmd.CmdEditCandidacy, - stakecmd.CmdDelegate, - stakecmd.CmdUnbond, - ) - - clientCmd.AddCommand( - proxy.RootCmd, - lineBreak, - - txcmd.RootCmd, - query.RootCmd, - rpccmd.RootCmd, - lineBreak, - - keys.RootCmd, - commands.InitCmd, - commands.ResetCmd, - commits.RootCmd, - lineBreak, - ) - -} diff --git a/examples/gaia/main.go b/examples/gaia/main.go deleted file mode 100644 index b631e5cba3..0000000000 --- a/examples/gaia/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "os" - - "github.com/spf13/cobra" - - "github.com/tendermint/tmlibs/cli" - - basecmd "github.com/cosmos/cosmos-sdk/server/commands" - "github.com/cosmos/gaia/version" -) - -// GaiaCmd is the entry point for this binary -var ( - GaiaCmd = &cobra.Command{ - Use: "gaia", - Short: "The Cosmos Network delegation-game test", - Run: func(cmd *cobra.Command, args []string) { - cmd.Help() - }, - } - - lineBreak = &cobra.Command{Run: func(*cobra.Command, []string) {}} -) - -func main() { - // disable sorting - cobra.EnableCommandSorting = false - - // add commands - prepareNodeCommands() - prepareRestServerCommands() - prepareClientCommands() - - GaiaCmd.AddCommand( - nodeCmd, - restServerCmd, - clientCmd, - - lineBreak, - version.VersionCmd, - //auto.AutoCompleteCmd, - ) - - // prepare and add flags - basecmd.SetUpRoot(GaiaCmd) - executor := cli.PrepareMainCmd(GaiaCmd, "GA", os.ExpandEnv("$HOME/.cosmos-gaia-cli")) - executor.Execute() -} diff --git a/examples/gaia/node.go b/examples/gaia/node.go deleted file mode 100644 index aec74aeaf0..0000000000 --- a/examples/gaia/node.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import ( - "github.com/spf13/cobra" - - abci "github.com/tendermint/abci/types" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/base" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/modules/fee" - "github.com/cosmos/cosmos-sdk/modules/ibc" - "github.com/cosmos/cosmos-sdk/modules/nonce" - "github.com/cosmos/cosmos-sdk/modules/roles" - basecmd "github.com/cosmos/cosmos-sdk/server/commands" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" - - "github.com/cosmos/gaia/modules/stake" -) - -// nodeCmd is the entry point for this binary -var nodeCmd = &cobra.Command{ - Use: "node", - Short: "The Cosmos Network delegation-game blockchain test", - Run: func(cmd *cobra.Command, args []string) { cmd.Help() }, -} - -func prepareNodeCommands() { - - basecmd.Handler = stack.New( - base.Logger{}, - stack.Recovery{}, - auth.Signatures{}, - base.Chain{}, - stack.Checkpoint{OnCheck: true}, - nonce.ReplayCheck{}, - ). - IBC(ibc.NewMiddleware()). - Apps( - roles.NewMiddleware(), - fee.NewSimpleFeeMiddleware(coin.Coin{"fermion", 0}, fee.Bank), - stack.Checkpoint{OnDeliver: true}, - ). - Dispatch( - coin.NewHandler(), - stack.WrapHandler(roles.NewHandler()), - stack.WrapHandler(ibc.NewHandler()), - stake.NewHandler(), - ) - - nodeCmd.AddCommand( - basecmd.GetInitCmd("fermion", []string{"stake/allowed_bond_denom/fermion"}), - basecmd.GetTickStartCmd(sdk.TickerFunc(tickFn)), - basecmd.UnsafeResetAllCmd, - ) -} - -// Tick - Called every block even if no transaction, process all queues, -// validator rewards, and calculate the validator set difference -func tickFn(ctx sdk.Context, store state.SimpleDB) (change []*abci.Validator, err error) { - // first need to prefix the store, at this point it's a global store - store = stack.PrefixedStore(stake.Name(), store) - - // execute Tick - change, err = stake.Tick(ctx, store) - return -} diff --git a/examples/gaia/rest.go b/examples/gaia/rest.go deleted file mode 100644 index 7a96978961..0000000000 --- a/examples/gaia/rest.go +++ /dev/null @@ -1,89 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/http" - - "github.com/gorilla/mux" - "github.com/spf13/cobra" - "github.com/spf13/viper" - "github.com/tendermint/tmlibs/cli" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/commands" - rest "github.com/cosmos/cosmos-sdk/client/rest" - coinrest "github.com/cosmos/cosmos-sdk/modules/coin/rest" - noncerest "github.com/cosmos/cosmos-sdk/modules/nonce/rest" - rolerest "github.com/cosmos/cosmos-sdk/modules/roles/rest" - - stakerest "github.com/cosmos/gaia/modules/stake/rest" -) - -const defaultAlgo = "ed25519" - -var ( - restServerCmd = &cobra.Command{ - Use: "rest-server", - Short: "REST client for gaia commands", - Long: `Gaiaserver presents a nice (not raw hex) interface to the gaia blockchain structure.`, - RunE: func(cmd *cobra.Command, args []string) error { - return cmdRestServer(cmd, args) - }, - } - - flagPort = "port" -) - -func prepareRestServerCommands() { - commands.AddBasicFlags(restServerCmd) - restServerCmd.PersistentFlags().IntP(flagPort, "p", 8998, "port to run the server on") -} - -func cmdRestServer(cmd *cobra.Command, args []string) error { - router := mux.NewRouter() - - rootDir := viper.GetString(cli.HomeFlag) - keyMan := client.GetKeyManager(rootDir) - serviceKeys := rest.NewServiceKeys(keyMan) - serviceTxs := rest.NewServiceTxs(commands.GetNode()) - - routeRegistrars := []func(*mux.Router) error{ - // rest.Keys handlers - serviceKeys.RegisterCRUD, - - // Coin handlers (Send, Query, SearchSent) - coinrest.RegisterAll, - - // Roles createRole handler - rolerest.RegisterCreateRole, - - // Gaia sign transactions handler - serviceKeys.RegisterSignTx, - // Gaia post transaction handler - serviceTxs.RegisterPostTx, - - // Nonce query handler - noncerest.RegisterQueryNonce, - - // Staking query handlers - stakerest.RegisterQueryCandidate, - stakerest.RegisterQueryCandidates, - stakerest.RegisterQueryDelegatorBond, - stakerest.RegisterQueryDelegatorCandidates, - // Staking tx builders - stakerest.RegisterDelegate, - stakerest.RegisterUnbond, - } - - for _, routeRegistrar := range routeRegistrars { - if err := routeRegistrar(router); err != nil { - log.Fatal(err) - } - } - - addr := fmt.Sprintf(":%d", viper.GetInt(flagPort)) - - log.Printf("Serving on %q", addr) - return http.ListenAndServe(addr, router) -} diff --git a/examples/gaia/sh_tests/stake.sh b/examples/gaia/sh_tests/stake.sh deleted file mode 100644 index 4f5d1c7703..0000000000 --- a/examples/gaia/sh_tests/stake.sh +++ /dev/null @@ -1,275 +0,0 @@ -#!/bin/bash -set -u - -# These global variables are required for common.sh -SERVER_EXE="gaia node" -CLIENT_EXE="gaia client" -ACCOUNTS=(jae ethan bucky rigel igor) -RICH=${ACCOUNTS[0]} -DELEGATOR=${ACCOUNTS[2]} -POOR=${ACCOUNTS[4]} - -BASE_DIR=$HOME/stake_test -BASE_DIR2=$HOME/stake_test2 -SERVER1=$BASE_DIR/server -SERVER2=$BASE_DIR2/server - -oneTimeSetUp() { - #[ "$2" ] || echo "missing parameters, line=${LINENO}" ; exit 1; - - - # These are passed in as args - CHAIN_ID="stake_test" - - # TODO Make this more robust - if [ "$BASE_DIR" == "$HOME/" ]; then - echo "Must be called with argument, or it will wipe your home directory" - exit 1 - fi - - rm -rf $BASE_DIR 2>/dev/null - mkdir -p $BASE_DIR - - if [ "$BASE_DIR2" == "$HOME/" ]; then - echo "Must be called with argument, or it will wipe your home directory" - exit 1 - fi - rm -rf $BASE_DIR2 2>/dev/null - mkdir -p $BASE_DIR2 - - # Set up client - make sure you use the proper prefix if you set - # a custom CLIENT_EXE - export BC_HOME=${BASE_DIR}/client - prepareClient - - # start the node server - set +u ; initServer $BASE_DIR $CHAIN_ID ; set -u - if [ $? != 0 ]; then return 1; fi - - set +u ; initClient $CHAIN_ID ; set -u - if [ $? != 0 ]; then return 1; fi - - printf "...Testing may begin!\n\n\n" - -} - -oneTimeTearDown() { - kill -9 $PID_SERVER2 >/dev/null 2>&1 - set +u ; quickTearDown ; set -u -} - -# Ex Usage: checkCandidate $PUBKEY $EXPECTED_VOTING_POWER -checkCandidate() { - CANDIDATE=$(${CLIENT_EXE} query candidate --pubkey=$1) - if ! assertTrue "line=${LINENO}, bad query" $?; then - return 1 - fi - assertEquals "line=${LINENO}, proper voting power" "$2" $(echo $CANDIDATE | jq .data.voting_power) - return $? -} - -# Ex Usage: checkCandidate $PUBKEY -checkCandidateEmpty() { - CANDIDATE=$(${CLIENT_EXE} query candidate --pubkey=$1 2>/dev/null) - if ! assertFalse "line=${LINENO}, expected empty query" $?; then - return 1 - fi -} - -# Ex Usage: checkCandidate $DELEGATOR_ADDR $PUBKEY $EXPECTED_SHARES -checkDelegatorBond() { - BOND=$(${CLIENT_EXE} query delegator-bond --delegator-address=$1 --pubkey=$2) - if ! assertTrue "line=${LINENO}, account must exist" $?; then - return 1 - fi - assertEquals "line=${LINENO}, proper bond amount" "$3" $(echo $BOND | jq .data.Shares) - return $? -} - -# Ex Usage: checkCandidate $DELEGATOR_ADDR $PUBKEY -checkDelegatorBondEmpty() { - BOND=$(${CLIENT_EXE} query delegator-bond --delegator-address=$1 --pubkey=$2 2>/dev/null) - if ! assertFalse "line=${LINENO}, expected empty query" $?; then - return 1 - fi -} - -#______________________________________________________________________________________ - -test00GetAccount() { - SENDER=$(getAddr $RICH) - RECV=$(getAddr $POOR) - - assertFalse "line=${LINENO}, requires arg" "${CLIENT_EXE} query account" - - set +u ; checkAccount $SENDER "9007199254740992" ; set -u - - ACCT2=$(${CLIENT_EXE} query account $RECV 2>/dev/null) - assertFalse "line=${LINENO}, has no genesis account" $? -} - -test01SendTx() { - assertFalse "line=${LINENO}, missing dest" "${CLIENT_EXE} tx send --amount=992fermion --sequence=1" - assertFalse "line=${LINENO}, bad password" "echo foo | ${CLIENT_EXE} tx send --amount=992fermion --sequence=1 --to=$RECV --name=$RICH" - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --amount=992fermion --sequence=1 --to=$RECV --name=$RICH) - txSucceeded $? "$TX" "$RECV" - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - - set +u - checkAccount $SENDER "9007199254740000" $TX_HEIGHT - # make sure 0x prefix also works - checkAccount "0x$SENDER" "9007199254740000" $TX_HEIGHT - checkAccount $RECV "992" $TX_HEIGHT - - # Make sure tx is indexed - checkSendTx $HASH $TX_HEIGHT $SENDER "992" - set -u -} - -test02DeclareCandidacy() { - - # the premise of this test is to run a second validator (from rich) and then bond and unbond some tokens - # first create a second node to run and connect to the system - - # init the second node - SERVER_LOG2=$BASE_DIR2/node2.log - GENKEY=$(${CLIENT_EXE} keys get ${RICH} | awk '{print $2}') - ${SERVER_EXE} init $GENKEY --chain-id $CHAIN_ID --home=$SERVER2 >>$SERVER_LOG2 - if [ $? != 0 ]; then return 1; fi - - # copy in the genesis from the first initialization to the new server - cp $SERVER1/genesis.json $SERVER2/genesis.json - - # point the new config to the old server location - rm $SERVER2/config.toml - echo 'proxy_app = "tcp://127.0.0.1:46668" - moniker = "anonymous" - fast_sync = true - db_backend = "leveldb" - log_level = "state:info,*:error" - - [rpc] - laddr = "tcp://0.0.0.0:46667" - - [p2p] - laddr = "tcp://0.0.0.0:46666" - seeds = "0.0.0.0:46656"' >$SERVER2/config.toml - - # start the second node - ${SERVER_EXE} start --home=$SERVER2 >>$SERVER_LOG2 2>&1 & - sleep 1 - PID_SERVER2=$! - disown - if ! ps $PID_SERVER2 >/dev/null; then - echo "**FAILED**" - cat $SERVER_LOG2 - return 1 - fi - - # get the pubkey of the second validator - PK2=$(cat $SERVER2/priv_validator.json | jq -r .pub_key.data) - - CAND_ADDR=$(getAddr $POOR) - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx declare-candidacy --sequence=1 --amount=10fermion --name=$POOR --pubkey=$PK2 --moniker=rigey) - if [ $? != 0 ]; then return 1; fi - HASH=$(echo $TX | jq .hash | tr -d \") - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $CAND_ADDR "982" $TX_HEIGHT ; set -u - checkCandidate $PK2 "10" - checkDelegatorBond $CAND_ADDR $PK2 "10" -} - -test03Delegate() { - # send some coins to a delegator - DELA_ADDR=$(getAddr $DELEGATOR) - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx send --sequence=2 --amount=15fermion --to=$DELA_ADDR --name=$RICH) - txSucceeded $? "$TX" "$DELA_ADDR" - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $DELA_ADDR "15" $TX_HEIGHT ; set -u - - # delegate some coins to the new - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx delegate --sequence=1 --amount=10fermion --name=$DELEGATOR --pubkey=$PK2) - if [ $? != 0 ]; then return 1; fi - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $DELA_ADDR "5" $TX_HEIGHT ; set -u - checkCandidate $PK2 "20" - checkDelegatorBond $DELA_ADDR $PK2 "10" - - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx delegate --sequence=2 --amount=3fermion --name=$DELEGATOR --pubkey=$PK2) - if [ $? != 0 ]; then return 1; fi - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $DELA_ADDR "2" $TX_HEIGHT ; set -u - checkCandidate $PK2 "23" - checkDelegatorBond $DELA_ADDR $PK2 "13" - - # attempt a delegation without enough funds - # NOTE the sequence number still increments here because it will fail - # only during DeliverTx - however this should be updated (TODO) in new - # SDK when we can fail in CheckTx - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx delegate --sequence=3 --amount=3fermion --name=$DELEGATOR --pubkey=$PK2 2>/dev/null) - if [ $? == 0 ]; then return 1; fi - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $DELA_ADDR "2" $TX_HEIGHT ; set -u - checkCandidate $PK2 "23" - checkDelegatorBond $DELA_ADDR $PK2 "13" - - # perform the final delegation which should empty the delegators account - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx delegate --sequence=4 --amount=2fermion --name=$DELEGATOR --pubkey=$PK2) - if [ $? != 0 ]; then return 1; fi - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $DELA_ADDR "null" $TX_HEIGHT ; set -u #empty account is null - checkCandidate $PK2 "25" -} - -test04Unbond() { - # unbond from the delegator a bit - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx unbond --sequence=5 --shares=10 --name=$DELEGATOR --pubkey=$PK2) - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $DELA_ADDR "10" $TX_HEIGHT ; set -u - checkCandidate $PK2 "15" - checkDelegatorBond $DELA_ADDR $PK2 "5" - - # attempt to unbond more shares than exist - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx unbond --sequence=6 --shares=10 --name=$DELEGATOR --pubkey=$PK2 2>/dev/null) - if [ $? == 0 ]; then return 1; fi - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $DELA_ADDR "10" $TX_HEIGHT ; set -u - checkCandidate $PK2 "15" - checkDelegatorBond $DELA_ADDR $PK2 "5" - - # unbond entirely from the delegator - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx unbond --sequence=6 --shares=5 --name=$DELEGATOR --pubkey=$PK2) - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $DELA_ADDR "15" $TX_HEIGHT ; set -u - checkCandidate $PK2 "10" - checkDelegatorBondEmpty $DELA_ADDR $PK2 - - # unbond a bit from the owner - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx unbond --sequence=2 --shares=5 --name=$POOR --pubkey=$PK2) - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $CAND_ADDR "987" $TX_HEIGHT ; set -u - checkCandidate $PK2 "5" - checkDelegatorBond $CAND_ADDR $PK2 "5" - - # attempt to unbond more shares than exist - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx unbond --sequence=3 --shares=10 --name=$POOR --pubkey=$PK2 2>/dev/null) - if [ $? == 0 ]; then return 1; fi - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $CAND_ADDR "987" $TX_HEIGHT ; set -u - checkCandidate $PK2 "5" - checkDelegatorBond $CAND_ADDR $PK2 "5" - - # unbond entirely from the validator - TX=$(echo qwertyuiop | ${CLIENT_EXE} tx unbond --sequence=3 --shares=5 --name=$POOR --pubkey=$PK2) - TX_HEIGHT=$(echo $TX | jq .height) - set +u ; checkAccount $CAND_ADDR "992" $TX_HEIGHT ; set -u - checkCandidateEmpty $PK2 - checkDelegatorBondEmpty $CAND_ADDR $PK2 -} - -# Load common then run these tests with shunit2! -CLI_DIR=$GOPATH/src/github.com/cosmos/gaia/vendor/github.com/cosmos/cosmos-sdk/tests/cli - -. $CLI_DIR/common.sh -. $CLI_DIR/shunit2 diff --git a/x/stake/commands/query.go b/x/stake/commands/query.go deleted file mode 100644 index 2528d07d10..0000000000 --- a/x/stake/commands/query.go +++ /dev/null @@ -1,136 +0,0 @@ -package commands - -import ( - "github.com/spf13/cobra" - flag "github.com/spf13/pflag" - "github.com/spf13/viper" - - crypto "github.com/tendermint/go-crypto" - - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/query" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/gaia/modules/stake" -) - -//nolint -var ( - CmdQueryCandidates = &cobra.Command{ - Use: "candidates", - Short: "Query for the set of validator-candidates pubkeys", - RunE: cmdQueryCandidates, - } - - CmdQueryCandidate = &cobra.Command{ - Use: "candidate", - Short: "Query a validator-candidate account", - RunE: cmdQueryCandidate, - } - - CmdQueryDelegatorBond = &cobra.Command{ - Use: "delegator-bond", - Short: "Query a delegators bond based on address and candidate pubkey", - RunE: cmdQueryDelegatorBond, - } - - CmdQueryDelegatorCandidates = &cobra.Command{ - Use: "delegator-candidates", - RunE: cmdQueryDelegatorCandidates, - Short: "Query all delegators candidates' pubkeys based on address", - } - - FlagDelegatorAddress = "delegator-address" -) - -func init() { - //Add Flags - fsPk := flag.NewFlagSet("", flag.ContinueOnError) - fsPk.String(FlagPubKey, "", "PubKey of the validator-candidate") - fsAddr := flag.NewFlagSet("", flag.ContinueOnError) - fsAddr.String(FlagDelegatorAddress, "", "Delegator Hex Address") - - CmdQueryCandidate.Flags().AddFlagSet(fsPk) - CmdQueryDelegatorBond.Flags().AddFlagSet(fsPk) - CmdQueryDelegatorBond.Flags().AddFlagSet(fsAddr) - CmdQueryDelegatorCandidates.Flags().AddFlagSet(fsAddr) -} - -func cmdQueryCandidates(cmd *cobra.Command, args []string) error { - - var pks []crypto.PubKey - - prove := !viper.GetBool(commands.FlagTrustNode) - key := stack.PrefixedKey(stake.Name(), stake.CandidatesPubKeysKey) - height, err := query.GetParsed(key, &pks, query.GetHeight(), prove) - if err != nil { - return err - } - - return query.OutputProof(pks, height) -} - -func cmdQueryCandidate(cmd *cobra.Command, args []string) error { - - var candidate stake.Candidate - - pk, err := GetPubKey(viper.GetString(FlagPubKey)) - if err != nil { - return err - } - - prove := !viper.GetBool(commands.FlagTrustNode) - key := stack.PrefixedKey(stake.Name(), stake.GetCandidateKey(pk)) - height, err := query.GetParsed(key, &candidate, query.GetHeight(), prove) - if err != nil { - return err - } - - return query.OutputProof(candidate, height) -} - -func cmdQueryDelegatorBond(cmd *cobra.Command, args []string) error { - - var bond stake.DelegatorBond - - pk, err := GetPubKey(viper.GetString(FlagPubKey)) - if err != nil { - return err - } - - delegatorAddr := viper.GetString(FlagDelegatorAddress) - delegator, err := commands.ParseActor(delegatorAddr) - if err != nil { - return err - } - delegator = coin.ChainAddr(delegator) - - prove := !viper.GetBool(commands.FlagTrustNode) - key := stack.PrefixedKey(stake.Name(), stake.GetDelegatorBondKey(delegator, pk)) - height, err := query.GetParsed(key, &bond, query.GetHeight(), prove) - if err != nil { - return err - } - - return query.OutputProof(bond, height) -} - -func cmdQueryDelegatorCandidates(cmd *cobra.Command, args []string) error { - - delegatorAddr := viper.GetString(FlagDelegatorAddress) - delegator, err := commands.ParseActor(delegatorAddr) - if err != nil { - return err - } - delegator = coin.ChainAddr(delegator) - - prove := !viper.GetBool(commands.FlagTrustNode) - key := stack.PrefixedKey(stake.Name(), stake.GetDelegatorBondsKey(delegator)) - var candidates []crypto.PubKey - height, err := query.GetParsed(key, &candidates, query.GetHeight(), prove) - if err != nil { - return err - } - - return query.OutputProof(candidates, height) -} diff --git a/x/stake/commands/tx.go b/x/stake/commands/tx.go deleted file mode 100644 index e14ac8cec1..0000000000 --- a/x/stake/commands/tx.go +++ /dev/null @@ -1,195 +0,0 @@ -package commands - -import ( - "encoding/hex" - "fmt" - - "github.com/spf13/cobra" - flag "github.com/spf13/pflag" - "github.com/spf13/viper" - - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/tmlibs/rational" - - txcmd "github.com/cosmos/cosmos-sdk/client/commands/txs" - "github.com/cosmos/cosmos-sdk/modules/coin" - - "github.com/cosmos/gaia/modules/stake" -) - -// nolint -const ( - FlagPubKey = "pubkey" - FlagAmount = "amount" - FlagShares = "shares" - - FlagMoniker = "moniker" - FlagIdentity = "keybase-sig" - FlagWebsite = "website" - FlagDetails = "details" -) - -// nolint -var ( - CmdDeclareCandidacy = &cobra.Command{ - Use: "declare-candidacy", - Short: "create new validator-candidate account and delegate some coins to it", - RunE: cmdDeclareCandidacy, - } - CmdEditCandidacy = &cobra.Command{ - Use: "edit-candidacy", - Short: "edit and existing validator-candidate account", - RunE: cmdEditCandidacy, - } - CmdDelegate = &cobra.Command{ - Use: "delegate", - Short: "delegate coins to an existing validator/candidate", - RunE: cmdDelegate, - } - CmdUnbond = &cobra.Command{ - Use: "unbond", - Short: "unbond coins from a validator/candidate", - RunE: cmdUnbond, - } -) - -func init() { - - // define the flags - fsPk := flag.NewFlagSet("", flag.ContinueOnError) - fsPk.String(FlagPubKey, "", "PubKey of the validator-candidate") - - fsAmount := flag.NewFlagSet("", flag.ContinueOnError) - fsAmount.String(FlagAmount, "1fermion", "Amount of coins to bond") - - fsShares := flag.NewFlagSet("", flag.ContinueOnError) - fsShares.String(FlagShares, "", "Amount of shares to unbond, either in decimal or keyword MAX (ex. 1.23456789, 99, MAX)") - - fsCandidate := flag.NewFlagSet("", flag.ContinueOnError) - fsCandidate.String(FlagMoniker, "", "validator-candidate name") - fsCandidate.String(FlagIdentity, "", "optional keybase signature") - fsCandidate.String(FlagWebsite, "", "optional website") - fsCandidate.String(FlagDetails, "", "optional detailed description space") - - // add the flags - CmdDelegate.Flags().AddFlagSet(fsPk) - CmdDelegate.Flags().AddFlagSet(fsAmount) - - CmdUnbond.Flags().AddFlagSet(fsPk) - CmdUnbond.Flags().AddFlagSet(fsShares) - - CmdDeclareCandidacy.Flags().AddFlagSet(fsPk) - CmdDeclareCandidacy.Flags().AddFlagSet(fsAmount) - CmdDeclareCandidacy.Flags().AddFlagSet(fsCandidate) - - CmdEditCandidacy.Flags().AddFlagSet(fsPk) - CmdEditCandidacy.Flags().AddFlagSet(fsCandidate) -} - -func cmdDeclareCandidacy(cmd *cobra.Command, args []string) error { - amount, err := coin.ParseCoin(viper.GetString(FlagAmount)) - if err != nil { - return err - } - - pk, err := GetPubKey(viper.GetString(FlagPubKey)) - if err != nil { - return err - } - - if viper.GetString(FlagMoniker) == "" { - return fmt.Errorf("please enter a moniker for the validator-candidate using --moniker") - } - - description := stake.Description{ - Moniker: viper.GetString(FlagMoniker), - Identity: viper.GetString(FlagIdentity), - Website: viper.GetString(FlagWebsite), - Details: viper.GetString(FlagDetails), - } - - tx := stake.NewTxDeclareCandidacy(amount, pk, description) - return txcmd.DoTx(tx) -} - -func cmdEditCandidacy(cmd *cobra.Command, args []string) error { - - pk, err := GetPubKey(viper.GetString(FlagPubKey)) - if err != nil { - return err - } - - description := stake.Description{ - Moniker: viper.GetString(FlagMoniker), - Identity: viper.GetString(FlagIdentity), - Website: viper.GetString(FlagWebsite), - Details: viper.GetString(FlagDetails), - } - - tx := stake.NewTxEditCandidacy(pk, description) - return txcmd.DoTx(tx) -} - -func cmdDelegate(cmd *cobra.Command, args []string) error { - amount, err := coin.ParseCoin(viper.GetString(FlagAmount)) - if err != nil { - return err - } - - pk, err := GetPubKey(viper.GetString(FlagPubKey)) - if err != nil { - return err - } - - tx := stake.NewTxDelegate(amount, pk) - return txcmd.DoTx(tx) -} - -func cmdUnbond(cmd *cobra.Command, args []string) error { - - // TODO once go-wire refactored the shares can be broadcast as a Rat instead of a string - - // check the shares before broadcasting - sharesStr := viper.GetString(FlagShares) - var shares rational.Rat - if sharesStr != "MAX" { - var err error - shares, err = rational.NewFromDecimal(sharesStr) - if err != nil { - return err - } - if !shares.GT(rational.Zero) { - return fmt.Errorf("shares must be positive integer or decimal (ex. 123, 1.23456789)") - } - } - - pk, err := GetPubKey(viper.GetString(FlagPubKey)) - if err != nil { - return err - } - - tx := stake.NewTxUnbond(sharesStr, pk) - return txcmd.DoTx(tx) -} - -// GetPubKey - create the pubkey from a pubkey string -func GetPubKey(pubKeyStr string) (pk crypto.PubKey, err error) { - - if len(pubKeyStr) == 0 { - err = fmt.Errorf("must use --pubkey flag") - return - } - if len(pubKeyStr) != 64 { //if len(pkBytes) != 32 { - err = fmt.Errorf("pubkey must be Ed25519 hex encoded string which is 64 characters long") - return - } - var pkBytes []byte - pkBytes, err = hex.DecodeString(pubKeyStr) - if err != nil { - return - } - var pkEd crypto.PubKeyEd25519 - copy(pkEd[:], pkBytes[:]) - pk = pkEd.Wrap() - return -} diff --git a/x/stake/errors.go b/x/stake/errors.go deleted file mode 100644 index 900077b125..0000000000 --- a/x/stake/errors.go +++ /dev/null @@ -1,53 +0,0 @@ -// nolint -package stake - -import ( - "fmt" - - "github.com/cosmos/cosmos-sdk/errors" -) - -var ( - errCandidateEmpty = fmt.Errorf("Cannot bond to an empty candidate") - errBadBondingDenom = fmt.Errorf("Invalid coin denomination") - errBadBondingAmount = fmt.Errorf("Amount must be > 0") - errNoBondingAcct = fmt.Errorf("No bond account for this (address, validator) pair") - errCommissionNegative = fmt.Errorf("Commission must be positive") - errCommissionHuge = fmt.Errorf("Commission cannot be more than 100%") - - errBadValidatorAddr = fmt.Errorf("Validator does not exist for that address") - errCandidateExistsAddr = fmt.Errorf("Candidate already exist, cannot re-declare candidacy") - errMissingSignature = fmt.Errorf("Missing signature") - errBondNotNominated = fmt.Errorf("Cannot bond to non-nominated account") - errNoCandidateForAddress = fmt.Errorf("Validator does not exist for that address") - errNoDelegatorForAddress = fmt.Errorf("Delegator does not contain validator bond") - errInsufficientFunds = fmt.Errorf("Insufficient bond shares") - errBadRemoveValidator = fmt.Errorf("Error removing validator") - - invalidInput = errors.CodeTypeBaseInvalidInput -) - -func ErrBadValidatorAddr() error { - return errors.WithCode(errBadValidatorAddr, errors.CodeTypeBaseUnknownAddress) -} -func ErrCandidateExistsAddr() error { - return errors.WithCode(errCandidateExistsAddr, errors.CodeTypeBaseInvalidInput) -} -func ErrMissingSignature() error { - return errors.WithCode(errMissingSignature, errors.CodeTypeUnauthorized) -} -func ErrBondNotNominated() error { - return errors.WithCode(errBondNotNominated, errors.CodeTypeBaseInvalidOutput) -} -func ErrNoCandidateForAddress() error { - return errors.WithCode(errNoCandidateForAddress, errors.CodeTypeBaseUnknownAddress) -} -func ErrNoDelegatorForAddress() error { - return errors.WithCode(errNoDelegatorForAddress, errors.CodeTypeBaseInvalidInput) -} -func ErrInsufficientFunds() error { - return errors.WithCode(errInsufficientFunds, errors.CodeTypeBaseInvalidInput) -} -func ErrBadRemoveValidator() error { - return errors.WithCode(errBadRemoveValidator, errors.CodeTypeInternalErr) -} diff --git a/x/stake/handler.go b/x/stake/handler.go deleted file mode 100644 index c60b408017..0000000000 --- a/x/stake/handler.go +++ /dev/null @@ -1,529 +0,0 @@ -package stake - -import ( - "fmt" - "strconv" - - "github.com/spf13/viper" - "github.com/tendermint/tmlibs/log" - "github.com/tendermint/tmlibs/rational" - - "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/errors" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/stack" - "github.com/cosmos/cosmos-sdk/state" -) - -// nolint -const stakingModuleName = "stake" - -// Name is the name of the modules. -func Name() string { - return stakingModuleName -} - -//_______________________________________________________________________ - -// DelegatedProofOfStake - interface to enforce delegation stake -type delegatedProofOfStake interface { - declareCandidacy(TxDeclareCandidacy) error - editCandidacy(TxEditCandidacy) error - delegate(TxDelegate) error - unbond(TxUnbond) error -} - -type coinSend interface { - transferFn(sender, receiver sdk.Actor, coins coin.Coins) error -} - -//_______________________________________________________________________ - -// Handler - the transaction processing handler -type Handler struct { - stack.PassInitValidate -} - -var _ stack.Dispatchable = Handler{} // enforce interface at compile time - -// NewHandler returns a new Handler with the default Params -func NewHandler() Handler { - return Handler{} -} - -// Name - return stake namespace -func (Handler) Name() string { - return stakingModuleName -} - -// AssertDispatcher - placeholder for stack.Dispatchable -func (Handler) AssertDispatcher() {} - -// InitState - set genesis parameters for staking -func (h Handler) InitState(l log.Logger, store state.SimpleDB, - module, key, value string, cb sdk.InitStater) (log string, err error) { - return "", h.initState(module, key, value, store) -} - -// separated for testing -func (Handler) initState(module, key, value string, store state.SimpleDB) error { - if module != stakingModuleName { - return errors.ErrUnknownModule(module) - } - - params := loadParams(store) - switch key { - case "allowed_bond_denom": - params.AllowedBondDenom = value - case "max_vals", - "gas_bond", - "gas_unbond": - - // TODO: enforce non-negative integers in input - i, err := strconv.Atoi(value) - if err != nil { - return fmt.Errorf("input must be integer, Error: %v", err.Error()) - } - - switch key { - case "max_vals": - params.MaxVals = uint16(i) - case "gas_bond": - params.GasDelegate = int64(i) - case "gas_unbound": - params.GasUnbond = int64(i) - } - default: - return errors.ErrUnknownKey(key) - } - - saveParams(store, params) - return nil -} - -// CheckTx checks if the tx is properly structured -func (h Handler) CheckTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, _ sdk.Checker) (res sdk.CheckResult, err error) { - - err = tx.ValidateBasic() - if err != nil { - return res, err - } - - // get the sender - sender, err := getTxSender(ctx) - if err != nil { - return res, err - } - - params := loadParams(store) - - // create the new checker object to - checker := check{ - store: store, - sender: sender, - } - - // return the fee for each tx type - switch txInner := tx.Unwrap().(type) { - case TxDeclareCandidacy: - return sdk.NewCheck(params.GasDeclareCandidacy, ""), - checker.declareCandidacy(txInner) - case TxEditCandidacy: - return sdk.NewCheck(params.GasEditCandidacy, ""), - checker.editCandidacy(txInner) - case TxDelegate: - return sdk.NewCheck(params.GasDelegate, ""), - checker.delegate(txInner) - case TxUnbond: - return sdk.NewCheck(params.GasUnbond, ""), - checker.unbond(txInner) - } - - return res, errors.ErrUnknownTxType(tx) -} - -// DeliverTx executes the tx if valid -func (h Handler) DeliverTx(ctx sdk.Context, store state.SimpleDB, - tx sdk.Tx, dispatch sdk.Deliver) (res sdk.DeliverResult, err error) { - - // TODO: remove redundancy - // also we don't need to check the res - gas is already deducted in sdk - _, err = h.CheckTx(ctx, store, tx, nil) - if err != nil { - return - } - - sender, err := getTxSender(ctx) - if err != nil { - return - } - - params := loadParams(store) - deliverer := deliver{ - store: store, - sender: sender, - params: params, - transfer: coinSender{ - store: store, - dispatch: dispatch, - ctx: ctx, - }.transferFn, - } - - // Run the transaction - switch _tx := tx.Unwrap().(type) { - case TxDeclareCandidacy: - res.GasUsed = params.GasDeclareCandidacy - return res, deliverer.declareCandidacy(_tx) - case TxEditCandidacy: - res.GasUsed = params.GasEditCandidacy - return res, deliverer.editCandidacy(_tx) - case TxDelegate: - res.GasUsed = params.GasDelegate - return res, deliverer.delegate(_tx) - case TxUnbond: - //context with hold account permissions - params := loadParams(store) - res.GasUsed = params.GasUnbond - ctx2 := ctx.WithPermissions(params.HoldBonded) - deliverer.transfer = coinSender{ - store: store, - dispatch: dispatch, - ctx: ctx2, - }.transferFn - return res, deliverer.unbond(_tx) - } - return -} - -// get the sender from the ctx and ensure it matches the tx pubkey -func getTxSender(ctx sdk.Context) (sender sdk.Actor, err error) { - senders := ctx.GetPermissions("", auth.NameSigs) - if len(senders) != 1 { - return sender, ErrMissingSignature() - } - return senders[0], nil -} - -//_______________________________________________________________________ - -type coinSender struct { - store state.SimpleDB - dispatch sdk.Deliver - ctx sdk.Context -} - -var _ coinSend = coinSender{} // enforce interface at compile time - -func (c coinSender) transferFn(sender, receiver sdk.Actor, coins coin.Coins) error { - send := coin.NewSendOneTx(sender, receiver, coins) - - // If the deduction fails (too high), abort the command - _, err := c.dispatch.DeliverTx(c.ctx, c.store, send) - return err -} - -//_____________________________________________________________________ - -type check struct { - store state.SimpleDB - sender sdk.Actor -} - -var _ delegatedProofOfStake = check{} // enforce interface at compile time - -func (c check) declareCandidacy(tx TxDeclareCandidacy) error { - - // check to see if the pubkey or sender has been registered before - candidate := loadCandidate(c.store, tx.PubKey) - if candidate != nil { - return fmt.Errorf("cannot bond to pubkey which is already declared candidacy"+ - " PubKey %v already registered with %v candidate address", - candidate.PubKey, candidate.Owner) - } - - return checkDenom(tx.BondUpdate, c.store) -} - -func (c check) editCandidacy(tx TxEditCandidacy) error { - - // candidate must already be registered - candidate := loadCandidate(c.store, tx.PubKey) - if candidate == nil { // does PubKey exist - return fmt.Errorf("cannot delegate to non-existant PubKey %v", tx.PubKey) - } - return nil -} - -func (c check) delegate(tx TxDelegate) error { - - candidate := loadCandidate(c.store, tx.PubKey) - if candidate == nil { // does PubKey exist - return fmt.Errorf("cannot delegate to non-existant PubKey %v", tx.PubKey) - } - return checkDenom(tx.BondUpdate, c.store) -} - -func (c check) unbond(tx TxUnbond) error { - - // check if bond has any shares in it unbond - bond := loadDelegatorBond(c.store, c.sender, tx.PubKey) - sharesStr := viper.GetString(tx.Shares) - if bond.Shares.LT(rational.Zero) { // bond shares < tx shares - return fmt.Errorf("no shares in account to unbond") - } - - // if shares set to maximum shares then we're good - if sharesStr == "MAX" { - return nil - } - - // test getting rational number from decimal provided - shares, err := rational.NewFromDecimal(sharesStr) - if err != nil { - return err - } - - // test that there are enough shares to unbond - if bond.Shares.LT(shares) { - return fmt.Errorf("not enough bond shares to unbond, have %v, trying to unbond %v", - bond.Shares, tx.Shares) - } - return nil -} - -func checkDenom(tx BondUpdate, store state.SimpleDB) error { - if tx.Bond.Denom != loadParams(store).AllowedBondDenom { - return fmt.Errorf("Invalid coin denomination") - } - return nil -} - -//_____________________________________________________________________ - -type deliver struct { - store state.SimpleDB - sender sdk.Actor - params Params - gs *GlobalState - transfer transferFn -} - -type transferFn func(sender, receiver sdk.Actor, coins coin.Coins) error - -var _ delegatedProofOfStake = deliver{} // enforce interface at compile time - -//_____________________________________________________________________ -// deliver helper functions - -// TODO move from deliver with new SDK should only be dependant on store to send coins in NEW SDK - -// move a candidates asset pool from bonded to unbonded pool -func (d deliver) bondedToUnbondedPool(candidate *Candidate) error { - - // replace bonded shares with unbonded shares - tokens := d.gs.removeSharesBonded(candidate.Assets) - candidate.Assets = d.gs.addTokensUnbonded(tokens) - candidate.Status = Unbonded - - return d.transfer(d.params.HoldBonded, d.params.HoldUnbonded, - coin.Coins{{d.params.AllowedBondDenom, tokens}}) -} - -// move a candidates asset pool from unbonded to bonded pool -func (d deliver) unbondedToBondedPool(candidate *Candidate) error { - - // replace bonded shares with unbonded shares - tokens := d.gs.removeSharesUnbonded(candidate.Assets) - candidate.Assets = d.gs.addTokensBonded(tokens) - candidate.Status = Bonded - - return d.transfer(d.params.HoldUnbonded, d.params.HoldBonded, - coin.Coins{{d.params.AllowedBondDenom, tokens}}) -} - -//_____________________________________________________________________ - -// These functions assume everything has been authenticated, -// now we just perform action and save -func (d deliver) declareCandidacy(tx TxDeclareCandidacy) error { - - // create and save the empty candidate - bond := loadCandidate(d.store, tx.PubKey) - if bond != nil { - return ErrCandidateExistsAddr() - } - candidate := NewCandidate(tx.PubKey, d.sender, tx.Description) - saveCandidate(d.store, candidate) - - // move coins from the d.sender account to a (self-bond) delegator account - // the candidate account and global shares are updated within here - txDelegate := TxDelegate{tx.BondUpdate} - return d.delegateWithCandidate(txDelegate, candidate) -} - -func (d deliver) editCandidacy(tx TxEditCandidacy) error { - - // Get the pubKey bond account - candidate := loadCandidate(d.store, tx.PubKey) - if candidate == nil { - return ErrBondNotNominated() - } - if candidate.Status == Unbonded { //candidate has been withdrawn - return ErrBondNotNominated() - } - - //check and edit any of the editable terms - if tx.Description.Moniker != "" { - candidate.Description.Moniker = tx.Description.Moniker - } - if tx.Description.Identity != "" { - candidate.Description.Identity = tx.Description.Identity - } - if tx.Description.Website != "" { - candidate.Description.Website = tx.Description.Website - } - if tx.Description.Details != "" { - candidate.Description.Details = tx.Description.Details - } - - saveCandidate(d.store, candidate) - return nil -} - -func (d deliver) delegate(tx TxDelegate) error { - // Get the pubKey bond account - candidate := loadCandidate(d.store, tx.PubKey) - if candidate == nil { - return ErrBondNotNominated() - } - return d.delegateWithCandidate(tx, candidate) -} - -func (d deliver) delegateWithCandidate(tx TxDelegate, candidate *Candidate) error { - - if candidate.Status == Revoked { //candidate has been withdrawn - return ErrBondNotNominated() - } - - var poolAccount sdk.Actor - if candidate.Status == Bonded { - poolAccount = d.params.HoldBonded - } else { - poolAccount = d.params.HoldUnbonded - } - - // TODO maybe refactor into GlobalState.addBondedTokens(), maybe with new SDK - // Move coins from the delegator account to the bonded pool account - err := d.transfer(d.sender, poolAccount, coin.Coins{tx.Bond}) - if err != nil { - return err - } - - // Get or create the delegator bond - bond := loadDelegatorBond(d.store, d.sender, tx.PubKey) - if bond == nil { - bond = &DelegatorBond{ - PubKey: tx.PubKey, - Shares: rational.Zero, - } - } - - // Account new shares, save - bond.Shares = bond.Shares.Add(candidate.addTokens(tx.Bond.Amount, d.gs)) - saveCandidate(d.store, candidate) - saveDelegatorBond(d.store, d.sender, bond) - saveGlobalState(d.store, d.gs) - return nil -} - -func (d deliver) unbond(tx TxUnbond) error { - - // get delegator bond - bond := loadDelegatorBond(d.store, d.sender, tx.PubKey) - if bond == nil { - return ErrNoDelegatorForAddress() - } - - // retrieve the amount of bonds to remove (TODO remove redundancy already serialized) - var shares rational.Rat - if tx.Shares == "MAX" { - shares = bond.Shares - } else { - var err error - shares, err = rational.NewFromDecimal(tx.Shares) - if err != nil { - return err - } - } - - // subtract bond tokens from delegator bond - if bond.Shares.LT(shares) { // bond shares < tx shares - return ErrInsufficientFunds() - } - bond.Shares = bond.Shares.Sub(shares) - - // get pubKey candidate - candidate := loadCandidate(d.store, tx.PubKey) - if candidate == nil { - return ErrNoCandidateForAddress() - } - - revokeCandidacy := false - if bond.Shares.IsZero() { - - // if the bond is the owner of the candidate then - // trigger a revoke candidacy - if d.sender.Equals(candidate.Owner) && - candidate.Status != Revoked { - revokeCandidacy = true - } - - // remove the bond - removeDelegatorBond(d.store, d.sender, tx.PubKey) - } else { - saveDelegatorBond(d.store, d.sender, bond) - } - - // transfer coins back to account - var poolAccount sdk.Actor - if candidate.Status == Bonded { - poolAccount = d.params.HoldBonded - } else { - poolAccount = d.params.HoldUnbonded - } - - returnCoins := candidate.removeShares(shares, d.gs) - err := d.transfer(poolAccount, d.sender, - coin.Coins{{d.params.AllowedBondDenom, returnCoins}}) - if err != nil { - return err - } - - // lastly if an revoke candidate if necessary - if revokeCandidacy { - - // change the share types to unbonded if they were not already - if candidate.Status == Bonded { - err = d.bondedToUnbondedPool(candidate) - if err != nil { - return err - } - } - - // lastly update the status - candidate.Status = Revoked - } - - // deduct shares from the candidate and save - if candidate.Liabilities.IsZero() { - removeCandidate(d.store, tx.PubKey) - } else { - saveCandidate(d.store, candidate) - } - - saveGlobalState(d.store, d.gs) - return nil -} diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go deleted file mode 100644 index 690e7710cf..0000000000 --- a/x/stake/handler_test.go +++ /dev/null @@ -1,336 +0,0 @@ -package stake - -import ( - "strconv" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/tmlibs/rational" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/state" -) - -//______________________________________________________________________ - -// dummy transfer functions, represents store operations on account balances - -type testCoinSender struct { - store map[string]int64 -} - -var _ coinSend = testCoinSender{} // enforce interface at compile time - -func (c testCoinSender) transferFn(sender, receiver sdk.Actor, coins coin.Coins) error { - c.store[string(sender.Address)] -= coins[0].Amount - c.store[string(receiver.Address)] += coins[0].Amount - return nil -} - -//______________________________________________________________________ - -func initAccounts(n int, amount int64) ([]sdk.Actor, map[string]int64) { - accStore := map[string]int64{} - senders := newActors(n) - for _, sender := range senders { - accStore[string(sender.Address)] = amount - } - return senders, accStore -} - -func newTxDeclareCandidacy(amt int64, pubKey crypto.PubKey) TxDeclareCandidacy { - return TxDeclareCandidacy{ - BondUpdate{ - PubKey: pubKey, - Bond: coin.Coin{"fermion", amt}, - }, - Description{}, - } -} - -func newTxDelegate(amt int64, pubKey crypto.PubKey) TxDelegate { - return TxDelegate{BondUpdate{ - PubKey: pubKey, - Bond: coin.Coin{"fermion", amt}, - }} -} - -func newTxUnbond(shares string, pubKey crypto.PubKey) TxUnbond { - return TxUnbond{ - PubKey: pubKey, - Shares: shares, - } -} - -func paramsNoInflation() Params { - return Params{ - HoldBonded: sdk.NewActor(stakingModuleName, []byte("77777777777777777777777777777777")), - HoldUnbonded: sdk.NewActor(stakingModuleName, []byte("88888888888888888888888888888888")), - InflationRateChange: rational.Zero, - InflationMax: rational.Zero, - InflationMin: rational.Zero, - GoalBonded: rational.New(67, 100), - MaxVals: 100, - AllowedBondDenom: "fermion", - GasDeclareCandidacy: 20, - GasEditCandidacy: 20, - GasDelegate: 20, - GasUnbond: 20, - } -} - -func newDeliver(sender sdk.Actor, accStore map[string]int64) deliver { - store := state.NewMemKVStore() - params := paramsNoInflation() - saveParams(store, params) - return deliver{ - store: store, - sender: sender, - params: params, - gs: loadGlobalState(store), - transfer: testCoinSender{accStore}.transferFn, - } -} - -func TestDuplicatesTxDeclareCandidacy(t *testing.T) { - assert := assert.New(t) - senders, accStore := initAccounts(2, 1000) // for accounts - - deliverer := newDeliver(senders[0], accStore) - checker := check{ - store: deliverer.store, - sender: senders[0], - } - - txDeclareCandidacy := newTxDeclareCandidacy(10, pks[0]) - got := deliverer.declareCandidacy(txDeclareCandidacy) - assert.NoError(got, "expected no error on runTxDeclareCandidacy") - - // one sender can bond to two different pubKeys - txDeclareCandidacy.PubKey = pks[1] - err := checker.declareCandidacy(txDeclareCandidacy) - assert.Nil(err, "didn't expected error on checkTx") - - // two senders cant bond to the same pubkey - checker.sender = senders[1] - txDeclareCandidacy.PubKey = pks[0] - err = checker.declareCandidacy(txDeclareCandidacy) - assert.NotNil(err, "expected error on checkTx") -} - -func TestIncrementsTxDelegate(t *testing.T) { - assert := assert.New(t) - initSender := int64(1000) - senders, accStore := initAccounts(1, initSender) // for accounts - deliverer := newDeliver(senders[0], accStore) - - // first declare candidacy - bondAmount := int64(10) - txDeclareCandidacy := newTxDeclareCandidacy(bondAmount, pks[0]) - got := deliverer.declareCandidacy(txDeclareCandidacy) - assert.NoError(got, "expected declare candidacy tx to be ok, got %v", got) - expectedBond := bondAmount // 1 since we send 1 at the start of loop, - - // just send the same txbond multiple times - holder := deliverer.params.HoldUnbonded // XXX this should be HoldBonded, new SDK updates - txDelegate := newTxDelegate(bondAmount, pks[0]) - for i := 0; i < 5; i++ { - got := deliverer.delegate(txDelegate) - assert.NoError(got, "expected tx %d to be ok, got %v", i, got) - - //Check that the accounts and the bond account have the appropriate values - candidates := loadCandidates(deliverer.store) - expectedBond += bondAmount - expectedSender := initSender - expectedBond - gotBonded := candidates[0].Liabilities.Evaluate() - gotHolder := accStore[string(holder.Address)] - gotSender := accStore[string(deliverer.sender.Address)] - assert.Equal(expectedBond, gotBonded, "i: %v, %v, %v", i, expectedBond, gotBonded) - assert.Equal(expectedBond, gotHolder, "i: %v, %v, %v", i, expectedBond, gotHolder) - assert.Equal(expectedSender, gotSender, "i: %v, %v, %v", i, expectedSender, gotSender) - } -} - -func TestIncrementsTxUnbond(t *testing.T) { - assert := assert.New(t) - initSender := int64(0) - senders, accStore := initAccounts(1, initSender) // for accounts - deliverer := newDeliver(senders[0], accStore) - - // set initial bond - initBond := int64(1000) - accStore[string(deliverer.sender.Address)] = initBond - got := deliverer.declareCandidacy(newTxDeclareCandidacy(initBond, pks[0])) - assert.NoError(got, "expected initial bond tx to be ok, got %v", got) - - // just send the same txunbond multiple times - holder := deliverer.params.HoldUnbonded // XXX new SDK, this should be HoldBonded - - // XXX use decimals here - unbondShares, unbondSharesStr := int64(10), "10" - txUndelegate := newTxUnbond(unbondSharesStr, pks[0]) - nUnbonds := 5 - for i := 0; i < nUnbonds; i++ { - got := deliverer.unbond(txUndelegate) - assert.NoError(got, "expected tx %d to be ok, got %v", i, got) - - //Check that the accounts and the bond account have the appropriate values - candidates := loadCandidates(deliverer.store) - expectedBond := initBond - int64(i+1)*unbondShares // +1 since we send 1 at the start of loop - expectedSender := initSender + (initBond - expectedBond) - gotBonded := candidates[0].Liabilities.Evaluate() - gotHolder := accStore[string(holder.Address)] - gotSender := accStore[string(deliverer.sender.Address)] - - assert.Equal(expectedBond, gotBonded, "%v, %v", expectedBond, gotBonded) - assert.Equal(expectedBond, gotHolder, "%v, %v", expectedBond, gotHolder) - assert.Equal(expectedSender, gotSender, "%v, %v", expectedSender, gotSender) - } - - // these are more than we have bonded now - errorCases := []int64{ - //1<<64 - 1, // more than int64 - //1<<63 + 1, // more than int64 - 1<<63 - 1, - 1 << 31, - initBond, - } - for _, c := range errorCases { - unbondShares := strconv.Itoa(int(c)) - txUndelegate := newTxUnbond(unbondShares, pks[0]) - got = deliverer.unbond(txUndelegate) - assert.Error(got, "expected unbond tx to fail") - } - - leftBonded := initBond - unbondShares*int64(nUnbonds) - - // should be unable to unbond one more than we have - txUndelegate = newTxUnbond(strconv.Itoa(int(leftBonded)+1), pks[0]) - got = deliverer.unbond(txUndelegate) - assert.Error(got, "expected unbond tx to fail") - - // should be able to unbond just what we have - txUndelegate = newTxUnbond(strconv.Itoa(int(leftBonded)), pks[0]) - got = deliverer.unbond(txUndelegate) - assert.NoError(got, "expected unbond tx to pass") -} - -func TestMultipleTxDeclareCandidacy(t *testing.T) { - assert := assert.New(t) - initSender := int64(1000) - senders, accStore := initAccounts(3, initSender) - pubKeys := []crypto.PubKey{pks[0], pks[1], pks[2]} - deliverer := newDeliver(senders[0], accStore) - - // bond them all - for i, sender := range senders { - txDeclareCandidacy := newTxDeclareCandidacy(10, pubKeys[i]) - deliverer.sender = sender - got := deliverer.declareCandidacy(txDeclareCandidacy) - assert.NoError(got, "expected tx %d to be ok, got %v", i, got) - - //Check that the account is bonded - candidates := loadCandidates(deliverer.store) - val := candidates[i] - balanceGot, balanceExpd := accStore[string(val.Owner.Address)], initSender-10 - assert.Equal(i+1, len(candidates), "expected %d candidates got %d, candidates: %v", i+1, len(candidates), candidates) - assert.Equal(10, int(val.Liabilities.Evaluate()), "expected %d shares, got %d", 10, val.Liabilities) - assert.Equal(balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) - } - - // unbond them all - for i, sender := range senders { - candidatePre := loadCandidate(deliverer.store, pubKeys[i]) - txUndelegate := newTxUnbond("10", pubKeys[i]) - deliverer.sender = sender - got := deliverer.unbond(txUndelegate) - assert.NoError(got, "expected tx %d to be ok, got %v", i, got) - - //Check that the account is unbonded - candidates := loadCandidates(deliverer.store) - assert.Equal(len(senders)-(i+1), len(candidates), "expected %d candidates got %d", len(senders)-(i+1), len(candidates)) - - candidatePost := loadCandidate(deliverer.store, pubKeys[i]) - balanceGot, balanceExpd := accStore[string(candidatePre.Owner.Address)], initSender - assert.Nil(candidatePost, "expected nil candidate retrieve, got %d", 0, candidatePost) - assert.Equal(balanceExpd, balanceGot, "expected account to have %d, got %d", balanceExpd, balanceGot) - } -} - -func TestMultipleTxDelegate(t *testing.T) { - assert, require := assert.New(t), require.New(t) - accounts, accStore := initAccounts(3, 1000) - sender, delegators := accounts[0], accounts[1:] - deliverer := newDeliver(sender, accStore) - - //first make a candidate - txDeclareCandidacy := newTxDeclareCandidacy(10, pks[0]) - got := deliverer.declareCandidacy(txDeclareCandidacy) - require.NoError(got, "expected tx to be ok, got %v", got) - - // delegate multiple parties - for i, delegator := range delegators { - txDelegate := newTxDelegate(10, pks[0]) - deliverer.sender = delegator - got := deliverer.delegate(txDelegate) - require.NoError(got, "expected tx %d to be ok, got %v", i, got) - - //Check that the account is bonded - bond := loadDelegatorBond(deliverer.store, delegator, pks[0]) - assert.NotNil(bond, "expected delegatee bond %d to exist", bond) - } - - // unbond them all - for i, delegator := range delegators { - txUndelegate := newTxUnbond("10", pks[0]) - deliverer.sender = delegator - got := deliverer.unbond(txUndelegate) - require.NoError(got, "expected tx %d to be ok, got %v", i, got) - - //Check that the account is unbonded - bond := loadDelegatorBond(deliverer.store, delegator, pks[0]) - assert.Nil(bond, "expected delegatee bond %d to be nil", bond) - } -} - -func TestVoidCandidacy(t *testing.T) { - assert, require := assert.New(t), require.New(t) - accounts, accStore := initAccounts(2, 1000) // for accounts - sender, delegator := accounts[0], accounts[1] - deliverer := newDeliver(sender, accStore) - - // create the candidate - txDeclareCandidacy := newTxDeclareCandidacy(10, pks[0]) - got := deliverer.declareCandidacy(txDeclareCandidacy) - require.NoError(got, "expected no error on runTxDeclareCandidacy") - - // bond a delegator - txDelegate := newTxDelegate(10, pks[0]) - deliverer.sender = delegator - got = deliverer.delegate(txDelegate) - require.NoError(got, "expected ok, got %v", got) - - // unbond the candidates bond portion - txUndelegate := newTxUnbond("10", pks[0]) - deliverer.sender = sender - got = deliverer.unbond(txUndelegate) - require.NoError(got, "expected no error on runTxDeclareCandidacy") - - // test that this pubkey cannot yet be bonded too - deliverer.sender = delegator - got = deliverer.delegate(txDelegate) - assert.Error(got, "expected error, got %v", got) - - // test that the delegator can still withdraw their bonds - got = deliverer.unbond(txUndelegate) - require.NoError(got, "expected no error on runTxDeclareCandidacy") - - // verify that the pubkey can now be reused - got = deliverer.declareCandidacy(txDeclareCandidacy) - assert.NoError(got, "expected ok, got %v", got) - -} diff --git a/x/stake/rest/query.go b/x/stake/rest/query.go deleted file mode 100644 index 48e54cfe81..0000000000 --- a/x/stake/rest/query.go +++ /dev/null @@ -1,188 +0,0 @@ -package rest - -import ( - "fmt" - "net/http" - - "github.com/gorilla/mux" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/client/commands/query" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/stack" - - "github.com/cosmos/gaia/modules/stake" - scmds "github.com/cosmos/gaia/modules/stake/commands" - - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/tmlibs/common" -) - -// RegisterQueryCandidate is a mux.Router handler that exposes GET -// method access on route /query/stake/candidate/{pubkey} to query a candidate -func RegisterQueryCandidate(r *mux.Router) error { - r.HandleFunc("/query/stake/candidate/{pubkey}", queryCandidate).Methods("GET") - return nil -} - -// RegisterQueryCandidates is a mux.Router handler that exposes GET -// method access on route /query/stake/candidate to query the group of all candidates -func RegisterQueryCandidates(r *mux.Router) error { - r.HandleFunc("/query/stake/candidates", queryCandidates).Methods("GET") - return nil -} - -// RegisterQueryDelegatorBond is a mux.Router handler that exposes GET -// method access on route /query/stake/candidate/{pubkey} to query a candidate -func RegisterQueryDelegatorBond(r *mux.Router) error { - r.HandleFunc("/query/stake/delegator/{address}/{pubkey}", queryDelegatorBond).Methods("GET") - return nil -} - -// RegisterQueryDelegatorCandidates is a mux.Router handler that exposes GET -// method access on route /query/stake/candidate to query the group of all candidates -func RegisterQueryDelegatorCandidates(r *mux.Router) error { - r.HandleFunc("/query/stake/delegator_candidates/{address}", queryDelegatorCandidates).Methods("GET") - return nil -} - -//--------------------------------------------------------------------- - -// queryCandidate is the HTTP handlerfunc to query a candidate -// it expects a query string -func queryCandidate(w http.ResponseWriter, r *http.Request) { - - // get the arguments object - args := mux.Vars(r) - prove := !viper.GetBool(commands.FlagTrustNode) // from viper because defined when starting server - - // get the pubkey - pkArg := args["pubkey"] - pk, err := scmds.GetPubKey(pkArg) - if err != nil { - common.WriteError(w, err) - return - } - - // get the candidate - var candidate stake.Candidate - key := stack.PrefixedKey(stake.Name(), stake.GetCandidateKey(pk)) - height, err := query.GetParsed(key, &candidate, query.GetHeight(), prove) - if client.IsNoDataErr(err) { - err := fmt.Errorf("candidate bytes are empty for pubkey: %q", pkArg) - common.WriteError(w, err) - return - } else if err != nil { - common.WriteError(w, err) - return - } - - // write the output - err = query.FoutputProof(w, candidate, height) - if err != nil { - common.WriteError(w, err) - } -} - -// queryCandidates is the HTTP handlerfunc to query the group of all candidates -func queryCandidates(w http.ResponseWriter, r *http.Request) { - - var pks []crypto.PubKey - - prove := !viper.GetBool(commands.FlagTrustNode) // from viper because defined when starting server - key := stack.PrefixedKey(stake.Name(), stake.CandidatesPubKeysKey) - height, err := query.GetParsed(key, &pks, query.GetHeight(), prove) - if err != nil { - common.WriteError(w, err) - return - } - - err = query.FoutputProof(w, pks, height) - if err != nil { - common.WriteError(w, err) - } -} - -// queryDelegatorBond is the HTTP handlerfunc to query a delegator bond it -// expects a query string -func queryDelegatorBond(w http.ResponseWriter, r *http.Request) { - - // get the arguments object - args := mux.Vars(r) - prove := !viper.GetBool(commands.FlagTrustNode) // from viper because defined when starting server - - // get the pubkey - pkArg := args["pubkey"] - pk, err := scmds.GetPubKey(pkArg) - if err != nil { - common.WriteError(w, err) - return - } - - // get the delegator actor - delegatorAddr := args["address"] - delegator, err := commands.ParseActor(delegatorAddr) - if err != nil { - common.WriteError(w, err) - return - } - delegator = coin.ChainAddr(delegator) - - // get the bond - var bond stake.DelegatorBond - key := stack.PrefixedKey(stake.Name(), stake.GetDelegatorBondKey(delegator, pk)) - height, err := query.GetParsed(key, &bond, query.GetHeight(), prove) - if client.IsNoDataErr(err) { - err := fmt.Errorf("bond bytes are empty for pubkey: %q, address: %q", pkArg, delegatorAddr) - common.WriteError(w, err) - return - } else if err != nil { - common.WriteError(w, err) - return - } - - // write the output - err = query.FoutputProof(w, bond, height) - if err != nil { - common.WriteError(w, err) - } -} - -// queryDelegatorCandidates is the HTTP handlerfunc to query a delegator bond it -// expects a query string -func queryDelegatorCandidates(w http.ResponseWriter, r *http.Request) { - - // get the arguments object - args := mux.Vars(r) - prove := !viper.GetBool(commands.FlagTrustNode) // from viper because defined when starting server - - // get the delegator actor - delegatorAddr := args["address"] - delegator, err := commands.ParseActor(delegatorAddr) - if err != nil { - common.WriteError(w, err) - return - } - delegator = coin.ChainAddr(delegator) - - // get the bond - var bond stake.DelegatorBond - key := stack.PrefixedKey(stake.Name(), stake.GetDelegatorBondsKey(delegator)) - height, err := query.GetParsed(key, &bond, query.GetHeight(), prove) - if client.IsNoDataErr(err) { - err := fmt.Errorf("bond bytes are empty for address: %q", delegatorAddr) - common.WriteError(w, err) - return - } else if err != nil { - common.WriteError(w, err) - return - } - - // write the output - err = query.FoutputProof(w, bond, height) - if err != nil { - common.WriteError(w, err) - } -} diff --git a/x/stake/rest/tx.go b/x/stake/rest/tx.go deleted file mode 100644 index 090ea5abbc..0000000000 --- a/x/stake/rest/tx.go +++ /dev/null @@ -1,159 +0,0 @@ -package rest - -import ( - "net/http" - "strings" - - "github.com/gorilla/mux" - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/tmlibs/common" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/client/commands" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/modules/base" - "github.com/cosmos/cosmos-sdk/modules/coin" - "github.com/cosmos/cosmos-sdk/modules/fee" - "github.com/cosmos/cosmos-sdk/modules/nonce" - "github.com/cosmos/gaia/modules/stake" -) - -const ( - //parameters used in urls - paramPubKey = "pubkey" - paramAmount = "amount" - paramShares = "shares" - - paramName = "name" - paramKeybase = "keybase" - paramWebsite = "website" - paramDetails = "details" -) - -type delegateInput struct { - Fees *coin.Coin `json:"fees"` - Sequence uint32 `json:"sequence"` - - Pubkey crypto.PubKey `json:"pub_key"` - From *sdk.Actor `json:"from"` - Amount coin.Coin `json:"amount"` -} - -type unbondInput struct { - Fees *coin.Coin `json:"fees"` - Sequence uint32 `json:"sequence"` - - Pubkey crypto.PubKey `json:"pub_key"` - From *sdk.Actor `json:"from"` - Shares string `json:"amount"` -} - -// RegisterDelegate is a mux.Router handler that exposes -// POST method access on route /tx/stake/delegate to create a -// transaction for delegate to a candidaate/validator -func RegisterDelegate(r *mux.Router) error { - r.HandleFunc("/build/stake/delegate", delegate).Methods("POST") - return nil -} - -// RegisterUnbond is a mux.Router handler that exposes -// POST method access on route /tx/stake/unbond to create a -// transaction for unbonding delegated coins -func RegisterUnbond(r *mux.Router) error { - r.HandleFunc("/build/stake/unbond", unbond).Methods("POST") - return nil -} - -func prepareDelegateTx(di *delegateInput) sdk.Tx { - tx := stake.NewTxDelegate(di.Amount, di.Pubkey) - // fees are optional - if di.Fees != nil && !di.Fees.IsZero() { - tx = fee.NewFee(tx, *di.Fees, *di.From) - } - // only add the actual signer to the nonce - signers := []sdk.Actor{*di.From} - tx = nonce.NewTx(di.Sequence, signers, tx) - tx = base.NewChainTx(commands.GetChainID(), 0, tx) - - tx = auth.NewSig(tx).Wrap() - return tx -} - -func delegate(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - di := new(delegateInput) - if err := common.ParseRequestAndValidateJSON(r, di); err != nil { - common.WriteError(w, err) - return - } - - var errsList []string - if di.From == nil { - errsList = append(errsList, `"from" cannot be nil`) - } - if di.Sequence <= 0 { - errsList = append(errsList, `"sequence" must be > 0`) - } - if di.Pubkey.Empty() { - errsList = append(errsList, `"pubkey" cannot be empty`) - } - if len(errsList) > 0 { - code := http.StatusBadRequest - err := &common.ErrorResponse{ - Err: strings.Join(errsList, ", "), - Code: code, - } - common.WriteCode(w, err, code) - return - } - - tx := prepareDelegateTx(di) - common.WriteSuccess(w, tx) -} - -func prepareUnbondTx(ui *unbondInput) sdk.Tx { - tx := stake.NewTxUnbond(ui.Shares, ui.Pubkey) - // fees are optional - if ui.Fees != nil && !ui.Fees.IsZero() { - tx = fee.NewFee(tx, *ui.Fees, *ui.From) - } - // only add the actual signer to the nonce - signers := []sdk.Actor{*ui.From} - tx = nonce.NewTx(ui.Sequence, signers, tx) - tx = base.NewChainTx(commands.GetChainID(), 0, tx) - - tx = auth.NewSig(tx).Wrap() - return tx -} - -func unbond(w http.ResponseWriter, r *http.Request) { - defer r.Body.Close() - ui := new(unbondInput) - if err := common.ParseRequestAndValidateJSON(r, ui); err != nil { - common.WriteError(w, err) - return - } - - var errsList []string - if ui.From == nil { - errsList = append(errsList, `"from" cannot be nil`) - } - if ui.Sequence <= 0 { - errsList = append(errsList, `"sequence" must be > 0`) - } - if ui.Pubkey.Empty() { - errsList = append(errsList, `"pubkey" cannot be empty`) - } - if len(errsList) > 0 { - code := http.StatusBadRequest - err := &common.ErrorResponse{ - Err: strings.Join(errsList, ", "), - Code: code, - } - common.WriteCode(w, err, code) - return - } - - tx := prepareUnbondTx(ui) - common.WriteSuccess(w, tx) -} diff --git a/x/stake/state.go b/x/stake/store.go similarity index 71% rename from x/stake/state.go rename to x/stake/store.go index e037d837b2..f62aa46e49 100644 --- a/x/stake/state.go +++ b/x/stake/store.go @@ -6,8 +6,7 @@ import ( crypto "github.com/tendermint/go-crypto" "github.com/tendermint/go-wire" - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" + "github.com/cosmos/cosmos-sdk/types" ) // nolint @@ -29,41 +28,52 @@ func GetCandidateKey(pubKey crypto.PubKey) []byte { } // GetDelegatorBondKey - get the key for delegator bond with candidate -func GetDelegatorBondKey(delegator sdk.Actor, candidate crypto.PubKey) []byte { +func GetDelegatorBondKey(delegator crypto.Address, candidate crypto.PubKey) []byte { return append(GetDelegatorBondKeyPrefix(delegator), candidate.Bytes()...) } // GetDelegatorBondKeyPrefix - get the prefix for a delegator for all candidates -func GetDelegatorBondKeyPrefix(delegator sdk.Actor) []byte { - return append(DelegatorBondKeyPrefix, wire.BinaryBytes(&delegator)...) +func GetDelegatorBondKeyPrefix(delegator crypto.Address) []byte { + res, err := wire.MarshalBinary(&delegator) + if err != nil { + panic(err) + } + return append(DelegatorBondKeyPrefix, res...) } // GetDelegatorBondsKey - get the key for list of all the delegator's bonds -func GetDelegatorBondsKey(delegator sdk.Actor) []byte { - return append(DelegatorBondsKeyPrefix, wire.BinaryBytes(&delegator)...) +func GetDelegatorBondsKey(delegator crypto.Address) []byte { + res, err := wire.MarshalBinary(&delegator) + if err != nil { + panic(err) + } + return append(DelegatorBondsKeyPrefix, res...) } //--------------------------------------------------------------------- // Get the active list of all the candidate pubKeys and owners -func loadCandidatesPubKeys(store state.SimpleDB) (pubKeys []crypto.PubKey) { +func loadCandidatesPubKeys(store types.KVStore) (pubKeys []crypto.PubKey) { bytes := store.Get(CandidatesPubKeysKey) if bytes == nil { return } - err := wire.ReadBinaryBytes(bytes, &pubKeys) + err := wire.UnmarshalBinary(bytes, &pubKeys) if err != nil { panic(err) } return } -func saveCandidatesPubKeys(store state.SimpleDB, pubKeys []crypto.PubKey) { - b := wire.BinaryBytes(pubKeys) +func saveCandidatesPubKeys(store types.KVStore, pubKeys []crypto.PubKey) { + b, err := wire.MarshalBinary(pubKeys) + if err != nil { + panic(err) + } store.Set(CandidatesPubKeysKey, b) } // loadCandidates - get the active list of all candidates TODO replace with multistore -func loadCandidates(store state.SimpleDB) (candidates Candidates) { +func loadCandidates(store types.KVStore) (candidates Candidates) { pks := loadCandidatesPubKeys(store) for _, pk := range pks { candidates = append(candidates, loadCandidate(store, pk)) @@ -74,10 +84,10 @@ func loadCandidates(store state.SimpleDB) (candidates Candidates) { //--------------------------------------------------------------------- // loadCandidate - loads the candidate object for the provided pubkey -func loadCandidate(store state.SimpleDB, pubKey crypto.PubKey) *Candidate { - if pubKey.Empty() { - return nil - } +func loadCandidate(store types.KVStore, pubKey crypto.PubKey) *Candidate { + //if pubKey.Empty() { + //return nil + //} b := store.Get(GetCandidateKey(pubKey)) if b == nil { return nil @@ -90,7 +100,7 @@ func loadCandidate(store state.SimpleDB, pubKey crypto.PubKey) *Candidate { return candidate } -func saveCandidate(store state.SimpleDB, candidate *Candidate) { +func saveCandidate(store types.KVStore, candidate *Candidate) { if !store.Has(GetCandidateKey(candidate.PubKey)) { // TODO to be replaced with iteration in the multistore? @@ -105,8 +115,8 @@ func saveCandidate(store state.SimpleDB, candidate *Candidate) { store.Set(GetCandidateKey(candidate.PubKey), b) } -func removeCandidate(store state.SimpleDB, pubKey crypto.PubKey) { - store.Remove(GetCandidateKey(pubKey)) +func removeCandidate(store types.KVStore, pubKey crypto.PubKey) { + store.Delete(GetCandidateKey(pubKey)) // TODO to be replaced with iteration in the multistore? pks := loadCandidatesPubKeys(store) @@ -122,15 +132,15 @@ func removeCandidate(store state.SimpleDB, pubKey crypto.PubKey) { //--------------------------------------------------------------------- // load the pubkeys of all candidates a delegator is delegated too -func loadDelegatorCandidates(store state.SimpleDB, - delegator sdk.Actor) (candidates []crypto.PubKey) { +func loadDelegatorCandidates(store types.KVStore, + delegator crypto.Address) (candidates []crypto.PubKey) { candidateBytes := store.Get(GetDelegatorBondsKey(delegator)) if candidateBytes == nil { return nil } - err := wire.ReadBinaryBytes(candidateBytes, &candidates) + err := wire.UnmarshalBinary(candidateBytes, &candidates) if err != nil { panic(err) } @@ -139,8 +149,8 @@ func loadDelegatorCandidates(store state.SimpleDB, //--------------------------------------------------------------------- -func loadDelegatorBond(store state.SimpleDB, - delegator sdk.Actor, candidate crypto.PubKey) *DelegatorBond { +func loadDelegatorBond(store types.KVStore, + delegator crypto.Address, candidate crypto.PubKey) *DelegatorBond { delegatorBytes := store.Get(GetDelegatorBondKey(delegator, candidate)) if delegatorBytes == nil { @@ -155,13 +165,16 @@ func loadDelegatorBond(store state.SimpleDB, return bond } -func saveDelegatorBond(store state.SimpleDB, delegator sdk.Actor, bond *DelegatorBond) { +func saveDelegatorBond(store types.KVStore, delegator crypto.Address, bond *DelegatorBond) { // if a new bond add to the list of bonds if loadDelegatorBond(store, delegator, bond.PubKey) == nil { pks := loadDelegatorCandidates(store, delegator) pks = append(pks, (*bond).PubKey) - b := wire.BinaryBytes(pks) + b, err := wire.MarshalBinary(pks) + if err != nil { + panic(err) + } store.Set(GetDelegatorBondsKey(delegator), b) } @@ -174,7 +187,7 @@ func saveDelegatorBond(store state.SimpleDB, delegator sdk.Actor, bond *Delegato //updateDelegatorBonds(store, delegator) } -func removeDelegatorBond(store state.SimpleDB, delegator sdk.Actor, candidate crypto.PubKey) { +func removeDelegatorBond(store types.KVStore, delegator crypto.Address, candidate crypto.PubKey) { // TODO use list queries on multistore to remove iterations here! // first remove from the list of bonds @@ -184,16 +197,19 @@ func removeDelegatorBond(store state.SimpleDB, delegator sdk.Actor, candidate cr pks = append(pks[:i], pks[i+1:]...) } } - b := wire.BinaryBytes(pks) + b, err := wire.MarshalBinary(pks) + if err != nil { + panic(err) + } store.Set(GetDelegatorBondsKey(delegator), b) // now remove the actual bond - store.Remove(GetDelegatorBondKey(delegator, candidate)) + store.Delete(GetDelegatorBondKey(delegator, candidate)) //updateDelegatorBonds(store, delegator) } -//func updateDelegatorBonds(store state.SimpleDB, -//delegator sdk.Actor) { +//func updateDelegatorBonds(store types.KVStore, +//delegator crypto.Address) { //var bonds []*DelegatorBond @@ -209,7 +225,7 @@ func removeDelegatorBond(store state.SimpleDB, delegator sdk.Actor, candidate cr //} //bond := new(DelegatorBond) -//err := wire.ReadBinaryBytes(delegatorBytes, bond) +//err := wire.UnmarshalBinary(delegatorBytes, bond) //if err != nil { //panic(err) //} @@ -221,14 +237,14 @@ func removeDelegatorBond(store state.SimpleDB, delegator sdk.Actor, candidate cr //return //} -//b := wire.BinaryBytes(bonds) +//b := wire.MarshalBinary(bonds) //store.Set(GetDelegatorBondsKey(delegator), b) //} //_______________________________________________________________________ // load/save the global staking params -func loadParams(store state.SimpleDB) (params Params) { +func loadParams(store types.KVStore) (params Params) { b := store.Get(ParamKey) if b == nil { return defaultParams() @@ -241,7 +257,7 @@ func loadParams(store state.SimpleDB) (params Params) { return } -func saveParams(store state.SimpleDB, params Params) { +func saveParams(store types.KVStore, params Params) { b, err := json.Marshal(params) if err != nil { panic(err) @@ -252,7 +268,7 @@ func saveParams(store state.SimpleDB, params Params) { //_______________________________________________________________________ // load/save the global staking state -func loadGlobalState(store state.SimpleDB) (gs *GlobalState) { +func loadGlobalState(store types.KVStore) (gs *GlobalState) { b := store.Get(GlobalStateKey) if b == nil { return initialGlobalState() @@ -264,7 +280,7 @@ func loadGlobalState(store state.SimpleDB) (gs *GlobalState) { } return } -func saveGlobalState(store state.SimpleDB, gs *GlobalState) { +func saveGlobalState(store types.KVStore, gs *GlobalState) { b, err := json.Marshal(*gs) if err != nil { panic(err) diff --git a/x/stake/state_test.go b/x/stake/store_test.go similarity index 70% rename from x/stake/state_test.go rename to x/stake/store_test.go index 919dfc4c44..d2c6839cb3 100644 --- a/x/stake/state_test.go +++ b/x/stake/store_test.go @@ -1,31 +1,51 @@ package stake import ( + "bytes" + "encoding/hex" "testing" - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/auth" - "github.com/cosmos/cosmos-sdk/store" + sdkstore "github.com/cosmos/cosmos-sdk/store" + "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + crypto "github.com/tendermint/go-crypto" + dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/rational" ) +func newPubKey(pk string) (res crypto.PubKey, err error) { + pkBytes, err := hex.DecodeString(pk) + if err != nil { + return + } + //res, err = crypto.PubKeyFromBytes(pkBytes) + var pkEd crypto.PubKeyEd25519 + copy(pkEd[:], pkBytes[:]) + return pkEd, nil +} + func TestState(t *testing.T) { assert, require := assert.New(t), require.New(t) db, err := dbm.NewGoLevelDB("basecoin", "basecoin-data") require.Nil(err) - mainLoader := store.NewIAVLStoreLoader(int64(100), 10000, numHistory) - var mainStoreKey = sdk.NewKVStoreKey("main") - multiStore := store.NewCommitMultiStore(db) - multiStore.SetSubstoreLoader(mainStoreKey, mainLoader) - var store = auth.NewAccountStore(mainStoreKey, bcm.AppAccountCodec{}) + cacheSize := 10000 + numHistory := int64(100) + stakeLoader := sdkstore.NewIAVLStoreLoader(db, cacheSize, numHistory) + var stakeStoreKey = types.NewKVStoreKey("stake") + multiStore := sdkstore.NewCommitMultiStore(db) + multiStore.SetSubstoreLoader(stakeStoreKey, stakeLoader) + multiStore.LoadLatestVersion() + store := multiStore.GetKVStore(stakeStoreKey) - delegator := sdk.Actor{"testChain", "testapp", []byte("addressdelegator")} - validator := sdk.Actor{"testChain", "testapp", []byte("addressvalidator")} + //delegator := crypto.Address{[]byte("addressdelegator")} + //validator := crypto.Address{[]byte("addressvalidator")} + delegator := []byte("addressdelegator") + validator := []byte("addressvalidator") - pk := newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB57") + pk, err := newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB57") + require.Nil(err) //---------------------------------------------------------------------- // Candidate checks @@ -42,7 +62,7 @@ func TestState(t *testing.T) { candidatesEqual := func(c1, c2 *Candidate) bool { return c1.Status == c2.Status && c1.PubKey.Equals(c2.PubKey) && - c1.Owner.Equals(c2.Owner) && + bytes.Equal(c1.Owner, c2.Owner) && c1.Assets.Equal(c2.Assets) && c1.Liabilities.Equal(c2.Liabilities) && c1.VotingPower.Equal(c2.VotingPower) && diff --git a/x/stake/test_common.go b/x/stake/test_common.go deleted file mode 100644 index 17d26d9230..0000000000 --- a/x/stake/test_common.go +++ /dev/null @@ -1,91 +0,0 @@ -package stake - -import ( - "encoding/hex" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" - "github.com/tendermint/tmlibs/rational" - - "github.com/cosmos/cosmos-sdk" -) - -func newActors(n int) (actors []sdk.Actor) { - for i := 0; i < n; i++ { - actors = append(actors, sdk.Actor{ - "testChain", "testapp", []byte(fmt.Sprintf("addr%d", i))}) - } - - return -} - -func newPubKey(pk string) crypto.PubKey { - pkBytes, _ := hex.DecodeString(pk) - var pkEd crypto.PubKeyEd25519 - copy(pkEd[:], pkBytes[:]) - return pkEd.Wrap() -} - -// dummy pubkeys used for testing -var pks = []crypto.PubKey{ - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB53"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB54"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB55"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB56"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB57"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB58"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB59"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB60"), -} - -// NOTE: PubKey is supposed to be the binaryBytes of the crypto.PubKey -// instead this is just being set the address here for testing purposes -func candidatesFromActors(actors []sdk.Actor, amts []int64) (candidates Candidates) { - for i := 0; i < len(actors); i++ { - c := &Candidate{ - Status: Unbonded, - PubKey: pks[i], - Owner: actors[i], - Assets: rational.New(amts[i]), - Liabilities: rational.New(amts[i]), - VotingPower: rational.New(amts[i]), - } - candidates = append(candidates, c) - } - - return -} - -func candidatesFromActorsEmpty(actors []sdk.Actor) (candidates Candidates) { - for i := 0; i < len(actors); i++ { - c := &Candidate{ - Status: Unbonded, - PubKey: pks[i], - Owner: actors[i], - Assets: rational.Zero, - Liabilities: rational.Zero, - VotingPower: rational.Zero, - } - candidates = append(candidates, c) - } - return -} - -// helper function test if Candidate is changed asabci.Validator -func testChange(t *testing.T, val Validator, chg *abci.Validator) { - assert := assert.New(t) - assert.Equal(val.PubKey.Bytes(), chg.PubKey) - assert.Equal(val.VotingPower.Evaluate(), chg.Power) -} - -// helper function test if Candidate is removed as abci.Validator -func testRemove(t *testing.T, val Validator, chg *abci.Validator) { - assert := assert.New(t) - assert.Equal(val.PubKey.Bytes(), chg.PubKey) - assert.Equal(int64(0), chg.Power) -} diff --git a/x/stake/tick.go b/x/stake/tick.go deleted file mode 100644 index 678a01ccd4..0000000000 --- a/x/stake/tick.go +++ /dev/null @@ -1,75 +0,0 @@ -package stake - -import ( - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" - - abci "github.com/tendermint/abci/types" - "github.com/tendermint/tmlibs/rational" -) - -// Tick - called at the end of every block -func Tick(ctx sdk.Context, store state.SimpleDB) (change []*abci.Validator, err error) { - - // retrieve params - params := loadParams(store) - gs := loadGlobalState(store) - height := ctx.BlockHeight() - - // Process Validator Provisions - // XXX right now just process every 5 blocks, in new SDK make hourly - if gs.InflationLastTime+5 <= height { - gs.InflationLastTime = height - processProvisions(store, gs, params) - } - - return UpdateValidatorSet(store, gs, params) -} - -var hrsPerYr = rational.New(8766) // as defined by a julian year of 365.25 days - -// process provisions for an hour period -func processProvisions(store state.SimpleDB, gs *GlobalState, params Params) { - - gs.Inflation = nextInflation(gs, params).Round(1000000000) - - // Because the validators hold a relative bonded share (`GlobalStakeShare`), when - // more bonded tokens are added proportionally to all validators the only term - // which needs to be updated is the `BondedPool`. So for each previsions cycle: - - provisions := gs.Inflation.Mul(rational.New(gs.TotalSupply)).Quo(hrsPerYr).Evaluate() - gs.BondedPool += provisions - gs.TotalSupply += provisions - - // XXX XXX XXX XXX XXX XXX XXX XXX XXX - // XXX Mint them to the hold account - // XXX XXX XXX XXX XXX XXX XXX XXX XXX - - // save the params - saveGlobalState(store, gs) -} - -// get the next inflation rate for the hour -func nextInflation(gs *GlobalState, params Params) (inflation rational.Rat) { - - // The target annual inflation rate is recalculated for each previsions cycle. The - // inflation is also subject to a rate change (positive of negative) depending or - // the distance from the desired ratio (67%). The maximum rate change possible is - // defined to be 13% per year, however the annual inflation is capped as between - // 7% and 20%. - - // (1 - bondedRatio/GoalBonded) * InflationRateChange - inflationRateChangePerYear := rational.One.Sub(gs.bondedRatio().Quo(params.GoalBonded)).Mul(params.InflationRateChange) - inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYr) - - // increase the new annual inflation for this next cycle - inflation = gs.Inflation.Add(inflationRateChange) - if inflation.GT(params.InflationMax) { - inflation = params.InflationMax - } - if inflation.LT(params.InflationMin) { - inflation = params.InflationMin - } - - return -} diff --git a/x/stake/tick_test.go b/x/stake/tick_test.go deleted file mode 100644 index 3a80ae2a3b..0000000000 --- a/x/stake/tick_test.go +++ /dev/null @@ -1,120 +0,0 @@ -package stake - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/tendermint/tmlibs/rational" - - "github.com/cosmos/cosmos-sdk/state" -) - -func TestGetInflation(t *testing.T) { - assert := assert.New(t) - store := state.NewMemKVStore() - params := loadParams(store) - gs := loadGlobalState(store) - - // Governing Mechanism: - // bondedRatio = BondedPool / TotalSupply - // inflationRateChangePerYear = (1- bondedRatio/ GoalBonded) * MaxInflationRateChange - - tests := []struct { - setBondedPool, setTotalSupply int64 - setInflation, expectedChange rational.Rat - }{ - // with 0% bonded atom supply the inflation should increase by InflationRateChange - {0, 0, rational.New(7, 100), params.InflationRateChange.Quo(hrsPerYr)}, - - // 100% bonded, starting at 20% inflation and being reduced - {1, 1, rational.New(20, 100), rational.One.Sub(rational.One.Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYr)}, - - // 50% bonded, starting at 10% inflation and being increased - {1, 2, rational.New(10, 100), rational.One.Sub(rational.New(1, 2).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYr)}, - - // test 7% minimum stop (testing with 100% bonded) - {1, 1, rational.New(7, 100), rational.Zero}, - {1, 1, rational.New(70001, 1000000), rational.New(-1, 1000000)}, - - // test 20% maximum stop (testing with 0% bonded) - {0, 0, rational.New(20, 100), rational.Zero}, - {0, 0, rational.New(199999, 1000000), rational.New(1, 1000000)}, - - // perfect balance shouldn't change inflation - {67, 100, rational.New(15, 100), rational.Zero}, - } - for _, tc := range tests { - gs.BondedPool, gs.TotalSupply = tc.setBondedPool, tc.setTotalSupply - gs.Inflation = tc.setInflation - - inflation := nextInflation(gs, params) - diffInflation := inflation.Sub(tc.setInflation) - - assert.True(diffInflation.Equal(tc.expectedChange), - "%v, %v", diffInflation, tc.expectedChange) - } -} - -func TestProcessProvisions(t *testing.T) { - assert := assert.New(t) - store := state.NewMemKVStore() - params := loadParams(store) - gs := loadGlobalState(store) - - // create some candidates some bonded, some unbonded - n := 10 - actors := newActors(n) - candidates := candidatesFromActorsEmpty(actors) - for i, candidate := range candidates { - if i < 5 { - candidate.Status = Bonded - } - mintedTokens := int64((i + 1) * 10000000) - gs.TotalSupply += mintedTokens - candidate.addTokens(mintedTokens, gs) - saveCandidate(store, candidate) - } - var totalSupply int64 = 550000000 - var bondedShares int64 = 150000000 - var unbondedShares int64 = 400000000 - - // initial bonded ratio ~ 27% - assert.True(gs.bondedRatio().Equal(rational.New(bondedShares, totalSupply)), "%v", gs.bondedRatio()) - - // Supplies - assert.Equal(totalSupply, gs.TotalSupply) - assert.Equal(bondedShares, gs.BondedPool) - assert.Equal(unbondedShares, gs.UnbondedPool) - - // test the value of candidate shares - assert.True(gs.bondedShareExRate().Equal(rational.One), "%v", gs.bondedShareExRate()) - - initialSupply := gs.TotalSupply - initialUnbonded := gs.TotalSupply - gs.BondedPool - - // process the provisions a year - for hr := 0; hr < 8766; hr++ { - expInflation := nextInflation(gs, params).Round(1000000000) - expProvisions := (expInflation.Mul(rational.New(gs.TotalSupply)).Quo(hrsPerYr)).Evaluate() - startBondedPool := gs.BondedPool - startTotalSupply := gs.TotalSupply - processProvisions(store, gs, params) - assert.Equal(startBondedPool+expProvisions, gs.BondedPool) - assert.Equal(startTotalSupply+expProvisions, gs.TotalSupply) - } - assert.NotEqual(initialSupply, gs.TotalSupply) - assert.Equal(initialUnbonded, gs.UnbondedPool) - //panic(fmt.Sprintf("debug total %v, bonded %v, diff %v\n", gs.TotalSupply, gs.BondedPool, gs.TotalSupply-gs.BondedPool)) - - // initial bonded ratio ~ 35% ~ 30% increase for bonded holders - assert.True(gs.bondedRatio().Equal(rational.New(105906511, 305906511)), "%v", gs.bondedRatio()) - - // global supply - assert.Equal(int64(611813022), gs.TotalSupply) - assert.Equal(int64(211813022), gs.BondedPool) - assert.Equal(unbondedShares, gs.UnbondedPool) - - // test the value of candidate shares - assert.True(gs.bondedShareExRate().Mul(rational.New(bondedShares)).Equal(rational.New(211813022)), "%v", gs.bondedShareExRate()) - -} diff --git a/x/stake/tx.go b/x/stake/tx.go deleted file mode 100644 index 951151dafd..0000000000 --- a/x/stake/tx.go +++ /dev/null @@ -1,147 +0,0 @@ -package stake - -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/coin" - crypto "github.com/tendermint/go-crypto" -) - -// Tx -//-------------------------------------------------------------------------------- - -// register the tx type with its validation logic -// make sure to use the name of the handler as the prefix in the tx type, -// so it gets routed properly -const ( - ByteTxDeclareCandidacy = 0x55 - ByteTxEditCandidacy = 0x56 - ByteTxDelegate = 0x57 - ByteTxUnbond = 0x58 - TypeTxDeclareCandidacy = stakingModuleName + "/declareCandidacy" - TypeTxEditCandidacy = stakingModuleName + "/editCandidacy" - TypeTxDelegate = stakingModuleName + "/delegate" - TypeTxUnbond = stakingModuleName + "/unbond" -) - -func init() { - sdk.TxMapper.RegisterImplementation(TxDeclareCandidacy{}, TypeTxDeclareCandidacy, ByteTxDeclareCandidacy) - sdk.TxMapper.RegisterImplementation(TxEditCandidacy{}, TypeTxEditCandidacy, ByteTxEditCandidacy) - sdk.TxMapper.RegisterImplementation(TxDelegate{}, TypeTxDelegate, ByteTxDelegate) - sdk.TxMapper.RegisterImplementation(TxUnbond{}, TypeTxUnbond, ByteTxUnbond) -} - -//Verify interface at compile time -var _, _, _, _ sdk.TxInner = &TxDeclareCandidacy{}, &TxEditCandidacy{}, &TxDelegate{}, &TxUnbond{} - -// BondUpdate - struct for bonding or unbonding transactions -type BondUpdate struct { - PubKey crypto.PubKey `json:"pub_key"` - Bond coin.Coin `json:"amount"` -} - -// ValidateBasic - Check for non-empty candidate, and valid coins -func (tx BondUpdate) ValidateBasic() error { - if tx.PubKey.Empty() { - return errCandidateEmpty - } - - coins := coin.Coins{tx.Bond} - if !coins.IsValid() { - return coin.ErrInvalidCoins() - } - if !coins.IsPositive() { - return fmt.Errorf("Amount must be > 0") - } - return nil -} - -// TxDeclareCandidacy - struct for unbonding transactions -type TxDeclareCandidacy struct { - BondUpdate - Description -} - -// NewTxDeclareCandidacy - new TxDeclareCandidacy -func NewTxDeclareCandidacy(bond coin.Coin, pubKey crypto.PubKey, description Description) sdk.Tx { - return TxDeclareCandidacy{ - BondUpdate{ - PubKey: pubKey, - Bond: bond, - }, - description, - }.Wrap() -} - -// Wrap - Wrap a Tx as a Basecoin Tx -func (tx TxDeclareCandidacy) Wrap() sdk.Tx { return sdk.Tx{tx} } - -// TxEditCandidacy - struct for editing a candidate -type TxEditCandidacy struct { - PubKey crypto.PubKey `json:"pub_key"` - Description -} - -// NewTxEditCandidacy - new TxEditCandidacy -func NewTxEditCandidacy(pubKey crypto.PubKey, description Description) sdk.Tx { - return TxEditCandidacy{ - PubKey: pubKey, - Description: description, - }.Wrap() -} - -// Wrap - Wrap a Tx as a Basecoin Tx -func (tx TxEditCandidacy) Wrap() sdk.Tx { return sdk.Tx{tx} } - -// ValidateBasic - Check for non-empty candidate, -func (tx TxEditCandidacy) ValidateBasic() error { - if tx.PubKey.Empty() { - return errCandidateEmpty - } - - empty := Description{} - if tx.Description == empty { - return fmt.Errorf("Transaction must include some information to modify") - } - return nil -} - -// TxDelegate - struct for bonding transactions -type TxDelegate struct{ BondUpdate } - -// NewTxDelegate - new TxDelegate -func NewTxDelegate(bond coin.Coin, pubKey crypto.PubKey) sdk.Tx { - return TxDelegate{BondUpdate{ - PubKey: pubKey, - Bond: bond, - }}.Wrap() -} - -// Wrap - Wrap a Tx as a Basecoin Tx -func (tx TxDelegate) Wrap() sdk.Tx { return sdk.Tx{tx} } - -// TxUnbond - struct for unbonding transactions -type TxUnbond struct { - PubKey crypto.PubKey `json:"pub_key"` - Shares string `json:"amount"` -} - -// NewTxUnbond - new TxUnbond -func NewTxUnbond(shares string, pubKey crypto.PubKey) sdk.Tx { - return TxUnbond{ - PubKey: pubKey, - Shares: shares, - }.Wrap() -} - -// Wrap - Wrap a Tx as a Basecoin Tx -func (tx TxUnbond) Wrap() sdk.Tx { return sdk.Tx{tx} } - -// ValidateBasic - Check for non-empty candidate, positive shares -func (tx TxUnbond) ValidateBasic() error { - if tx.PubKey.Empty() { - return errCandidateEmpty - } - return nil -} diff --git a/x/stake/tx_test.go b/x/stake/tx_test.go deleted file mode 100644 index f6d814589d..0000000000 --- a/x/stake/tx_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package stake - -import ( - "strconv" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/modules/coin" - - crypto "github.com/tendermint/go-crypto" - wire "github.com/tendermint/go-wire" -) - -var ( - validator = sdk.Actor{"testChain", "testapp", []byte("addressvalidator1")} - empty sdk.Actor - - coinPos = coin.Coin{"fermion", 1000} - coinZero = coin.Coin{"fermion", 0} - coinNeg = coin.Coin{"fermion", -10000} - coinPosNotAtoms = coin.Coin{"foo", 10000} - coinZeroNotAtoms = coin.Coin{"foo", 0} - coinNegNotAtoms = coin.Coin{"foo", -10000} -) - -func TestBondUpdateValidateBasic(t *testing.T) { - tests := []struct { - name string - PubKey crypto.PubKey - Bond coin.Coin - wantErr bool - }{ - {"basic good", pks[0], coinPos, false}, - {"empty delegator", crypto.PubKey{}, coinPos, true}, - {"zero coin", pks[0], coinZero, true}, - {"neg coin", pks[0], coinNeg, true}, - } - - for _, tc := range tests { - tx := TxDelegate{BondUpdate{ - PubKey: tc.PubKey, - Bond: tc.Bond, - }} - assert.Equal(t, tc.wantErr, tx.ValidateBasic() != nil, - "test: %v, tx.ValidateBasic: %v", tc.name, tx.ValidateBasic()) - } -} - -func TestAllAreTx(t *testing.T) { - assert := assert.New(t) - - // make sure all types construct properly - pubKey := newPubKey("1234567890") - bondAmt := 1234321 - bond := coin.Coin{Denom: "ATOM", Amount: int64(bondAmt)} - - // Note that Wrap is only defined on BondUpdate, so when you call it, - // you lose all info on the embedding type. Please add Wrap() - // method to all the parents - txDelegate := NewTxDelegate(bond, pubKey) - _, ok := txDelegate.Unwrap().(TxDelegate) - assert.True(ok, "%#v", txDelegate) - - txUnbond := NewTxUnbond(strconv.Itoa(bondAmt), pubKey) - _, ok = txUnbond.Unwrap().(TxUnbond) - assert.True(ok, "%#v", txUnbond) - - txDecl := NewTxDeclareCandidacy(bond, pubKey, Description{}) - _, ok = txDecl.Unwrap().(TxDeclareCandidacy) - assert.True(ok, "%#v", txDecl) - - txEditCan := NewTxEditCandidacy(pubKey, Description{}) - _, ok = txEditCan.Unwrap().(TxEditCandidacy) - assert.True(ok, "%#v", txEditCan) -} - -func TestSerializeTx(t *testing.T) { - assert := assert.New(t) - - // make sure all types construct properly - pubKey := newPubKey("1234567890") - bondAmt := 1234321 - bond := coin.Coin{Denom: "ATOM", Amount: int64(bondAmt)} - - tests := []struct { - tx sdk.Tx - }{ - {NewTxUnbond(strconv.Itoa(bondAmt), pubKey)}, - {NewTxDeclareCandidacy(bond, pubKey, Description{})}, - {NewTxDeclareCandidacy(bond, pubKey, Description{})}, - // {NewTxRevokeCandidacy(pubKey)}, - } - - for i, tc := range tests { - var tx sdk.Tx - bs := wire.BinaryBytes(tc.tx) - err := wire.ReadBinaryBytes(bs, &tx) - if assert.NoError(err, "%d", i) { - assert.Equal(tc.tx, tx, "%d", i) - } - } -} diff --git a/x/stake/types.go b/x/stake/types.go index 0ca88ef11d..018840a017 100644 --- a/x/stake/types.go +++ b/x/stake/types.go @@ -4,8 +4,7 @@ import ( "bytes" "sort" - "github.com/cosmos/cosmos-sdk" - "github.com/cosmos/cosmos-sdk/state" + "github.com/cosmos/cosmos-sdk/types" abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" @@ -15,8 +14,8 @@ import ( // Params defines the high level settings for staking type Params struct { - HoldBonded sdk.Actor `json:"hold_bonded"` // account where all bonded coins are held - HoldUnbonded sdk.Actor `json:"hold_unbonded"` // account where all delegated but unbonded coins are held + HoldBonded crypto.Address `json:"hold_bonded"` // account where all bonded coins are held + HoldUnbonded crypto.Address `json:"hold_unbonded"` // account where all delegated but unbonded coins are held InflationRateChange rational.Rat `json:"inflation_rate_change"` // maximum annual change in inflation rate InflationMax rational.Rat `json:"inflation_max"` // maximum inflation rate @@ -35,8 +34,8 @@ type Params struct { func defaultParams() Params { return Params{ - HoldBonded: sdk.NewActor(stakingModuleName, []byte("77777777777777777777777777777777")), - HoldUnbonded: sdk.NewActor(stakingModuleName, []byte("88888888888888888888888888888888")), + HoldBonded: []byte("77777777777777777777777777777777"), + HoldUnbonded: []byte("88888888888888888888888888888888"), InflationRateChange: rational.New(13, 100), InflationMax: rational.New(20, 100), InflationMin: rational.New(7, 100), @@ -151,7 +150,7 @@ const ( type Candidate struct { Status CandidateStatus `json:"status"` // Bonded status PubKey crypto.PubKey `json:"pub_key"` // Pubkey of candidate - Owner sdk.Actor `json:"owner"` // Sender of BondTx - UnbondTx returns here + Owner crypto.Address `json:"owner"` // Sender of BondTx - UnbondTx returns here Assets rational.Rat `json:"assets"` // total shares of a global hold pools TODO custom type PoolShares Liabilities rational.Rat `json:"liabilities"` // total shares issued to a candidate's delegators TODO custom type DelegatorShares VotingPower rational.Rat `json:"voting_power"` // Voting power if considered a validator @@ -167,7 +166,7 @@ type Description struct { } // NewCandidate - initialize a new candidate -func NewCandidate(pubKey crypto.PubKey, owner sdk.Actor, description Description) *Candidate { +func NewCandidate(pubKey crypto.PubKey, owner crypto.Address, description Description) *Candidate { return &Candidate{ Status: Unbonded, PubKey: pubKey, @@ -234,8 +233,13 @@ type Validator Candidate // ABCIValidator - Get the validator from a bond value func (v Validator) ABCIValidator() *abci.Validator { + pk, err := wire.MarshalBinary(v.PubKey) + if err != nil { + panic(err) + } + return &abci.Validator{ - PubKey: wire.BinaryBytes(v.PubKey), + PubKey: pk, Power: v.VotingPower.Evaluate(), } } @@ -269,7 +273,7 @@ func (cs Candidates) Sort() { } // update the voting power and save -func (cs Candidates) updateVotingPower(store state.SimpleDB, gs *GlobalState, params Params) Candidates { +func (cs Candidates) updateVotingPower(store types.KVStore, gs *GlobalState, params Params) Candidates { // update voting power for _, c := range cs { @@ -391,7 +395,7 @@ func (vs Validators) validatorsUpdated(vs2 Validators) (updated []*abci.Validato // UpdateValidatorSet - Updates the voting power for the candidate set and // returns the subset of validators which have been updated for Tendermint -func UpdateValidatorSet(store state.SimpleDB, gs *GlobalState, params Params) (change []*abci.Validator, err error) { +func UpdateValidatorSet(store types.KVStore, gs *GlobalState, params Params) (change []*abci.Validator, err error) { // get the validators before update candidates := loadCandidates(store) diff --git a/x/stake/types_test.go b/x/stake/types_test.go deleted file mode 100644 index d78df60b00..0000000000 --- a/x/stake/types_test.go +++ /dev/null @@ -1,251 +0,0 @@ -package stake - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/tendermint/tmlibs/rational" - - "github.com/cosmos/cosmos-sdk/state" -) - -func TestCandidatesSort(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - N := 5 - actors := newActors(N) - candidates := candidatesFromActors(actors, []int64{10, 300, 123, 4, 200}) - expectedOrder := []int{1, 4, 2, 0, 3} - - // test basic sort - candidates.Sort() - - vals := candidates.Validators() - require.Equal(N, len(vals)) - - for i, val := range vals { - expectedIdx := expectedOrder[i] - assert.Equal(val.PubKey, pks[expectedIdx]) - } -} - -func TestValidatorsSort(t *testing.T) { - assert := assert.New(t) - - v1 := (&Candidate{PubKey: pks[0], VotingPower: rational.New(25)}).validator() - v2 := (&Candidate{PubKey: pks[1], VotingPower: rational.New(1234)}).validator() - v3 := (&Candidate{PubKey: pks[2], VotingPower: rational.New(122)}).validator() - v4 := (&Candidate{PubKey: pks[3], VotingPower: rational.New(13)}).validator() - v5 := (&Candidate{PubKey: pks[4], VotingPower: rational.New(1111)}).validator() - - // test from nothing to something - vs := Validators{v4, v2, v5, v1, v3} - - // test basic sort - vs.Sort() - - for i, v := range vs { - assert.True(v.PubKey.Equals(pks[i])) - } -} - -func TestUpdateVotingPower(t *testing.T) { - assert := assert.New(t) - store := state.NewMemKVStore() - params := loadParams(store) - gs := loadGlobalState(store) - - N := 5 - actors := newActors(N) - candidates := candidatesFromActors(actors, []int64{400, 200, 100, 10, 1}) - - // test a basic change in voting power - candidates[0].Assets = rational.New(500) - candidates.updateVotingPower(store, gs, params) - assert.Equal(int64(500), candidates[0].VotingPower.Evaluate(), "%v", candidates[0]) - - // test a swap in voting power - candidates[1].Assets = rational.New(600) - candidates.updateVotingPower(store, gs, params) - assert.Equal(int64(600), candidates[0].VotingPower.Evaluate(), "%v", candidates[0]) - assert.Equal(int64(500), candidates[1].VotingPower.Evaluate(), "%v", candidates[1]) - - // test the max validators term - params.MaxVals = 4 - saveParams(store, params) - candidates.updateVotingPower(store, gs, params) - assert.Equal(int64(0), candidates[4].VotingPower.Evaluate(), "%v", candidates[4]) -} - -func TestGetValidators(t *testing.T) { - assert, require := assert.New(t), require.New(t) - - N := 5 - actors := newActors(N) - candidates := candidatesFromActors(actors, []int64{400, 200, 0, 0, 0}) - - validators := candidates.Validators() - require.Equal(2, len(validators)) - assert.Equal(candidates[0].PubKey, validators[0].PubKey) - assert.Equal(candidates[1].PubKey, validators[1].PubKey) -} - -func TestValidatorsChanged(t *testing.T) { - require := require.New(t) - - v1 := (&Candidate{PubKey: pks[0], VotingPower: rational.New(10)}).validator() - v2 := (&Candidate{PubKey: pks[1], VotingPower: rational.New(10)}).validator() - v3 := (&Candidate{PubKey: pks[2], VotingPower: rational.New(10)}).validator() - v4 := (&Candidate{PubKey: pks[3], VotingPower: rational.New(10)}).validator() - v5 := (&Candidate{PubKey: pks[4], VotingPower: rational.New(10)}).validator() - - // test from nothing to something - vs1 := Validators{} - vs2 := Validators{v1, v2} - changed := vs1.validatorsUpdated(vs2) - require.Equal(2, len(changed)) - testChange(t, vs2[0], changed[0]) - testChange(t, vs2[1], changed[1]) - - // test from something to nothing - vs1 = Validators{v1, v2} - vs2 = Validators{} - changed = vs1.validatorsUpdated(vs2) - require.Equal(2, len(changed)) - testRemove(t, vs1[0], changed[0]) - testRemove(t, vs1[1], changed[1]) - - // test identical - vs1 = Validators{v1, v2, v4} - vs2 = Validators{v1, v2, v4} - changed = vs1.validatorsUpdated(vs2) - require.Zero(len(changed)) - - // test single value change - vs2[2].VotingPower = rational.One - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testChange(t, vs2[2], changed[0]) - - // test multiple value change - vs2[0].VotingPower = rational.New(11) - vs2[2].VotingPower = rational.New(5) - changed = vs1.validatorsUpdated(vs2) - require.Equal(2, len(changed)) - testChange(t, vs2[0], changed[0]) - testChange(t, vs2[2], changed[1]) - - // test validator added at the beginning - vs1 = Validators{v2, v4} - vs2 = Validators{v2, v4, v1} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testChange(t, vs2[0], changed[0]) - - // test validator added in the middle - vs1 = Validators{v1, v2, v4} - vs2 = Validators{v3, v1, v4, v2} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testChange(t, vs2[2], changed[0]) - - // test validator added at the end - vs2 = Validators{v1, v2, v4, v5} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testChange(t, vs2[3], changed[0]) - - // test multiple validators added - vs2 = Validators{v1, v2, v3, v4, v5} - changed = vs1.validatorsUpdated(vs2) - require.Equal(2, len(changed)) - testChange(t, vs2[2], changed[0]) - testChange(t, vs2[4], changed[1]) - - // test validator removed at the beginning - vs2 = Validators{v2, v4} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testRemove(t, vs1[0], changed[0]) - - // test validator removed in the middle - vs2 = Validators{v1, v4} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testRemove(t, vs1[1], changed[0]) - - // test validator removed at the end - vs2 = Validators{v1, v2} - changed = vs1.validatorsUpdated(vs2) - require.Equal(1, len(changed)) - testRemove(t, vs1[2], changed[0]) - - // test multiple validators removed - vs2 = Validators{v1} - changed = vs1.validatorsUpdated(vs2) - require.Equal(2, len(changed)) - testRemove(t, vs1[1], changed[0]) - testRemove(t, vs1[2], changed[1]) - - // test many types of changes - vs2 = Validators{v1, v3, v4, v5} - vs2[2].VotingPower = rational.New(11) - changed = vs1.validatorsUpdated(vs2) - require.Equal(4, len(changed), "%v", changed) // change 1, remove 1, add 2 - testRemove(t, vs1[1], changed[0]) - testChange(t, vs2[1], changed[1]) - testChange(t, vs2[2], changed[2]) - testChange(t, vs2[3], changed[3]) - -} - -func TestUpdateValidatorSet(t *testing.T) { - assert, require := assert.New(t), require.New(t) - store := state.NewMemKVStore() - params := loadParams(store) - gs := loadGlobalState(store) - - N := 5 - actors := newActors(N) - candidates := candidatesFromActors(actors, []int64{400, 200, 100, 10, 1}) - for _, c := range candidates { - saveCandidate(store, c) - } - - // they should all already be validators - change, err := UpdateValidatorSet(store, gs, params) - require.Nil(err) - require.Equal(0, len(change), "%v", change) // change 1, remove 1, add 2 - - // test the max value and test again - params.MaxVals = 4 - saveParams(store, params) - change, err = UpdateValidatorSet(store, gs, params) - require.Nil(err) - require.Equal(1, len(change), "%v", change) - testRemove(t, candidates[4].validator(), change[0]) - candidates = loadCandidates(store) - assert.Equal(int64(0), candidates[4].VotingPower.Evaluate()) - - // mess with the power's of the candidates and test - candidates[0].Assets = rational.New(10) - candidates[1].Assets = rational.New(600) - candidates[2].Assets = rational.New(1000) - candidates[3].Assets = rational.One - candidates[4].Assets = rational.New(10) - for _, c := range candidates { - saveCandidate(store, c) - } - change, err = UpdateValidatorSet(store, gs, params) - require.Nil(err) - require.Equal(5, len(change), "%v", change) // 3 changed, 1 added, 1 removed - candidates = loadCandidates(store) - testChange(t, candidates[0].validator(), change[0]) - testChange(t, candidates[1].validator(), change[1]) - testChange(t, candidates[2].validator(), change[2]) - testRemove(t, candidates[3].validator(), change[3]) - testChange(t, candidates[4].validator(), change[4]) -} - -// XXX test global state functions, candidate exchange rate functions etc.