Merge pull request #655 from cosmos/adrian/simple_staking
Adrian/simple staking
This commit is contained in:
commit
328dd2f73f
3
.gitignore
vendored
3
.gitignore
vendored
@ -14,6 +14,9 @@ docs/_build
|
||||
coverage.txt
|
||||
profile.out
|
||||
.vscode
|
||||
coverage.txt
|
||||
profile.out
|
||||
client/lcd/keys.db/
|
||||
|
||||
### Vagrant ###
|
||||
.vagrant/
|
||||
|
||||
2
Makefile
2
Makefile
@ -71,7 +71,7 @@ test_unit:
|
||||
@go test $(PACKAGES)
|
||||
|
||||
test_cover:
|
||||
@rm -rf examples/basecoin/vendor
|
||||
@rm -rf examples/basecoin/vendor/
|
||||
@rm -rf client/lcd/keys.db ~/.tendermint_test
|
||||
@bash tests/test_cover.sh
|
||||
@rm -rf client/lcd/keys.db ~/.tendermint_test
|
||||
|
||||
@ -15,6 +15,7 @@ import (
|
||||
"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/staking"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool"
|
||||
@ -31,8 +32,9 @@ type BasecoinApp struct {
|
||||
cdc *wire.Codec
|
||||
|
||||
// keys to access the substores
|
||||
capKeyMainStore *sdk.KVStoreKey
|
||||
capKeyIBCStore *sdk.KVStoreKey
|
||||
capKeyMainStore *sdk.KVStoreKey
|
||||
capKeyIBCStore *sdk.KVStoreKey
|
||||
capKeyStakingStore *sdk.KVStoreKey
|
||||
|
||||
// Manage getting and setting accounts
|
||||
accountMapper sdk.AccountMapper
|
||||
@ -41,10 +43,11 @@ type BasecoinApp struct {
|
||||
func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||
// create your application object
|
||||
var app = &BasecoinApp{
|
||||
BaseApp: bam.NewBaseApp(appName, logger, db),
|
||||
cdc: MakeCodec(),
|
||||
capKeyMainStore: sdk.NewKVStoreKey("main"),
|
||||
capKeyIBCStore: sdk.NewKVStoreKey("ibc"),
|
||||
BaseApp: bam.NewBaseApp(appName, logger, db),
|
||||
cdc: MakeCodec(),
|
||||
capKeyMainStore: sdk.NewKVStoreKey("main"),
|
||||
capKeyIBCStore: sdk.NewKVStoreKey("ibc"),
|
||||
capKeyStakingStore: sdk.NewKVStoreKey("staking"),
|
||||
}
|
||||
|
||||
// define the accountMapper
|
||||
@ -57,18 +60,18 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||
coinKeeper := bank.NewCoinKeeper(app.accountMapper)
|
||||
coolMapper := cool.NewMapper(app.capKeyMainStore)
|
||||
ibcMapper := ibc.NewIBCMapper(app.cdc, app.capKeyIBCStore)
|
||||
stakingMapper := staking.NewMapper(app.capKeyStakingStore)
|
||||
app.Router().
|
||||
AddRoute("bank", bank.NewHandler(coinKeeper)).
|
||||
AddRoute("cool", cool.NewHandler(coinKeeper, coolMapper)).
|
||||
AddRoute("sketchy", sketchy.NewHandler()).
|
||||
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper))
|
||||
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)).
|
||||
AddRoute("staking", staking.NewHandler(stakingMapper, coinKeeper))
|
||||
|
||||
// initialize BaseApp
|
||||
app.SetTxDecoder(app.txDecoder)
|
||||
app.SetInitChainer(app.initChainer)
|
||||
// TODO: mounting multiple stores is broken
|
||||
// https://github.com/cosmos/cosmos-sdk/issues/532
|
||||
app.MountStoresIAVL(app.capKeyMainStore, app.capKeyIBCStore)
|
||||
app.MountStoresIAVL(app.capKeyMainStore, app.capKeyIBCStore, app.capKeyStakingStore)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper))
|
||||
err := app.LoadLatestVersion(app.capKeyMainStore)
|
||||
if err != nil {
|
||||
@ -81,13 +84,14 @@ func NewBasecoinApp(logger log.Logger, db dbm.DB) *BasecoinApp {
|
||||
// custom tx codec
|
||||
// TODO: use new go-wire
|
||||
func MakeCodec() *wire.Codec {
|
||||
|
||||
const msgTypeSend = 0x1
|
||||
const msgTypeIssue = 0x2
|
||||
const msgTypeQuiz = 0x3
|
||||
const msgTypeSetTrend = 0x4
|
||||
const msgTypeIBCTransferMsg = 0x5
|
||||
const msgTypeIBCReceiveMsg = 0x6
|
||||
const msgTypeBondMsg = 0x7
|
||||
const msgTypeUnbondMsg = 0x8
|
||||
var _ = oldwire.RegisterInterface(
|
||||
struct{ sdk.Msg }{},
|
||||
oldwire.ConcreteType{bank.SendMsg{}, msgTypeSend},
|
||||
@ -96,6 +100,8 @@ func MakeCodec() *wire.Codec {
|
||||
oldwire.ConcreteType{cool.SetTrendMsg{}, msgTypeSetTrend},
|
||||
oldwire.ConcreteType{ibc.IBCTransferMsg{}, msgTypeIBCTransferMsg},
|
||||
oldwire.ConcreteType{ibc.IBCReceiveMsg{}, msgTypeIBCReceiveMsg},
|
||||
oldwire.ConcreteType{staking.BondMsg{}, msgTypeBondMsg},
|
||||
oldwire.ConcreteType{staking.UnbondMsg{}, msgTypeUnbondMsg},
|
||||
)
|
||||
|
||||
const accTypeApp = 0x1
|
||||
|
||||
@ -2,9 +2,8 @@ package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
|
||||
@ -14,14 +13,15 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
|
||||
coolcmd "github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool/commands"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
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"
|
||||
stakingcmd "github.com/cosmos/cosmos-sdk/x/staking/commands"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
coolcmd "github.com/cosmos/cosmos-sdk/examples/basecoin/x/cool/commands"
|
||||
)
|
||||
|
||||
// gaiacliCmd is the entry point for this binary
|
||||
@ -77,6 +77,11 @@ func main() {
|
||||
basecliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
ibccmd.IBCRelayCmd(cdc),
|
||||
stakingcmd.BondTxCmd(cdc),
|
||||
)...)
|
||||
basecliCmd.AddCommand(
|
||||
client.PostCommands(
|
||||
stakingcmd.UnbondTxCmd(cdc),
|
||||
)...)
|
||||
|
||||
// add proxy, version and key info
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
//"os"
|
||||
// "os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
||||
100
x/staking/commands/commands.go
Normal file
100
x/staking/commands/commands.go
Normal file
@ -0,0 +1,100 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/builder"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
)
|
||||
|
||||
const (
|
||||
flagStake = "stake"
|
||||
flagValidator = "validator"
|
||||
)
|
||||
|
||||
func BondTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||
cmdr := commander{cdc}
|
||||
cmd := &cobra.Command{
|
||||
Use: "bond",
|
||||
Short: "Bond to a validator",
|
||||
RunE: cmdr.bondTxCmd,
|
||||
}
|
||||
cmd.Flags().String(flagStake, "", "Amount of coins to stake")
|
||||
cmd.Flags().String(flagValidator, "", "Validator address to stake")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func UnbondTxCmd(cdc *wire.Codec) *cobra.Command {
|
||||
cmdr := commander{cdc}
|
||||
cmd := &cobra.Command{
|
||||
Use: "unbond",
|
||||
Short: "Unbond from a validator",
|
||||
RunE: cmdr.unbondTxCmd,
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
type commander struct {
|
||||
cdc *wire.Codec
|
||||
}
|
||||
|
||||
func (co commander) bondTxCmd(cmd *cobra.Command, args []string) error {
|
||||
from, err := builder.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stake, err := sdk.ParseCoin(viper.GetString(flagStake))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rawPubKey, err := hex.DecodeString(viper.GetString(flagValidator))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var pubKey crypto.PubKeyEd25519
|
||||
copy(pubKey[:], rawPubKey)
|
||||
|
||||
msg := staking.NewBondMsg(from, stake, pubKey.Wrap())
|
||||
|
||||
return co.sendMsg(msg)
|
||||
}
|
||||
|
||||
func (co commander) unbondTxCmd(cmd *cobra.Command, args []string) error {
|
||||
from, err := builder.GetFromAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := staking.NewUnbondMsg(from)
|
||||
|
||||
return co.sendMsg(msg)
|
||||
}
|
||||
|
||||
func (co commander) sendMsg(msg sdk.Msg) error {
|
||||
name := viper.GetString(client.FlagName)
|
||||
buf := client.BufferStdin()
|
||||
prompt := fmt.Sprintf("Password to sign with '%s':", name)
|
||||
passphrase, err := client.GetPassword(prompt, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := builder.SignBuildBroadcast(name, passphrase, msg, co.cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
}
|
||||
31
x/staking/errors.go
Normal file
31
x/staking/errors.go
Normal file
@ -0,0 +1,31 @@
|
||||
package staking
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// Staking errors reserve 300 - 399.
|
||||
CodeEmptyValidator sdk.CodeType = 300
|
||||
CodeInvalidUnbond sdk.CodeType = 301
|
||||
CodeEmptyStake sdk.CodeType = 302
|
||||
)
|
||||
|
||||
func ErrEmptyValidator() sdk.Error {
|
||||
return newError(CodeEmptyValidator, "")
|
||||
}
|
||||
|
||||
func ErrInvalidUnbond() sdk.Error {
|
||||
return newError(CodeInvalidUnbond, "")
|
||||
}
|
||||
|
||||
func ErrEmptyStake() sdk.Error {
|
||||
return newError(CodeEmptyStake, "")
|
||||
}
|
||||
|
||||
// -----------------------------
|
||||
// Helpers
|
||||
|
||||
func newError(code sdk.CodeType, msg string) sdk.Error {
|
||||
return sdk.NewError(code, msg)
|
||||
}
|
||||
69
x/staking/handler.go
Normal file
69
x/staking/handler.go
Normal file
@ -0,0 +1,69 @@
|
||||
package staking
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/abci/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
func NewHandler(sm StakingMapper, ck bank.CoinKeeper) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
|
||||
switch msg := msg.(type) {
|
||||
case BondMsg:
|
||||
return handleBondMsg(ctx, sm, ck, msg)
|
||||
case UnbondMsg:
|
||||
return handleUnbondMsg(ctx, sm, ck, msg)
|
||||
default:
|
||||
return sdk.ErrUnknownRequest("No match for message type.").Result()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleBondMsg(ctx sdk.Context, sm StakingMapper, ck bank.CoinKeeper, msg BondMsg) sdk.Result {
|
||||
_, err := ck.SubtractCoins(ctx, msg.Address, []sdk.Coin{msg.Stake})
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
power, err := sm.Bond(ctx, msg.Address, msg.PubKey, msg.Stake.Amount)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
valSet := abci.Validator{
|
||||
PubKey: msg.PubKey.Bytes(),
|
||||
Power: power,
|
||||
}
|
||||
|
||||
return sdk.Result{
|
||||
Code: sdk.CodeOK,
|
||||
ValidatorUpdates: abci.Validators{valSet},
|
||||
}
|
||||
}
|
||||
|
||||
func handleUnbondMsg(ctx sdk.Context, sm StakingMapper, ck bank.CoinKeeper, msg UnbondMsg) sdk.Result {
|
||||
pubKey, power, err := sm.Unbond(ctx, msg.Address)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
stake := sdk.Coin{
|
||||
Denom: "mycoin",
|
||||
Amount: power,
|
||||
}
|
||||
_, err = ck.AddCoins(ctx, msg.Address, sdk.Coins{stake})
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
}
|
||||
|
||||
valSet := abci.Validator{
|
||||
PubKey: pubKey.Bytes(),
|
||||
Power: int64(0),
|
||||
}
|
||||
|
||||
return sdk.Result{
|
||||
Code: sdk.CodeOK,
|
||||
ValidatorUpdates: abci.Validators{valSet},
|
||||
}
|
||||
}
|
||||
91
x/staking/mapper.go
Normal file
91
x/staking/mapper.go
Normal file
@ -0,0 +1,91 @@
|
||||
package staking
|
||||
|
||||
import (
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
wire "github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
type StakingMapper struct {
|
||||
key sdk.StoreKey
|
||||
cdc *wire.Codec
|
||||
}
|
||||
|
||||
func NewMapper(key sdk.StoreKey) StakingMapper {
|
||||
cdc := wire.NewCodec()
|
||||
return StakingMapper{
|
||||
key: key,
|
||||
cdc: cdc,
|
||||
}
|
||||
}
|
||||
|
||||
func (sm StakingMapper) getBondInfo(ctx sdk.Context, addr sdk.Address) bondInfo {
|
||||
store := ctx.KVStore(sm.key)
|
||||
bz := store.Get(addr)
|
||||
if bz == nil {
|
||||
return bondInfo{}
|
||||
}
|
||||
var bi bondInfo
|
||||
err := sm.cdc.UnmarshalBinary(bz, &bi)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bi
|
||||
}
|
||||
|
||||
func (sm StakingMapper) setBondInfo(ctx sdk.Context, addr sdk.Address, bi bondInfo) {
|
||||
store := ctx.KVStore(sm.key)
|
||||
bz, err := sm.cdc.MarshalBinary(bi)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
store.Set(addr, bz)
|
||||
}
|
||||
|
||||
func (sm StakingMapper) deleteBondInfo(ctx sdk.Context, addr sdk.Address) {
|
||||
store := ctx.KVStore(sm.key)
|
||||
store.Delete(addr)
|
||||
}
|
||||
|
||||
func (sm StakingMapper) Bond(ctx sdk.Context, addr sdk.Address, pubKey crypto.PubKey, power int64) (int64, sdk.Error) {
|
||||
bi := sm.getBondInfo(ctx, addr)
|
||||
if bi.isEmpty() {
|
||||
bi = bondInfo{
|
||||
PubKey: pubKey,
|
||||
Power: power,
|
||||
}
|
||||
sm.setBondInfo(ctx, addr, bi)
|
||||
return bi.Power, nil
|
||||
}
|
||||
|
||||
newPower := bi.Power + power
|
||||
newBi := bondInfo{
|
||||
PubKey: bi.PubKey,
|
||||
Power: newPower,
|
||||
}
|
||||
sm.setBondInfo(ctx, addr, newBi)
|
||||
|
||||
return newBi.Power, nil
|
||||
}
|
||||
|
||||
func (sm StakingMapper) Unbond(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, int64, sdk.Error) {
|
||||
bi := sm.getBondInfo(ctx, addr)
|
||||
if bi.isEmpty() {
|
||||
return crypto.PubKey{}, 0, ErrInvalidUnbond()
|
||||
}
|
||||
sm.deleteBondInfo(ctx, addr)
|
||||
return bi.PubKey, bi.Power, nil
|
||||
}
|
||||
|
||||
type bondInfo struct {
|
||||
PubKey crypto.PubKey
|
||||
Power int64
|
||||
}
|
||||
|
||||
func (bi bondInfo) isEmpty() bool {
|
||||
if bi == (bondInfo{}) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
76
x/staking/mapper_test.go
Normal file
76
x/staking/mapper_test.go
Normal file
@ -0,0 +1,76 @@
|
||||
package staking
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey) {
|
||||
db := dbm.NewMemDB()
|
||||
capKey := sdk.NewKVStoreKey("capkey")
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db)
|
||||
ms.LoadLatestVersion()
|
||||
return ms, capKey
|
||||
}
|
||||
|
||||
func TestStakingMapperGetSet(t *testing.T) {
|
||||
ms, capKey := setupMultiStore()
|
||||
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
|
||||
stakingMapper := NewMapper(capKey)
|
||||
addr := sdk.Address([]byte("some-address"))
|
||||
|
||||
bi := stakingMapper.getBondInfo(ctx, addr)
|
||||
assert.Equal(t, bi, bondInfo{})
|
||||
|
||||
privKey := crypto.GenPrivKeyEd25519()
|
||||
|
||||
bi = bondInfo{
|
||||
PubKey: privKey.PubKey(),
|
||||
Power: int64(10),
|
||||
}
|
||||
fmt.Printf("Pubkey: %v\n", privKey.PubKey())
|
||||
stakingMapper.setBondInfo(ctx, addr, bi)
|
||||
|
||||
savedBi := stakingMapper.getBondInfo(ctx, addr)
|
||||
assert.NotNil(t, savedBi)
|
||||
fmt.Printf("Bond Info: %v\n", savedBi)
|
||||
assert.Equal(t, int64(10), savedBi.Power)
|
||||
}
|
||||
|
||||
func TestBonding(t *testing.T) {
|
||||
ms, capKey := setupMultiStore()
|
||||
|
||||
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
|
||||
stakingMapper := NewMapper(capKey)
|
||||
addr := sdk.Address([]byte("some-address"))
|
||||
privKey := crypto.GenPrivKeyEd25519()
|
||||
pubKey := privKey.PubKey()
|
||||
|
||||
_, _, err := stakingMapper.Unbond(ctx, addr)
|
||||
assert.Equal(t, err, ErrInvalidUnbond())
|
||||
|
||||
_, err = stakingMapper.Bond(ctx, addr, pubKey, 10)
|
||||
assert.Nil(t, err)
|
||||
|
||||
power, err := stakingMapper.Bond(ctx, addr, pubKey, 10)
|
||||
assert.Equal(t, int64(20), power)
|
||||
|
||||
pk, _, err := stakingMapper.Unbond(ctx, addr)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, pubKey, pk)
|
||||
|
||||
_, _, err = stakingMapper.Unbond(ctx, addr)
|
||||
assert.Equal(t, err, ErrInvalidUnbond())
|
||||
}
|
||||
91
x/staking/types.go
Normal file
91
x/staking/types.go
Normal file
@ -0,0 +1,91 @@
|
||||
package staking
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// -------------------------
|
||||
// BondMsg
|
||||
|
||||
type BondMsg struct {
|
||||
Address sdk.Address `json:"address"`
|
||||
Stake sdk.Coin `json:"coins"`
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
}
|
||||
|
||||
func NewBondMsg(addr sdk.Address, stake sdk.Coin, pubKey crypto.PubKey) BondMsg {
|
||||
return BondMsg{
|
||||
Address: addr,
|
||||
Stake: stake,
|
||||
PubKey: pubKey,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg BondMsg) Type() string {
|
||||
return "staking"
|
||||
}
|
||||
|
||||
func (msg BondMsg) ValidateBasic() sdk.Error {
|
||||
if msg.Stake.IsZero() {
|
||||
return ErrEmptyStake()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg BondMsg) Get(key interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg BondMsg) GetSignBytes() []byte {
|
||||
bz, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
}
|
||||
|
||||
func (msg BondMsg) GetSigners() []sdk.Address {
|
||||
return []sdk.Address{msg.Address}
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// UnbondMsg
|
||||
|
||||
type UnbondMsg struct {
|
||||
Address sdk.Address `json:"address"`
|
||||
}
|
||||
|
||||
func NewUnbondMsg(addr sdk.Address) UnbondMsg {
|
||||
return UnbondMsg{
|
||||
Address: addr,
|
||||
}
|
||||
}
|
||||
|
||||
func (msg UnbondMsg) Type() string {
|
||||
return "staking"
|
||||
}
|
||||
|
||||
func (msg UnbondMsg) ValidateBasic() sdk.Error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg UnbondMsg) Get(key interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg UnbondMsg) GetSignBytes() []byte {
|
||||
bz, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
}
|
||||
|
||||
func (msg UnbondMsg) GetSigners() []sdk.Address {
|
||||
return []sdk.Address{msg.Address}
|
||||
}
|
||||
31
x/staking/types_test.go
Normal file
31
x/staking/types_test.go
Normal file
@ -0,0 +1,31 @@
|
||||
package staking
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func TestBondMsgValidation(t *testing.T) {
|
||||
privKey := crypto.GenPrivKeyEd25519()
|
||||
cases := []struct {
|
||||
valid bool
|
||||
bondMsg BondMsg
|
||||
}{
|
||||
{true, NewBondMsg(sdk.Address{}, sdk.Coin{"mycoin", 5}, privKey.PubKey())},
|
||||
{false, NewBondMsg(sdk.Address{}, sdk.Coin{"mycoin", 0}, privKey.PubKey())},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
err := tc.bondMsg.ValidateBasic()
|
||||
if tc.valid {
|
||||
assert.Nil(t, err, "%d: %+v", i, err)
|
||||
} else {
|
||||
assert.NotNil(t, err, "%d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user