Merge pull request #813 from cosmos/rigel/staking-cli

Gaia Refactor / Stake CLI
This commit is contained in:
Rigel 2018-04-18 14:49:35 -04:00 committed by GitHub
commit 1b9afdab48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1199 additions and 350 deletions

View File

@ -31,7 +31,7 @@ jobs:
name: binaries
command: |
export PATH="$GOBIN:$PATH"
make build
make install
- persist_to_workspace:
root: /tmp/workspace
paths:
@ -59,7 +59,9 @@ jobs:
- run:
name: Run tests
command: |
for pkg in $(go list github.com/cosmos/cosmos-sdk/... | grep -v /vendor/ | circleci tests split --split-by=timings); do
export PATH="$GOBIN:$PATH"
make install
for pkg in $(go list github.com/cosmos/cosmos-sdk/... | grep -v /vendor/ | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test | circleci tests split --split-by=timings); do
id=$(basename "$pkg")
go test -timeout 5m -race -coverprofile=/tmp/workspace/profiles/$id.out -covermode=atomic "$pkg"

View File

@ -7,17 +7,19 @@ FEATURES:
* Add CacheContext
* Add auto sequencing to client
* Add FeeHandler to ante handler
* Gaia stake commands include, DeclareCandidacy, EditCandidacy, Delegate, Unbond
* MountStoreWithDB without providing a custom store works.
BREAKING CHANGES
* Remove go-wire, use go-amino
* Gaia simple-staking bond and unbond functions replaced
* [store] Add `SubspaceIterator` and `ReverseSubspaceIterator` to `KVStore` interface
* [basecoin] NewBasecoinApp takes a `dbm.DB` and uses namespaced DBs for substores
* All module keepers now require a codespace, see basecoin or democoin for usage
BUG FIXES
* MountStoreWithDB without providing a custom store works.
* Gaia now uses stake, ported from github.com/cosmos/gaia
## 0.14.1 (April 9, 2018)

View File

@ -7,7 +7,7 @@ all: check_tools get_vendor_deps build build_examples test
########################################
### CI
ci: get_tools get_vendor_deps build test_cover
ci: get_tools get_vendor_deps install test_cover
########################################
### Build
@ -15,11 +15,11 @@ ci: get_tools get_vendor_deps build test_cover
# This can be unified later, here for easy demos
build:
ifeq ($(OS),Windows_NT)
go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaiacli
go build $(BUILD_FLAGS) -o build/gaiad.exe ./cmd/gaia/cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli.exe ./cmd/gaia/cmd/gaiacli
else
go build $(BUILD_FLAGS) -o build/gaiad ./cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaiacli
go build $(BUILD_FLAGS) -o build/gaiad ./cmd/gaia/cmd/gaiad
go build $(BUILD_FLAGS) -o build/gaiacli ./cmd/gaia/cmd/gaiacli
endif
build_examples:
@ -36,8 +36,8 @@ else
endif
install:
go install $(BUILD_FLAGS) ./cmd/gaiad
go install $(BUILD_FLAGS) ./cmd/gaiacli
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiad
go install $(BUILD_FLAGS) ./cmd/gaia/cmd/gaiacli
install_examples:
go install $(BUILD_FLAGS) ./examples/basecoin/cmd/basecoind

View File

@ -322,9 +322,8 @@ func (app *BaseApp) DeliverTx(txBytes []byte) (res abci.ResponseDeliverTx) {
if result.IsOK() {
app.valUpdates = append(app.valUpdates, result.ValidatorUpdates...)
} else {
// Even though the Code is not OK, there will be some side
// effects, like those caused by fee deductions or sequence
// incrementations.
// Even though the Result.Code is not OK, there are still effects,
// namely fee deductions and sequence incrementing.
}
// Tell the blockchain engine (i.e. Tendermint).
@ -453,7 +452,7 @@ func (app *BaseApp) Commit() (res abci.ResponseCommit) {
// Use the header from this latest block.
app.setCheckState(header)
// Emtpy the Deliver state
// Empty the Deliver state
app.deliverState = nil
return abci.ResponseCommit{

View File

@ -11,6 +11,12 @@ func init() {
wire.RegisterCrypto(cdc)
}
// marshal keys
func MarshalJSON(o interface{}) ([]byte, error) {
return cdc.MarshalJSON(o)
}
// unmarshal json
func UnmarshalJSON(bz []byte, ptr interface{}) error {
return cdc.UnmarshalJSON(bz, ptr)
}

200
cmd/gaia/app/app.go Normal file
View File

@ -0,0 +1,200 @@
package app
import (
"encoding/json"
abci "github.com/tendermint/abci/types"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
bam "github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/cosmos/cosmos-sdk/x/stake"
)
const (
appName = "GaiaApp"
)
// Extended ABCI application
type GaiaApp struct {
*bam.BaseApp
cdc *wire.Codec
// keys to access the substores
capKeyMainStore *sdk.KVStoreKey
capKeyAccountStore *sdk.KVStoreKey
capKeyIBCStore *sdk.KVStoreKey
capKeyStakeStore *sdk.KVStoreKey
// Manage getting and setting accounts
accountMapper sdk.AccountMapper
coinKeeper bank.CoinKeeper
ibcMapper ibc.IBCMapper
stakeKeeper stake.Keeper
// Handle fees
feeHandler sdk.FeeHandler
}
func NewGaiaApp(logger log.Logger, db dbm.DB) *GaiaApp {
// create your application object
var app = &GaiaApp{
BaseApp: bam.NewBaseApp(appName, logger, db),
cdc: MakeCodec(),
capKeyMainStore: sdk.NewKVStoreKey("main"),
capKeyAccountStore: sdk.NewKVStoreKey("acc"),
capKeyIBCStore: sdk.NewKVStoreKey("ibc"),
capKeyStakeStore: sdk.NewKVStoreKey("stake"),
}
// define the accountMapper
app.accountMapper = auth.NewAccountMapper(
app.cdc,
app.capKeyMainStore, // target store
&auth.BaseAccount{}, // prototype
).Seal()
// add handlers
app.coinKeeper = bank.NewCoinKeeper(app.accountMapper)
app.ibcMapper = ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore, app.RegisterCodespace(ibc.DefaultCodespace))
app.stakeKeeper = stake.NewKeeper(app.cdc, app.capKeyStakeStore, app.coinKeeper, app.RegisterCodespace(stake.DefaultCodespace))
app.Router().
AddRoute("bank", bank.NewHandler(app.coinKeeper)).
AddRoute("ibc", ibc.NewHandler(app.ibcMapper, app.coinKeeper)).
AddRoute("stake", stake.NewHandler(app.stakeKeeper))
// Define the feeHandler.
app.feeHandler = auth.BurnFeeHandler
// initialize BaseApp
app.SetTxDecoder(app.txDecoder)
app.SetInitChainer(app.initChainer)
app.SetEndBlocker(stake.NewEndBlocker(app.stakeKeeper))
app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyIBCStore, app.capKeyStakeStore)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeHandler))
err := app.LoadLatestVersion(app.capKeyMainStore)
if err != nil {
cmn.Exit(err.Error())
}
return app
}
// custom tx codec
func MakeCodec() *wire.Codec {
var cdc = wire.NewCodec()
// Register Msgs
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
ibc.RegisterWire(cdc)
bank.RegisterWire(cdc)
stake.RegisterWire(cdc)
// Register AppAccount
cdc.RegisterInterface((*sdk.Account)(nil), nil)
cdc.RegisterConcrete(&auth.BaseAccount{}, "gaia/Account", nil)
// Register crypto.
wire.RegisterCrypto(cdc)
return cdc
}
// custom logic for transaction decoding
func (app *GaiaApp) txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx = sdk.StdTx{}
if len(txBytes) == 0 {
return nil, sdk.ErrTxDecode("txBytes are empty")
}
// StdTx.Msg is an interface. The concrete types
// are registered by MakeTxCodec
err := app.cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, sdk.ErrTxDecode("").Trace(err.Error())
}
return tx, nil
}
// custom logic for gaia initialization
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
genesisState := new(GenesisState)
err := json.Unmarshal(stateJSON, genesisState)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
// load the accounts
for _, gacc := range genesisState.Accounts {
acc := gacc.ToAccount()
app.accountMapper.SetAccount(ctx, acc)
}
// load the initial stake information
stake.InitGenesis(ctx, app.stakeKeeper, genesisState.StakeData)
return abci.ResponseInitChain{}
}
//__________________________________________________________
// State to Unmarshal
type GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
StakeData stake.GenesisState `json:"stake"`
}
// GenesisAccount doesn't need pubkey or sequence
type GenesisAccount struct {
Address sdk.Address `json:"address"`
Coins sdk.Coins `json:"coins"`
}
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
return GenesisAccount{
Address: acc.Address,
Coins: acc.Coins,
}
}
// convert GenesisAccount to GaiaAccount
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
return &auth.BaseAccount{
Address: ga.Address,
Coins: ga.Coins.Sort(),
}
}
// DefaultGenAppState expects two args: an account address
// and a coin denomination, and gives lots of coins to that address.
func DefaultGenAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) {
accAuth := auth.NewBaseAccountWithAddress(addr)
accAuth.Coins = sdk.Coins{{"fermion", 100000}}
acc := NewGenesisAccount(&accAuth)
genaccs := []GenesisAccount{acc}
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stake.GetDefaultGenesisState(),
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
if err != nil {
return nil, err
}
return stateBytes, nil
}

518
cmd/gaia/app/app_test.go Normal file
View File

@ -0,0 +1,518 @@
package app
import (
"encoding/json"
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/ibc"
"github.com/cosmos/cosmos-sdk/x/stake"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
)
// Construct some global addrs and txs for tests.
var (
chainID = "" // TODO
accName = "foobart"
priv1 = crypto.GenPrivKeyEd25519()
addr1 = priv1.PubKey().Address()
priv2 = crypto.GenPrivKeyEd25519()
addr2 = priv2.PubKey().Address()
addr3 = crypto.GenPrivKeyEd25519().PubKey().Address()
priv4 = crypto.GenPrivKeyEd25519()
addr4 = priv4.PubKey().Address()
coins = sdk.Coins{{"foocoin", 10}}
halfCoins = sdk.Coins{{"foocoin", 5}}
manyCoins = sdk.Coins{{"foocoin", 1}, {"barcoin", 1}}
fee = sdk.StdFee{
sdk.Coins{{"foocoin", 0}},
0,
}
sendMsg1 = bank.SendMsg{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
sendMsg2 = bank.SendMsg{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{
bank.NewOutput(addr2, halfCoins),
bank.NewOutput(addr3, halfCoins),
},
}
sendMsg3 = bank.SendMsg{
Inputs: []bank.Input{
bank.NewInput(addr1, coins),
bank.NewInput(addr4, coins),
},
Outputs: []bank.Output{
bank.NewOutput(addr2, coins),
bank.NewOutput(addr3, coins),
},
}
sendMsg4 = bank.SendMsg{
Inputs: []bank.Input{
bank.NewInput(addr2, coins),
},
Outputs: []bank.Output{
bank.NewOutput(addr1, coins),
},
}
sendMsg5 = bank.SendMsg{
Inputs: []bank.Input{
bank.NewInput(addr1, manyCoins),
},
Outputs: []bank.Output{
bank.NewOutput(addr2, manyCoins),
},
}
)
func loggerAndDB() (log.Logger, dbm.DB) {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
return logger, db
}
func newGaiaApp() *GaiaApp {
logger, db := loggerAndDB()
return NewGaiaApp(logger, db)
}
func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
genaccs := make([]GenesisAccount, len(accs))
for i, acc := range accs {
genaccs[i] = NewGenesisAccount(acc)
}
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stake.GetDefaultGenesisState(),
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
if err != nil {
return err
}
// Initialize the chain
vals := []abci.Validator{}
gapp.InitChain(abci.RequestInitChain{vals, stateBytes})
gapp.Commit()
return nil
}
//_______________________________________________________________________
func TestMsgs(t *testing.T) {
gapp := newGaiaApp()
require.Nil(t, setGenesis(gapp))
msgs := []struct {
msg sdk.Msg
}{
{sendMsg1},
}
for i, m := range msgs {
// Run a CheckDeliver
SignCheckDeliver(t, gapp, m.msg, []int64{int64(i)}, false, priv1)
}
}
func setGenesisAccounts(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
genaccs := make([]GenesisAccount, len(accs))
for i, acc := range accs {
genaccs[i] = NewGenesisAccount(acc)
}
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stake.GetDefaultGenesisState(),
}
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
if err != nil {
return err
}
// Initialize the chain
vals := []abci.Validator{}
gapp.InitChain(abci.RequestInitChain{vals, stateBytes})
gapp.Commit()
return nil
}
func TestGenesis(t *testing.T) {
logger, dbs := loggerAndDB()
gapp := NewGaiaApp(logger, dbs)
// Construct some genesis bytes to reflect GaiaAccount
pk := crypto.GenPrivKeyEd25519().PubKey()
addr := pk.Address()
coins, err := sdk.ParseCoins("77foocoin,99barcoin")
require.Nil(t, err)
baseAcc := &auth.BaseAccount{
Address: addr,
Coins: coins,
}
err = setGenesis(gapp, baseAcc)
assert.Nil(t, err)
// A checkTx context
ctx := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctx, baseAcc.Address)
assert.Equal(t, baseAcc, res1)
// reload app and ensure the account is still there
gapp = NewGaiaApp(logger, dbs)
ctx = gapp.BaseApp.NewContext(true, abci.Header{})
res1 = gapp.accountMapper.GetAccount(ctx, baseAcc.Address)
assert.Equal(t, baseAcc, res1)
}
func TestSendMsgWithAccounts(t *testing.T) {
gapp := newGaiaApp()
// Construct some genesis bytes to reflect GaiaAccount
// Give 77 foocoin to the first key
coins, err := sdk.ParseCoins("77foocoin")
require.Nil(t, err)
baseAcc := &auth.BaseAccount{
Address: addr1,
Coins: coins,
}
// Construct genesis state
err = setGenesis(gapp, baseAcc)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, baseAcc, res1.(*auth.BaseAccount))
// Run a CheckDeliver
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, gapp, addr1, "67foocoin")
CheckBalance(t, gapp, addr2, "10foocoin")
// Delivering again should cause replay error
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, false, priv1)
// bumping the txnonce number without resigning should be an auth error
tx := genTx(sendMsg1, []int64{0}, priv1)
tx.Signatures[0].Sequence = 1
res := gapp.Deliver(tx)
assert.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
// resigning the tx with the bumped sequence should work
SignCheckDeliver(t, gapp, sendMsg1, []int64{1}, true, priv1)
}
func TestSendMsgMultipleOut(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := &auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
err = setGenesis(gapp, acc1, acc2)
require.Nil(t, err)
// Simulate a Block
SignCheckDeliver(t, gapp, sendMsg2, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, gapp, addr1, "32foocoin")
CheckBalance(t, gapp, addr2, "47foocoin")
CheckBalance(t, gapp, addr3, "5foocoin")
}
func TestSengMsgMultipleInOut(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := &auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
acc4 := &auth.BaseAccount{
Address: addr4,
Coins: genCoins,
}
err = setGenesis(gapp, acc1, acc2, acc4)
assert.Nil(t, err)
// CheckDeliver
SignCheckDeliver(t, gapp, sendMsg3, []int64{0, 0}, true, priv1, priv4)
// Check balances
CheckBalance(t, gapp, addr1, "32foocoin")
CheckBalance(t, gapp, addr4, "32foocoin")
CheckBalance(t, gapp, addr2, "52foocoin")
CheckBalance(t, gapp, addr3, "10foocoin")
}
func TestSendMsgDependent(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42foocoin")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
err = setGenesis(gapp, acc1)
require.Nil(t, err)
// CheckDeliver
SignCheckDeliver(t, gapp, sendMsg1, []int64{0}, true, priv1)
// Check balances
CheckBalance(t, gapp, addr1, "32foocoin")
CheckBalance(t, gapp, addr2, "10foocoin")
// Simulate a Block
SignCheckDeliver(t, gapp, sendMsg4, []int64{0}, true, priv2)
// Check balances
CheckBalance(t, gapp, addr1, "42foocoin")
}
func TestIBCMsgs(t *testing.T) {
gapp := newGaiaApp()
sourceChain := "source-chain"
destChain := "dest-chain"
baseAcc := &auth.BaseAccount{
Address: addr1,
Coins: coins,
}
err := setGenesis(gapp, baseAcc)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
assert.Equal(t, baseAcc, res1)
packet := ibc.IBCPacket{
SrcAddr: addr1,
DestAddr: addr1,
Coins: coins,
SrcChain: sourceChain,
DestChain: destChain,
}
transferMsg := ibc.IBCTransferMsg{
IBCPacket: packet,
}
receiveMsg := ibc.IBCReceiveMsg{
IBCPacket: packet,
Relayer: addr1,
Sequence: 0,
}
SignCheckDeliver(t, gapp, transferMsg, []int64{0}, true, priv1)
CheckBalance(t, gapp, addr1, "")
SignCheckDeliver(t, gapp, transferMsg, []int64{1}, false, priv1)
SignCheckDeliver(t, gapp, receiveMsg, []int64{2}, true, priv1)
CheckBalance(t, gapp, addr1, "10foocoin")
SignCheckDeliver(t, gapp, receiveMsg, []int64{3}, false, priv1)
}
func TestStakeMsgs(t *testing.T) {
gapp := newGaiaApp()
genCoins, err := sdk.ParseCoins("42fermion")
require.Nil(t, err)
bondCoin, err := sdk.ParseCoin("10fermion")
require.Nil(t, err)
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: genCoins,
}
acc2 := &auth.BaseAccount{
Address: addr2,
Coins: genCoins,
}
err = setGenesis(gapp, acc1, acc2)
require.Nil(t, err)
// A checkTx context (true)
ctxCheck := gapp.BaseApp.NewContext(true, abci.Header{})
res1 := gapp.accountMapper.GetAccount(ctxCheck, addr1)
res2 := gapp.accountMapper.GetAccount(ctxCheck, addr2)
require.Equal(t, acc1, res1)
require.Equal(t, acc2, res2)
// Declare Candidacy
description := stake.NewDescription("foo_moniker", "", "", "")
declareCandidacyMsg := stake.NewMsgDeclareCandidacy(
addr1, priv1.PubKey(), bondCoin, description,
)
SignCheckDeliver(t, gapp, declareCandidacyMsg, []int64{0}, true, priv1)
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
res1 = gapp.accountMapper.GetAccount(ctxDeliver, addr1)
require.Equal(t, genCoins.Minus(sdk.Coins{bondCoin}), res1.GetCoins())
candidate, found := gapp.stakeKeeper.GetCandidate(ctxDeliver, addr1)
require.True(t, found)
require.Equal(t, candidate.Address, addr1)
// Edit Candidacy
description = stake.NewDescription("bar_moniker", "", "", "")
editCandidacyMsg := stake.NewMsgEditCandidacy(
addr1, description,
)
SignDeliver(t, gapp, editCandidacyMsg, []int64{1}, true, priv1)
candidate, found = gapp.stakeKeeper.GetCandidate(ctxDeliver, addr1)
require.True(t, found)
require.Equal(t, candidate.Description, description)
// Delegate
delegateMsg := stake.NewMsgDelegate(
addr2, addr1, bondCoin,
)
SignDeliver(t, gapp, delegateMsg, []int64{0}, true, priv2)
ctxDeliver = gapp.BaseApp.NewContext(false, abci.Header{})
res2 = gapp.accountMapper.GetAccount(ctxDeliver, addr2)
require.Equal(t, genCoins.Minus(sdk.Coins{bondCoin}), res2.GetCoins())
bond, found := gapp.stakeKeeper.GetDelegatorBond(ctxDeliver, addr2, addr1)
require.True(t, found)
require.Equal(t, bond.DelegatorAddr, addr2)
// Unbond
unbondMsg := stake.NewMsgUnbond(
addr2, addr1, "MAX",
)
SignDeliver(t, gapp, unbondMsg, []int64{1}, true, priv2)
ctxDeliver = gapp.BaseApp.NewContext(false, abci.Header{})
res2 = gapp.accountMapper.GetAccount(ctxDeliver, addr2)
require.Equal(t, genCoins, res2.GetCoins())
_, found = gapp.stakeKeeper.GetDelegatorBond(ctxDeliver, addr2, addr1)
require.False(t, found)
}
//____________________________________________________________________________________
func CheckBalance(t *testing.T, gapp *GaiaApp, addr sdk.Address, balExpected string) {
ctxDeliver := gapp.BaseApp.NewContext(false, abci.Header{})
res2 := gapp.accountMapper.GetAccount(ctxDeliver, addr)
assert.Equal(t, balExpected, fmt.Sprintf("%v", res2.GetCoins()))
}
func genTx(msg sdk.Msg, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.StdTx {
sigs := make([]sdk.StdSignature, len(priv))
for i, p := range priv {
sigs[i] = sdk.StdSignature{
PubKey: p.PubKey(),
Signature: p.Sign(sdk.StdSignBytes(chainID, seq, fee, msg)),
Sequence: seq[i],
}
}
return sdk.NewStdTx(msg, fee, sigs)
}
func SignCheckDeliver(t *testing.T, gapp *GaiaApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
// Sign the tx
tx := genTx(msg, seq, priv...)
// Run a Check
res := gapp.Check(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
// Simulate a Block
gapp.BeginBlock(abci.RequestBeginBlock{})
res = gapp.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
gapp.EndBlock(abci.RequestEndBlock{})
// XXX fix code or add explaination as to why using commit breaks a bunch of these tests
//gapp.Commit()
}
// XXX the only reason we are using Sign Deliver here is because the tests
// break on check tx the second time you use SignCheckDeliver in a test because
// the checktx state has not been updated likely because commit is not being
// called!
func SignDeliver(t *testing.T, gapp *GaiaApp, msg sdk.Msg, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) {
// Sign the tx
tx := genTx(msg, seq, priv...)
// Simulate a Block
gapp.BeginBlock(abci.RequestBeginBlock{})
res := gapp.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
gapp.EndBlock(abci.RequestEndBlock{})
}

View File

@ -0,0 +1,184 @@
package clitest
import (
"encoding/hex"
"encoding/json"
"fmt"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/stake"
crypto "github.com/tendermint/go-crypto"
crkeys "github.com/tendermint/go-crypto/keys"
)
func TestGaiaCLISend(t *testing.T) {
tests.ExecuteT(t, "gaiad unsafe_reset_all", 1)
pass := "1234567890"
executeWrite(t, "gaiacli keys delete foo", pass)
executeWrite(t, "gaiacli keys delete bar", pass)
masterKey, chainID := executeInit(t, "gaiad init")
// get a free port, also setup some common flags
servAddr := server.FreeTCPAddr(t)
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
// start gaiad server
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
defer cmd.Process.Kill()
executeWrite(t, "gaiacli keys add foo --recover", pass, masterKey)
executeWrite(t, "gaiacli keys add bar", pass)
fooAddr, _ := executeGetAddr(t, "gaiacli keys show foo --output=json")
barAddr, _ := executeGetAddr(t, "gaiacli keys show bar --output=json")
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion"))
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10fermion --to=%v --name=foo", flags, barAddr), pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion"))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(99990), fooAcc.GetCoins().AmountOf("fermion"))
}
func TestGaiaCLIDeclareCandidacy(t *testing.T) {
tests.ExecuteT(t, "gaiad unsafe_reset_all", 1)
pass := "1234567890"
executeWrite(t, "gaiacli keys delete foo", pass)
masterKey, chainID := executeInit(t, "gaiad init")
// get a free port, also setup some common flags
servAddr := server.FreeTCPAddr(t)
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID)
// start gaiad server
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
defer cmd.Process.Kill()
executeWrite(t, "gaiacli keys add foo --recover", pass, masterKey)
fooAddr, fooPubKey := executeGetAddr(t, "gaiacli keys show foo --output=json")
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion"))
// declare candidacy
declStr := fmt.Sprintf("gaiacli declare-candidacy %v", flags)
declStr += fmt.Sprintf(" --name=%v", "foo")
declStr += fmt.Sprintf(" --address-candidate=%v", fooAddr)
declStr += fmt.Sprintf(" --pubkey=%v", fooPubKey)
declStr += fmt.Sprintf(" --amount=%v", "3fermion")
declStr += fmt.Sprintf(" --moniker=%v", "foo-vally")
fmt.Printf("debug declStr: %v\n", declStr)
executeWrite(t, declStr, pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(99997), fooAcc.GetCoins().AmountOf("fermion"))
candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr))
assert.Equal(t, candidate.Address.String(), fooAddr)
assert.Equal(t, int64(3), candidate.Assets.Evaluate())
// TODO figure out why this times out with connection refused errors in go-bash
// unbond a single share
unbondStr := fmt.Sprintf("gaiacli unbond %v", flags)
unbondStr += fmt.Sprintf(" --name=%v", "foo")
unbondStr += fmt.Sprintf(" --address-candidate=%v", fooAddr)
unbondStr += fmt.Sprintf(" --address-delegator=%v", fooAddr)
unbondStr += fmt.Sprintf(" --shares=%v", "1")
unbondStr += fmt.Sprintf(" --sequence=%v", "1")
fmt.Printf("debug unbondStr: %v\n", unbondStr)
executeWrite(t, unbondStr, pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
assert.Equal(t, int64(99998), fooAcc.GetCoins().AmountOf("fermion"))
candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr))
assert.Equal(t, int64(2), candidate.Assets.Evaluate())
}
func executeWrite(t *testing.T, cmdStr string, writes ...string) {
cmd, wc, _ := tests.GoExecuteT(t, cmdStr)
for _, write := range writes {
_, err := wc.Write([]byte(write + "\n"))
require.NoError(t, err)
}
cmd.Wait()
}
func executeWritePrint(t *testing.T, cmdStr string, writes ...string) {
cmd, wc, rc := tests.GoExecuteT(t, cmdStr)
for _, write := range writes {
_, err := wc.Write([]byte(write + "\n"))
require.NoError(t, err)
}
cmd.Wait()
bz := make([]byte, 100000)
rc.Read(bz)
fmt.Printf("debug read: %v\n", string(bz))
}
func executeInit(t *testing.T, cmdStr string) (masterKey, chainID string) {
out := tests.ExecuteT(t, cmdStr, 1)
outCut := "{" + strings.SplitN(out, "{", 2)[1] // weird I'm sorry
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(outCut), &initRes)
require.NoError(t, err)
err = json.Unmarshal(initRes["secret"], &masterKey)
require.NoError(t, err)
err = json.Unmarshal(initRes["chain_id"], &chainID)
require.NoError(t, err)
return
}
func executeGetAddr(t *testing.T, cmdStr string) (addr, pubKey string) {
out := tests.ExecuteT(t, cmdStr, 2)
var info crkeys.Info
keys.UnmarshalJSON([]byte(out), &info)
pubKey = hex.EncodeToString(info.PubKey.(crypto.PubKeyEd25519).Bytes())
// TODO this is really wierd, also error that not 64 characters!
pubKey = strings.TrimLeft(pubKey, "1624de6220")
pubKey = fmt.Sprintf("%064v", pubKey)
fmt.Printf("debug pubKey: %v\n", pubKey)
addr = info.PubKey.Address().String()
fmt.Printf("debug addr: %v\n", addr)
return
}
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
out := tests.ExecuteT(t, cmdStr, 2)
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(out), &initRes)
require.NoError(t, err, "out %v, err %v", out, err)
value := initRes["value"]
var acc auth.BaseAccount
_ = json.Unmarshal(value, &acc) //XXX pubkey can't be decoded go amino issue
require.NoError(t, err, "value %v, err %v", string(value), err)
return acc
}
func executeGetCandidate(t *testing.T, cmdStr string) stake.Candidate {
out := tests.ExecuteT(t, cmdStr, 2)
var candidate stake.Candidate
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &candidate)
require.NoError(t, err, "out %v, err %v", out, err)
return candidate
}

View File

@ -17,14 +17,11 @@ import (
authcmd "github.com/cosmos/cosmos-sdk/x/auth/commands"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/commands"
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/commands"
simplestakingcmd "github.com/cosmos/cosmos-sdk/x/simplestake/commands"
stakecmd "github.com/cosmos/cosmos-sdk/x/stake/commands"
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
)
// TODO: distinguish from basecli
// rootCmd is the entry point for this binary
var (
rootCmd = &cobra.Command{
@ -34,10 +31,7 @@ var (
)
func main() {
// disable sorting
cobra.EnableCommandSorting = false
// get the codec
cdc := app.MakeCodec()
// TODO: setup keybase, viper object, etc. to be passed into
@ -53,24 +47,21 @@ func main() {
// add query/post commands (custom to binary)
rootCmd.AddCommand(
client.GetCommands(
authcmd.GetAccountCmd("main", cdc, types.GetAccountDecoder(cdc)),
authcmd.GetAccountCmd("main", cdc, authcmd.GetAccountDecoder(cdc)),
stakecmd.GetCmdQueryCandidate("stake", cdc),
//stakecmd.GetCmdQueryCandidates("stake", cdc),
stakecmd.GetCmdQueryDelegatorBond("stake", cdc),
//stakecmd.GetCmdQueryDelegatorBonds("stake", cdc),
)...)
rootCmd.AddCommand(
client.PostCommands(
bankcmd.SendTxCmd(cdc),
)...)
rootCmd.AddCommand(
client.PostCommands(
ibccmd.IBCTransferCmd(cdc),
)...)
rootCmd.AddCommand(
client.PostCommands(
ibccmd.IBCRelayCmd(cdc),
simplestakingcmd.BondTxCmd(cdc),
)...)
rootCmd.AddCommand(
client.PostCommands(
simplestakingcmd.UnbondTxCmd(cdc),
stakecmd.GetCmdDeclareCandidacy(cdc),
stakecmd.GetCmdEditCandidacy(cdc),
stakecmd.GetCmdDelegate(cdc),
stakecmd.GetCmdUnbond(cdc),
)...)
// add proxy, version and key info
@ -83,6 +74,6 @@ func main() {
)
// prepare and add flags
executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.gaiacli"))
executor := cli.PrepareMainCmd(rootCmd, "GA", os.ExpandEnv("$HOME/.gaiacli"))
executor.Execute()
}

View File

@ -11,7 +11,7 @@ import (
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
)
@ -25,21 +25,21 @@ var (
}
)
// TODO: distinguish from basecoin
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
dataDir := filepath.Join(rootDir, "data")
db, err := dbm.NewGoLevelDB("gaia", dataDir)
if err != nil {
return nil, err
}
bapp := app.NewBasecoinApp(logger, db)
bapp := app.NewGaiaApp(logger, db)
return bapp, nil
}
func main() {
server.AddCommands(rootCmd, server.DefaultGenAppState, generateApp, context)
server.AddCommands(rootCmd, app.DefaultGenAppState, generateApp, context)
// prepare and add flags
executor := cli.PrepareBaseCmd(rootCmd, "GA", os.ExpandEnv("$HOME/.gaiad"))
rootDir := os.ExpandEnv("$HOME/.gaiad")
executor := cli.PrepareBaseCmd(rootCmd, "GA", rootDir)
executor.Execute()
}

View File

@ -70,7 +70,7 @@ func (c initCmd) run(cmd *cobra.Command, args []string) error {
return nil
}
// generate secrete and address
// generate secret and address
addr, secret, err := GenerateCoinKey()
if err != nil {
return err

54
tests/gobash.go Normal file
View File

@ -0,0 +1,54 @@
package tests
import (
"fmt"
"io"
"os/exec"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func getCmd(t *testing.T, command string) *exec.Cmd {
//split command into command and args
split := strings.Split(command, " ")
require.True(t, len(split) > 0, "no command provided")
var cmd *exec.Cmd
if len(split) == 1 {
cmd = exec.Command(split[0])
} else {
cmd = exec.Command(split[0], split[1:]...)
}
return cmd
}
// Execute the command, return standard output and error, try a few times if requested
func ExecuteT(t *testing.T, command string, trials int) (out string) {
cmd := getCmd(t, command)
bz, err := cmd.CombinedOutput()
if err != nil && trials > 1 {
fmt.Printf("trial %v, retrying: %v\n", trials, command)
time.Sleep(time.Second * 10)
return ExecuteT(t, command, trials-1)
}
require.NoError(t, err, string(bz))
out = strings.Trim(string(bz), "\n") //trim any new lines
time.Sleep(time.Second)
return out
}
// Asynchronously execute the command, return standard output and error
func GoExecuteT(t *testing.T, command string) (cmd *exec.Cmd, pipeIn io.WriteCloser, pipeOut io.ReadCloser) {
cmd = getCmd(t, command)
pipeIn, err := cmd.StdinPipe()
require.NoError(t, err)
pipeOut, err = cmd.StdoutPipe()
require.NoError(t, err)
go cmd.Start()
time.Sleep(time.Second)
return cmd, pipeIn, pipeOut
}

View File

@ -20,7 +20,7 @@ type Result struct {
// GasWanted is the maximum units of work we allow this tx to perform.
GasWanted int64
// GasUsed is the amount of gas actually consumed. NOTE: not used.
// GasUsed is the amount of gas actually consumed. NOTE: unimplemented
GasUsed int64
// Tx fee amount and denom.

View File

@ -6,7 +6,6 @@ import (
// Register concrete types on wire codec
func RegisterWire(cdc *wire.Codec) {
// TODO include option to always include prefix bytes.
//cdc.RegisterConcrete(SendMsg{}, "github.com/cosmos/cosmos-sdk/bank/SendMsg", nil)
//cdc.RegisterConcrete(IssueMsg{}, "github.com/cosmos/cosmos-sdk/bank/IssueMsg", nil)
cdc.RegisterConcrete(SendMsg{}, "cosmos-sdk/Send", nil)
cdc.RegisterConcrete(IssueMsg{}, "cosmos-sdk/Issue", nil)
}

View File

@ -6,6 +6,6 @@ import (
// Register concrete types on wire codec
func RegisterWire(cdc *wire.Codec) {
//cdc.RegisterConcrete(IBCTransferMsg{}, "github.com/cosmos/cosmos-sdk/x/ibc/IBCTransferMsg", nil)
//cdc.RegisterConcrete(IBCReceiveMsg{}, "github.com/cosmos/cosmos-sdk/x/ibc/IBCReceiveMsg", nil)
cdc.RegisterConcrete(IBCTransferMsg{}, "cosmos-sdk/IBCTransferMsg", nil)
cdc.RegisterConcrete(IBCReceiveMsg{}, "cosmos-sdk/IBCReceiveMsg", nil)
}

41
x/stake/commands/flags.go Normal file
View File

@ -0,0 +1,41 @@
package commands
import (
flag "github.com/spf13/pflag"
)
// nolint
const (
FlagAddressDelegator = "address-delegator"
FlagAddressCandidate = "address-candidate"
FlagPubKey = "pubkey"
FlagAmount = "amount"
FlagShares = "shares"
FlagMoniker = "moniker"
FlagIdentity = "keybase-sig"
FlagWebsite = "website"
FlagDetails = "details"
)
// common flagsets to add to various functions
var (
fsPk = flag.NewFlagSet("", flag.ContinueOnError)
fsAmount = flag.NewFlagSet("", flag.ContinueOnError)
fsShares = flag.NewFlagSet("", flag.ContinueOnError)
fsDescription = flag.NewFlagSet("", flag.ContinueOnError)
fsCandidate = flag.NewFlagSet("", flag.ContinueOnError)
fsDelegator = flag.NewFlagSet("", flag.ContinueOnError)
)
func init() {
fsPk.String(FlagPubKey, "", "PubKey of the validator-candidate")
fsAmount.String(FlagAmount, "1fermion", "Amount of coins to bond")
fsShares.String(FlagShares, "", "Amount of shares to unbond, either in decimal or keyword MAX (ex. 1.23456789, 99, MAX)")
fsDescription.String(FlagMoniker, "", "validator-candidate name")
fsDescription.String(FlagIdentity, "", "optional keybase signature")
fsDescription.String(FlagWebsite, "", "optional website")
fsDescription.String(FlagDetails, "", "optional details")
fsCandidate.String(FlagAddressCandidate, "", "hex address of the validator/candidate")
fsDelegator.String(FlagAddressDelegator, "", "hex address of the delegator")
}

View File

@ -5,7 +5,6 @@ import (
"fmt"
"github.com/spf13/cobra"
flag "github.com/spf13/pflag"
"github.com/spf13/viper"
crypto "github.com/tendermint/go-crypto"
@ -16,76 +15,55 @@ import (
"github.com/cosmos/cosmos-sdk/x/stake"
)
// XXX remove dependancy
func PrefixedKey(app string, key []byte) []byte {
prefix := append([]byte(app), byte(0))
return append(prefix, key...)
}
//// create command to query for all candidates
//func GetCmdQueryCandidates(storeName string, cdc *wire.Codec) *cobra.Command {
//cmd := &cobra.Command{
//Use: "candidates",
//Short: "Query for the set of validator-candidates pubkeys",
//RunE: func(cmd *cobra.Command, args []string) error {
//nolint
var (
fsValAddr = flag.NewFlagSet("", flag.ContinueOnError)
fsDelAddr = flag.NewFlagSet("", flag.ContinueOnError)
FlagValidatorAddr = "address"
FlagDelegatorAddr = "delegator-address"
)
//key := stake.CandidatesKey
func init() {
//Add Flags
fsValAddr.String(FlagValidatorAddr, "", "Address of the validator/candidate")
fsDelAddr.String(FlagDelegatorAddr, "", "Delegator hex address")
//ctx := context.NewCoreContextFromViper()
//res, err := ctx.Query(key, storeName)
//if err != nil {
//return err
//}
}
//// parse out the candidates
//candidates := new(stake.Candidates)
//err = cdc.UnmarshalBinary(res, candidates)
//if err != nil {
//return err
//}
//output, err := wire.MarshalJSONIndent(cdc, candidates)
//if err != nil {
//return err
//}
//fmt.Println(string(output))
//return nil
// create command to query for all candidates
func GetCmdQueryCandidates(cdc *wire.Codec, storeName string) *cobra.Command {
cmd := &cobra.Command{
Use: "candidates",
Short: "Query for the set of validator-candidates pubkeys",
RunE: func(cmd *cobra.Command, args []string) error {
//// TODO output with proofs / machine parseable etc.
//},
//}
key := PrefixedKey(stake.MsgType, stake.CandidatesKey)
ctx := context.NewCoreContextFromViper()
res, err := ctx.Query(key, storeName)
if err != nil {
return err
}
// parse out the candidates
candidates := new(stake.Candidates)
err = cdc.UnmarshalJSON(res, candidates)
if err != nil {
return err
}
output, err := wire.MarshalJSONIndent(cdc, candidates)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
// TODO output with proofs / machine parseable etc.
},
}
cmd.Flags().AddFlagSet(fsDelAddr)
return cmd
}
//cmd.Flags().AddFlagSet(fsDelegator)
//return cmd
//}
// get the command to query a candidate
func GetCmdQueryCandidate(cdc *wire.Codec, storeName string) *cobra.Command {
func GetCmdQueryCandidate(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "candidate",
Short: "Query a validator-candidate account",
RunE: func(cmd *cobra.Command, args []string) error {
addr, err := sdk.GetAddress(viper.GetString(FlagValidatorAddr))
addr, err := sdk.GetAddress(viper.GetString(FlagAddressCandidate))
if err != nil {
return err
}
key := PrefixedKey(stake.MsgType, stake.GetCandidateKey(addr))
key := stake.GetCandidateKey(addr)
ctx := context.NewCoreContextFromViper()
@ -111,29 +89,29 @@ func GetCmdQueryCandidate(cdc *wire.Codec, storeName string) *cobra.Command {
},
}
cmd.Flags().AddFlagSet(fsValAddr)
cmd.Flags().AddFlagSet(fsCandidate)
return cmd
}
// get the command to query a single delegator bond
func GetCmdQueryDelegatorBond(cdc *wire.Codec, storeName string) *cobra.Command {
func GetCmdQueryDelegatorBond(storeName string, cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "delegator-bond",
Short: "Query a delegators bond based on address and candidate pubkey",
RunE: func(cmd *cobra.Command, args []string) error {
addr, err := sdk.GetAddress(viper.GetString(FlagValidatorAddr))
addr, err := sdk.GetAddress(viper.GetString(FlagAddressCandidate))
if err != nil {
return err
}
bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddr))
bz, err := hex.DecodeString(viper.GetString(FlagAddressDelegator))
if err != nil {
return err
}
delegator := crypto.Address(bz)
key := PrefixedKey(stake.MsgType, stake.GetDelegatorBondKey(delegator, addr, cdc))
key := stake.GetDelegatorBondKey(delegator, addr, cdc)
ctx := context.NewCoreContextFromViper()
@ -143,7 +121,7 @@ func GetCmdQueryDelegatorBond(cdc *wire.Codec, storeName string) *cobra.Command
}
// parse out the bond
var bond stake.DelegatorBond
bond := new(stake.DelegatorBond)
err = cdc.UnmarshalBinary(res, bond)
if err != nil {
return err
@ -159,49 +137,49 @@ func GetCmdQueryDelegatorBond(cdc *wire.Codec, storeName string) *cobra.Command
},
}
cmd.Flags().AddFlagSet(fsValAddr)
cmd.Flags().AddFlagSet(fsDelAddr)
cmd.Flags().AddFlagSet(fsCandidate)
cmd.Flags().AddFlagSet(fsDelegator)
return cmd
}
// get the command to query all the candidates bonded to a delegator
func GetCmdQueryDelegatorBonds(cdc *wire.Codec, storeName string) *cobra.Command {
cmd := &cobra.Command{
Use: "delegator-candidates",
Short: "Query all delegators candidates' pubkeys based on address",
RunE: func(cmd *cobra.Command, args []string) error {
//// get the command to query all the candidates bonded to a delegator
//func GetCmdQueryDelegatorBonds(storeName string, cdc *wire.Codec) *cobra.Command {
//cmd := &cobra.Command{
//Use: "delegator-candidates",
//Short: "Query all delegators bond's candidate-addresses based on delegator-address",
//RunE: func(cmd *cobra.Command, args []string) error {
bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddr))
if err != nil {
return err
}
delegator := crypto.Address(bz)
//bz, err := hex.DecodeString(viper.GetString(FlagAddressDelegator))
//if err != nil {
//return err
//}
//delegator := crypto.Address(bz)
key := PrefixedKey(stake.MsgType, stake.GetDelegatorBondsKey(delegator, cdc))
//key := stake.GetDelegatorBondsKey(delegator, cdc)
ctx := context.NewCoreContextFromViper()
//ctx := context.NewCoreContextFromViper()
res, err := ctx.Query(key, storeName)
if err != nil {
return err
}
//res, err := ctx.Query(key, storeName)
//if err != nil {
//return err
//}
// parse out the candidates list
var candidates []crypto.PubKey
err = cdc.UnmarshalBinary(res, candidates)
if err != nil {
return err
}
output, err := wire.MarshalJSONIndent(cdc, candidates)
if err != nil {
return err
}
fmt.Println(string(output))
return nil
//// parse out the candidates list
//var candidates []crypto.PubKey
//err = cdc.UnmarshalBinary(res, candidates)
//if err != nil {
//return err
//}
//output, err := wire.MarshalJSONIndent(cdc, candidates)
//if err != nil {
//return err
//}
//fmt.Println(string(output))
//return nil
// TODO output with proofs / machine parseable etc.
},
}
cmd.Flags().AddFlagSet(fsDelAddr)
return cmd
}
//// TODO output with proofs / machine parseable etc.
//},
//}
//cmd.Flags().AddFlagSet(fsDelegator)
//return cmd
//}

View File

@ -5,12 +5,10 @@ import (
"fmt"
"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"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
@ -18,51 +16,6 @@ import (
"github.com/cosmos/cosmos-sdk/x/stake"
)
// nolint
const (
FlagAddressDelegator = "addressD"
FlagAddressCandidate = "addressC"
FlagPubKey = "pubkey"
FlagAmount = "amount"
FlagShares = "shares"
FlagMoniker = "moniker"
FlagIdentity = "keybase-sig"
FlagWebsite = "website"
FlagDetails = "details"
)
// common flagsets to add to various functions
var (
fsPk = flag.NewFlagSet("", flag.ContinueOnError)
fsAmount = flag.NewFlagSet("", flag.ContinueOnError)
fsShares = flag.NewFlagSet("", flag.ContinueOnError)
fsCandidate = flag.NewFlagSet("", flag.ContinueOnError)
fsDelegator = flag.NewFlagSet("", flag.ContinueOnError)
)
func init() {
fsPk.String(FlagPubKey, "", "PubKey of the validator-candidate")
fsAmount.String(FlagAmount, "1fermion", "Amount of coins to bond")
fsShares.String(FlagShares, "", "Amount of shares to unbond, either in decimal or keyword MAX (ex. 1.23456789, 99, MAX)")
fsCandidate.String(FlagMoniker, "", "validator-candidate name")
fsCandidate.String(FlagIdentity, "", "optional keybase signature")
fsCandidate.String(FlagWebsite, "", "optional website")
fsCandidate.String(FlagAddressCandidate, "", "hex address of the validator/candidate")
fsDelegator.String(FlagAddressDelegator, "", "hex address of the delegator")
}
//TODO refactor to common functionality
func getNamePassword() (name, passphrase string, err error) {
name = viper.GetString(client.FlagName)
buf := client.BufferStdin()
prompt := fmt.Sprintf("Password to sign with '%s':", name)
passphrase, err = client.GetPassword(prompt, buf)
return
}
//_________________________________________________________________________________________
// create declare candidacy command
func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
@ -113,6 +66,7 @@ func GetCmdDeclareCandidacy(cdc *wire.Codec) *cobra.Command {
cmd.Flags().AddFlagSet(fsPk)
cmd.Flags().AddFlagSet(fsAmount)
cmd.Flags().AddFlagSet(fsDescription)
cmd.Flags().AddFlagSet(fsCandidate)
return cmd
}
@ -155,7 +109,7 @@ func GetCmdEditCandidacy(cdc *wire.Codec) *cobra.Command {
},
}
cmd.Flags().AddFlagSet(fsPk)
cmd.Flags().AddFlagSet(fsDescription)
cmd.Flags().AddFlagSet(fsCandidate)
return cmd
}
@ -198,9 +152,9 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
},
}
cmd.Flags().AddFlagSet(fsPk)
cmd.Flags().AddFlagSet(fsAmount)
cmd.Flags().AddFlagSet(fsDelegator)
cmd.Flags().AddFlagSet(fsCandidate)
return cmd
}
@ -252,9 +206,9 @@ func GetCmdUnbond(cdc *wire.Codec) *cobra.Command {
},
}
cmd.Flags().AddFlagSet(fsPk)
cmd.Flags().AddFlagSet(fsShares)
cmd.Flags().AddFlagSet(fsDelegator)
cmd.Flags().AddFlagSet(fsCandidate)
return cmd
}
@ -269,9 +223,11 @@ func GetPubKey(pubKeyStr string) (pk crypto.PubKey, err error) {
return
}
if len(pubKeyStr) != 64 { //if len(pkBytes) != 32 {
err = fmt.Errorf("pubkey must be Ed25519 hex encoded string which is 64 characters long")
err = fmt.Errorf("pubkey must be Ed25519 hex encoded string which is 64 characters, this pubkey is %v characters", len(pubKeyStr))
return
}
// TODO: bech32 ...
var pkBytes []byte
pkBytes, err = hex.DecodeString(pubKeyStr)
if err != nil {

View File

@ -4,7 +4,6 @@ import (
"bytes"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank"
abci "github.com/tendermint/abci/types"
)
@ -18,7 +17,7 @@ const (
//_______________________________________________________________________
func NewHandler(k Keeper, ck bank.CoinKeeper) sdk.Handler {
func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
// NOTE msg already has validate basic run
switch msg := msg.(type) {
@ -36,7 +35,7 @@ func NewHandler(k Keeper, ck bank.CoinKeeper) sdk.Handler {
}
}
//_______________________________________________
//_____________________________________________________________________
// NewEndBlocker generates sdk.EndBlocker
// Performs tick functionality
@ -49,6 +48,14 @@ func NewEndBlocker(k Keeper) sdk.EndBlocker {
//_____________________________________________________________________
// InitGenesis - store genesis parameters
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
k.setPool(ctx, data.Pool)
k.setParams(ctx, data.Params)
}
//_____________________________________________________________________
// These functions assume everything has been authenticated,
// now we just perform action and save
@ -92,9 +99,6 @@ func handleMsgEditCandidacy(ctx sdk.Context, msg MsgEditCandidacy, k Keeper) sdk
GasUsed: GasEditCandidacy,
}
}
if candidate.Status == Unbonded { //candidate has been withdrawn
return ErrBondNotNominated(k.codespace).Result()
}
// XXX move to types
// replace all editable fields (clients should autofill existing values)
@ -136,7 +140,7 @@ func delegate(ctx sdk.Context, k Keeper, delegatorAddr sdk.Address,
bondAmt sdk.Coin, candidate Candidate) sdk.Error {
// Get or create the delegator bond
bond, found := k.getDelegatorBond(ctx, delegatorAddr, candidate.Address)
bond, found := k.GetDelegatorBond(ctx, delegatorAddr, candidate.Address)
if !found {
bond = DelegatorBond{
DelegatorAddr: delegatorAddr,
@ -163,7 +167,7 @@ func delegate(ctx sdk.Context, k Keeper, delegatorAddr sdk.Address,
func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result {
// check if bond has any shares in it unbond
bond, found := k.getDelegatorBond(ctx, msg.DelegatorAddr, msg.CandidateAddr)
bond, found := k.GetDelegatorBond(ctx, msg.DelegatorAddr, msg.CandidateAddr)
if !found {
return ErrNoDelegatorForAddress(k.codespace).Result()
}
@ -171,11 +175,7 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result {
return ErrInsufficientFunds(k.codespace).Result()
}
// test getting rational number from decimal provided
shares, err := sdk.NewRatFromDecimal(msg.Shares)
if err != nil {
return err.Result()
}
var shares sdk.Rat
// test that there are enough shares to unbond
if msg.Shares == "MAX" {
@ -183,6 +183,11 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result {
return ErrNotEnoughBondShares(k.codespace, msg.Shares).Result()
}
} else {
var err sdk.Error
shares, err = sdk.NewRatFromDecimal(msg.Shares)
if err != nil {
return err.Result()
}
if bond.Shares.LT(shares) {
return ErrNotEnoughBondShares(k.codespace, msg.Shares).Result()
}
@ -253,40 +258,3 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result {
k.setPool(ctx, p)
return sdk.Result{}
}
// TODO use or remove
//// Perform all the actions required to bond tokens to a delegator bond from their account
//func BondCoins(ctx sdk.Context, k Keeper, bond DelegatorBond,
//candidate Candidate, amount sdk.Coin) (DelegatorBond, Candidate, Pool, sdk.Error) {
//pool := k.GetPool(ctx)
//_, err := k.coinKeeper.SubtractCoins(ctx, bond.DelegatorAddr, sdk.Coins{amount})
//if err != nil {
//return bond, candidate, pool, err
//}
//pool, candidate, newShares := pool.candidateAddTokens(candidate, amount.Amount)
//bond.Shares = bond.Shares.Add(newShares)
//return bond, candidate, pool, nil
//}
//// Perform all the actions required to bond tokens to a delegator bond from their account
//func UnbondCoins(ctx sdk.Context, k Keeper, bond DelegatorBond,
//candidate Candidate, shares sdk.Rat) (DelegatorBond, Candidate, Pool, sdk.Error) {
//pool := k.GetPool(ctx)
//// subtract bond tokens from delegator bond
//if bond.Shares.LT(shares) {
//errMsg := fmt.Sprintf("cannot unbond %v shares, only have %v shares available", shares, bond.Shares)
//return bond, candidate, pool, sdk.ErrInsufficientFunds(errMsg)
//}
//bond.Shares = bond.Shares.Sub(shares)
//pool, candidate, returnAmount := p.candidateRemoveShares(candidate, shares)
//returnCoins := sdk.Coins{{k.GetParams(ctx).BondDenom, returnAmount}}
//_, err := k.coinKeeper.AddCoins(ctx, candidate.Address, returnCoins)
//if err != nil {
//return err
//}
//return bond, candidate, pool, nil
//}

View File

@ -83,7 +83,7 @@ func TestIncrementsMsgDelegate(t *testing.T) {
//Check that the accounts and the bond account have the appropriate values
candidate, found := keeper.GetCandidate(ctx, candidateAddr)
require.True(t, found)
bond, found := keeper.getDelegatorBond(ctx, delegatorAddr, candidateAddr)
bond, found := keeper.GetDelegatorBond(ctx, delegatorAddr, candidateAddr)
require.True(t, found)
expBond := int64(i+1) * bondAmount
@ -139,7 +139,7 @@ func TestIncrementsMsgUnbond(t *testing.T) {
//Check that the accounts and the bond account have the appropriate values
candidate, found = keeper.GetCandidate(ctx, candidateAddr)
require.True(t, found)
bond, found := keeper.getDelegatorBond(ctx, delegatorAddr, candidateAddr)
bond, found := keeper.GetDelegatorBond(ctx, delegatorAddr, candidateAddr)
require.True(t, found)
expBond := initBond - int64(i+1)*unbondShares
@ -254,7 +254,7 @@ func TestMultipleMsgDelegate(t *testing.T) {
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
//Check that the account is bonded
bond, found := keeper.getDelegatorBond(ctx, delegatorAddr, candidateAddr)
bond, found := keeper.GetDelegatorBond(ctx, delegatorAddr, candidateAddr)
require.True(t, found)
require.NotNil(t, bond, "expected delegatee bond %d to exist", bond)
}
@ -266,7 +266,7 @@ func TestMultipleMsgDelegate(t *testing.T) {
require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got)
//Check that the account is unbonded
_, found := keeper.getDelegatorBond(ctx, delegatorAddr, candidateAddr)
_, found := keeper.GetDelegatorBond(ctx, delegatorAddr, candidateAddr)
require.False(t, found)
}
}

View File

@ -2,7 +2,6 @@ package stake
import (
"bytes"
"encoding/json"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
@ -24,7 +23,7 @@ type Keeper struct {
codespace sdk.CodespaceType
}
func NewKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, ck bank.CoinKeeper, codespace sdk.CodespaceType) Keeper {
func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.CoinKeeper, codespace sdk.CodespaceType) Keeper {
keeper := Keeper{
storeKey: key,
cdc: cdc,
@ -34,17 +33,6 @@ func NewKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, ck bank.CoinK
return keeper
}
// InitGenesis - store genesis parameters
func (k Keeper) InitGenesis(ctx sdk.Context, data json.RawMessage) error {
var state GenesisState
if err := json.Unmarshal(data, &state); err != nil {
return err
}
k.setPool(ctx, state.Pool)
k.setParams(ctx, state.Params)
return nil
}
//_________________________________________________________________________
// get a single candidate
@ -309,7 +297,8 @@ func (k Keeper) clearAccUpdateValidators(ctx sdk.Context) {
//_____________________________________________________________________
func (k Keeper) getDelegatorBond(ctx sdk.Context,
// load a delegator bong
func (k Keeper) GetDelegatorBond(ctx sdk.Context,
delegatorAddr, candidateAddr sdk.Address) (bond DelegatorBond, found bool) {
store := ctx.KVStore(k.storeKey)
@ -326,7 +315,7 @@ func (k Keeper) getDelegatorBond(ctx sdk.Context,
}
// load all bonds of a delegator
func (k Keeper) getDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRetrieve int16) (bonds []DelegatorBond) {
func (k Keeper) GetDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRetrieve int16) (bonds []DelegatorBond) {
store := ctx.KVStore(k.storeKey)
delegatorPrefixKey := GetDelegatorBondsKey(delegator, k.cdc)
iterator := store.Iterator(subspace(delegatorPrefixKey)) //smallest to largest

View File

@ -2,11 +2,9 @@ package stake
import (
"bytes"
"encoding/json"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
crypto "github.com/tendermint/go-crypto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -128,19 +126,19 @@ func TestBond(t *testing.T) {
}
// check the empty keeper first
_, found := keeper.getDelegatorBond(ctx, addrDels[0], addrVals[0])
_, found := keeper.GetDelegatorBond(ctx, addrDels[0], addrVals[0])
assert.False(t, found)
// set and retrieve a record
keeper.setDelegatorBond(ctx, bond1to1)
resBond, found := keeper.getDelegatorBond(ctx, addrDels[0], addrVals[0])
resBond, found := keeper.GetDelegatorBond(ctx, addrDels[0], addrVals[0])
assert.True(t, found)
assert.True(t, bondsEqual(bond1to1, resBond))
// modify a records, save, and retrieve
bond1to1.Shares = sdk.NewRat(99)
keeper.setDelegatorBond(ctx, bond1to1)
resBond, found = keeper.getDelegatorBond(ctx, addrDels[0], addrVals[0])
resBond, found = keeper.GetDelegatorBond(ctx, addrDels[0], addrVals[0])
assert.True(t, found)
assert.True(t, bondsEqual(bond1to1, resBond))
@ -159,16 +157,16 @@ func TestBond(t *testing.T) {
keeper.setDelegatorBond(ctx, bond2to3)
// test all bond retrieve capabilities
resBonds := keeper.getDelegatorBonds(ctx, addrDels[0], 5)
resBonds := keeper.GetDelegatorBonds(ctx, addrDels[0], 5)
require.Equal(t, 3, len(resBonds))
assert.True(t, bondsEqual(bond1to1, resBonds[0]))
assert.True(t, bondsEqual(bond1to2, resBonds[1]))
assert.True(t, bondsEqual(bond1to3, resBonds[2]))
resBonds = keeper.getDelegatorBonds(ctx, addrDels[0], 3)
resBonds = keeper.GetDelegatorBonds(ctx, addrDels[0], 3)
require.Equal(t, 3, len(resBonds))
resBonds = keeper.getDelegatorBonds(ctx, addrDels[0], 2)
resBonds = keeper.GetDelegatorBonds(ctx, addrDels[0], 2)
require.Equal(t, 2, len(resBonds))
resBonds = keeper.getDelegatorBonds(ctx, addrDels[1], 5)
resBonds = keeper.GetDelegatorBonds(ctx, addrDels[1], 5)
require.Equal(t, 3, len(resBonds))
assert.True(t, bondsEqual(bond2to1, resBonds[0]))
assert.True(t, bondsEqual(bond2to2, resBonds[1]))
@ -176,9 +174,9 @@ func TestBond(t *testing.T) {
// delete a record
keeper.removeDelegatorBond(ctx, bond2to3)
_, found = keeper.getDelegatorBond(ctx, addrDels[1], addrVals[2])
_, found = keeper.GetDelegatorBond(ctx, addrDels[1], addrVals[2])
assert.False(t, found)
resBonds = keeper.getDelegatorBonds(ctx, addrDels[1], 5)
resBonds = keeper.GetDelegatorBonds(ctx, addrDels[1], 5)
require.Equal(t, 2, len(resBonds))
assert.True(t, bondsEqual(bond2to1, resBonds[0]))
assert.True(t, bondsEqual(bond2to2, resBonds[1]))
@ -186,11 +184,11 @@ func TestBond(t *testing.T) {
// delete all the records from delegator 2
keeper.removeDelegatorBond(ctx, bond2to1)
keeper.removeDelegatorBond(ctx, bond2to2)
_, found = keeper.getDelegatorBond(ctx, addrDels[1], addrVals[0])
_, found = keeper.GetDelegatorBond(ctx, addrDels[1], addrVals[0])
assert.False(t, found)
_, found = keeper.getDelegatorBond(ctx, addrDels[1], addrVals[1])
_, found = keeper.GetDelegatorBond(ctx, addrDels[1], addrVals[1])
assert.False(t, found)
resBonds = keeper.getDelegatorBonds(ctx, addrDels[1], 5)
resBonds = keeper.GetDelegatorBonds(ctx, addrDels[1], 5)
require.Equal(t, 0, len(resBonds))
}
@ -316,15 +314,6 @@ func TestGetAccUpdateValidators(t *testing.T) {
}
}
// to compare pubkeys between abci pubkey and crypto.PubKey
wirePK := func(pk crypto.PubKey) []byte {
pkBytes, err := keeper.cdc.MarshalBinary(pk)
if err != nil {
panic(err)
}
return pkBytes
}
// test from nothing to something
// candidate set: {} -> {c1, c3}
// validator set: {} -> {c1, c3}
@ -479,7 +468,7 @@ func TestGetAccUpdateValidators(t *testing.T) {
acc = keeper.getAccUpdateValidators(ctx)
require.Equal(t, 2, len(acc), "%v", acc)
assert.Equal(t, wirePK(candidatesIn[0].PubKey), acc[0].PubKey)
assert.Equal(t, candidatesIn[0].PubKey.Bytes(), acc[0].PubKey)
assert.Equal(t, int64(0), acc[0].Power)
assert.Equal(t, vals[0].abciValidator(keeper.cdc), acc[1])
@ -504,10 +493,10 @@ func TestGetAccUpdateValidators(t *testing.T) {
require.Equal(t, 0, len(candidates))
acc = keeper.getAccUpdateValidators(ctx)
require.Equal(t, 4, len(acc))
assert.Equal(t, wirePK(candidatesIn[1].PubKey), acc[0].PubKey)
assert.Equal(t, wirePK(candidatesIn[2].PubKey), acc[1].PubKey)
assert.Equal(t, wirePK(candidatesIn[3].PubKey), acc[2].PubKey)
assert.Equal(t, wirePK(candidatesIn[4].PubKey), acc[3].PubKey)
assert.Equal(t, candidatesIn[1].PubKey.Bytes(), acc[0].PubKey)
assert.Equal(t, candidatesIn[2].PubKey.Bytes(), acc[1].PubKey)
assert.Equal(t, candidatesIn[3].PubKey.Bytes(), acc[2].PubKey)
assert.Equal(t, candidatesIn[4].PubKey.Bytes(), acc[3].PubKey)
assert.Equal(t, int64(0), acc[0].Power)
assert.Equal(t, int64(0), acc[1].Power)
assert.Equal(t, int64(0), acc[2].Power)
@ -584,31 +573,3 @@ func TestPool(t *testing.T) {
resPool = keeper.GetPool(ctx)
assert.Equal(t, expPool, resPool)
}
func TestInitGenesis(t *testing.T) {
ctx, _, keeper := createTestInput(t, false, 0)
jsonStr := `{
"params": {
"inflation_rate_change": {"num": 13, "denom": 100},
"inflation_max": {"num": 20, "denom": 100},
"inflation_min": {"num": 7, "denom": 100},
"goal_bonded": {"num": 67, "denom": 100},
"max_validators": 100,
"bond_denom": "fermion"
},
"pool": {
"total_supply": 0,
"bonded_shares": {"num": 0, "denom": 1},
"unbonded_shares": {"num": 0, "denom": 1},
"bonded_pool": 0,
"unbonded_pool": 0,
"inflation_last_time": 0,
"inflation": {"num": 7, "denom": 100}
}
}`
encoded := json.RawMessage(jsonStr)
err := keeper.InitGenesis(ctx, encoded)
require.Nil(t, err)
require.Equal(t, keeper.GetPool(ctx), initialPool())
require.Equal(t, keeper.GetParams(ctx), defaultParams())
}

View File

@ -75,6 +75,14 @@ func initialPool() Pool {
}
}
// get raw genesis raw message for testing
func GetDefaultGenesisState() GenesisState {
return GenesisState{
Pool: initialPool(),
Params: defaultParams(),
}
}
// XXX reference the common declaration of this function
func subspace(prefix []byte) (start, end []byte) {
end = make([]byte, len(prefix))
@ -132,7 +140,7 @@ func createTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context
&auth.BaseAccount{}, // prototype
).Seal()
ck := bank.NewCoinKeeper(accountMapper)
keeper := NewKeeper(ctx, cdc, keyStake, ck, DefaultCodespace)
keeper := NewKeeper(cdc, keyStake, ck, DefaultCodespace)
keeper.setPool(ctx, initialPool())
keeper.setParams(ctx, defaultParams())

View File

@ -7,6 +7,14 @@ import (
crypto "github.com/tendermint/go-crypto"
)
// GenesisState - all staking state that must be provided at genesis
type GenesisState struct {
Pool Pool `json:"pool"`
Params Params `json:"params"`
}
//_________________________________________________________________________
// Params defines the high level settings for staking
type Params struct {
InflationRateChange sdk.Rat `json:"inflation_rate_change"` // maximum annual change in inflation rate
@ -31,13 +39,7 @@ type Pool struct {
Inflation sdk.Rat `json:"inflation"` // current annual inflation rate
}
// GenesisState - all staking state that must be provided at genesis
type GenesisState struct {
Pool Pool `json:"pool"`
Params Params `json:"params"`
}
//_______________________________________________________________________________________________________
//_________________________________________________________________________
// CandidateStatus - status of a validator-candidate
type CandidateStatus byte
@ -65,6 +67,9 @@ type Candidate struct {
Description Description `json:"description"` // Description terms for the candidate
}
// Candidates - list of Candidates
type Candidates []Candidate
// NewCandidate - initialize a new candidate
func NewCandidate(address sdk.Address, pubKey crypto.PubKey, description Description) Candidate {
return Candidate{
@ -126,12 +131,8 @@ type Validator struct {
// abci validator from stake validator type
func (v Validator) abciValidator(cdc *wire.Codec) abci.Validator {
pkBytes, err := cdc.MarshalBinary(v.PubKey)
if err != nil {
panic(err)
}
return abci.Validator{
PubKey: pkBytes,
PubKey: v.PubKey.Bytes(),
Power: v.Power.Evaluate(),
}
}
@ -139,29 +140,20 @@ func (v Validator) abciValidator(cdc *wire.Codec) abci.Validator {
// abci validator from stake validator type
// with zero power used for validator updates
func (v Validator) abciValidatorZero(cdc *wire.Codec) abci.Validator {
pkBytes, err := cdc.MarshalBinary(v.PubKey)
if err != nil {
panic(err)
}
return abci.Validator{
PubKey: pkBytes,
PubKey: v.PubKey.Bytes(),
Power: 0,
}
}
//_________________________________________________________________________
// Candidates - list of Candidates
type Candidates []Candidate
//_________________________________________________________________________
// DelegatorBond represents the bond with tokens held by an account. It is
// owned by one delegator, and is associated with the voting power of one
// pubKey.
// TODO better way of managing space
type DelegatorBond struct {
DelegatorAddr sdk.Address `json:"delegatoraddr"`
DelegatorAddr sdk.Address `json:"delegator_addr"`
CandidateAddr sdk.Address `json:"candidate_addr"`
Shares sdk.Rat `json:"shares"`
}

View File

@ -4,9 +4,10 @@ import (
"github.com/cosmos/cosmos-sdk/wire"
)
// XXX complete
// Register concrete types on wire codec
func RegisterWire(cdc *wire.Codec) {
// TODO include option to always include prefix bytes.
//cdc.RegisterConcrete(SendMsg{}, "cosmos-sdk/SendMsg", nil)
//cdc.RegisterConcrete(IssueMsg{}, "cosmos-sdk/IssueMsg", nil)
cdc.RegisterConcrete(MsgDeclareCandidacy{}, "cosmos-sdk/MsgDeclareCandidacy", nil)
cdc.RegisterConcrete(MsgEditCandidacy{}, "cosmos-sdk/MsgEditCandidacy", nil)
cdc.RegisterConcrete(MsgDelegate{}, "cosmos-sdk/MsgDelegate", nil)
cdc.RegisterConcrete(MsgUnbond{}, "cosmos-sdk/MsgUnbond", nil)
}