cleanup, move simplestaking to democoin

This commit is contained in:
rigelrozanski
2018-04-26 22:59:30 -04:00
parent 2021ee1c77
commit 260ab69e4f
23 changed files with 155 additions and 181 deletions
+10 -44
View File
@@ -12,11 +12,11 @@ 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/simplestake"
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/pow"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/simplestake"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/sketchy"
)
@@ -38,9 +38,6 @@ type DemocoinApp struct {
// Manage getting and setting accounts
accountMapper sdk.AccountMapper
// Handle fees
feeHandler sdk.FeeHandler
}
func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
@@ -50,7 +47,7 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
// Create your application object.
var app = &DemocoinApp{
BaseApp: bam.NewBaseApp(appName, logger, db),
BaseApp: bam.NewBaseApp(appName, cdc, logger, db),
cdc: cdc,
capKeyMainStore: sdk.NewKVStoreKey("main"),
capKeyAccountStore: sdk.NewKVStoreKey("acc"),
@@ -80,65 +77,34 @@ func NewDemocoinApp(logger log.Logger, db dbm.DB) *DemocoinApp {
AddRoute("ibc", ibc.NewHandler(ibcMapper, coinKeeper)).
AddRoute("simplestake", simplestake.NewHandler(stakeKeeper))
// Define the feeHandler.
app.feeHandler = auth.BurnFeeHandler
// Initialize BaseApp.
app.SetTxDecoder(app.txDecoder)
app.SetInitChainer(app.initChainerFn(coolKeeper, powKeeper))
app.MountStoresIAVL(app.capKeyMainStore, app.capKeyAccountStore, app.capKeyPowStore, app.capKeyIBCStore, app.capKeyStakingStore)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeHandler))
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.BurnFeeHandler))
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)
cdc.RegisterConcrete(bank.MsgSend{}, "democoin/Send", nil)
cdc.RegisterConcrete(bank.MsgIssue{}, "democoin/Issue", nil)
cdc.RegisterConcrete(cool.MsgQuiz{}, "democoin/Quiz", nil)
cdc.RegisterConcrete(cool.MsgSetTrend{}, "democoin/SetTrend", nil)
cdc.RegisterConcrete(pow.MsgMine{}, "democoin/Mine", nil)
cdc.RegisterConcrete(ibc.IBCTransferMsg{}, "democoin/IBCTransferMsg", nil)
cdc.RegisterConcrete(ibc.IBCReceiveMsg{}, "democoin/IBCReceiveMsg", nil)
cdc.RegisterConcrete(simplestake.MsgBond{}, "democoin/BondMsg", nil)
cdc.RegisterConcrete(simplestake.MsgUnbond{}, "democoin/UnbondMsg", nil)
wire.RegisterCrypto(cdc) // Register crypto.
sdk.RegisterWire(cdc) // Register Msgs
cool.RegisterWire(cdc)
pow.RegisterWire(cdc)
bank.RegisterWire(cdc)
ibc.RegisterWire(cdc)
simplestake.RegisterWire(cdc)
// Register AppAccount
cdc.RegisterInterface((*sdk.Account)(nil), nil)
cdc.RegisterConcrete(&types.AppAccount{}, "democoin/Account", nil)
// Register crypto.
wire.RegisterCrypto(cdc)
return cdc
}
// custom logic for transaction decoding
func (app *DemocoinApp) 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 in bank.RegisterWire.
err := app.cdc.UnmarshalBinary(txBytes, &tx)
if err != nil {
return nil, sdk.ErrTxDecode("").Trace(err.Error())
}
return tx, nil
}
// custom logic for democoin initialization
func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keeper) sdk.InitChainer {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
+1 -1
View File
@@ -17,12 +17,12 @@ import (
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
ibccmd "github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
simplestakingcmd "github.com/cosmos/cosmos-sdk/x/simplestake/client/cli"
"github.com/cosmos/cosmos-sdk/examples/democoin/app"
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
coolcmd "github.com/cosmos/cosmos-sdk/examples/democoin/x/cool/client/cli"
powcmd "github.com/cosmos/cosmos-sdk/examples/democoin/x/pow/client/cli"
simplestakingcmd "github.com/cosmos/cosmos-sdk/examples/democoin/x/simplestake/client/cli"
)
// rootCmd is the entry point for this binary
+11
View File
@@ -0,0 +1,11 @@
package cool
import (
"github.com/cosmos/cosmos-sdk/wire"
)
// Register concrete types on wire codec
func RegisterWire(cdc *wire.Codec) {
cdc.RegisterConcrete(MsgQuiz{}, "cool/Quiz", nil)
cdc.RegisterConcrete(MsgSetTrend{}, "cool/SetTrend", nil)
}
+10
View File
@@ -0,0 +1,10 @@
package pow
import (
"github.com/cosmos/cosmos-sdk/wire"
)
// Register concrete types on wire codec
func RegisterWire(cdc *wire.Codec) {
cdc.RegisterConcrete(MsgMine{}, "pow/Mine", nil)
}
@@ -0,0 +1,97 @@
package cli
import (
"encoding/hex"
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
crypto "github.com/tendermint/go-crypto"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/examples/democoin/x/simplestake"
)
const (
flagStake = "stake"
flagValidator = "validator"
)
// simple bond tx
func BondTxCmd(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "bond",
Short: "Bond to a validator",
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.NewCoreContextFromViper()
from, err := ctx.GetFromAddress()
if err != nil {
return err
}
stakeString := viper.GetString(flagStake)
if len(stakeString) == 0 {
return fmt.Errorf("specify coins to bond with --stake")
}
valString := viper.GetString(flagValidator)
if len(valString) == 0 {
return fmt.Errorf("specify pubkey to bond to with --validator")
}
stake, err := sdk.ParseCoin(stakeString)
if err != nil {
return err
}
// TODO: bech32 ...
rawPubKey, err := hex.DecodeString(valString)
if err != nil {
return err
}
var pubKeyEd crypto.PubKeyEd25519
copy(pubKeyEd[:], rawPubKey)
msg := simplestake.NewMsgBond(from, stake, pubKeyEd)
return sendMsg(cdc, msg)
},
}
cmd.Flags().String(flagStake, "", "Amount of coins to stake")
cmd.Flags().String(flagValidator, "", "Validator address to stake")
return cmd
}
// simple unbond tx
func UnbondTxCmd(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "unbond",
Short: "Unbond from a validator",
RunE: func(cmd *cobra.Command, args []string) error {
from, err := context.NewCoreContextFromViper().GetFromAddress()
if err != nil {
return err
}
msg := simplestake.NewMsgUnbond(from)
return sendMsg(cdc, msg)
},
}
return cmd
}
func sendMsg(cdc *wire.Codec, msg sdk.Msg) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, msg, cdc)
if err != nil {
return err
}
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil
}
+37
View File
@@ -0,0 +1,37 @@
package simplestake
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// simple stake errors reserve 300 ~ 399.
const (
DefaultCodespace sdk.CodespaceType = 4
// simplestake errors reserve 300 - 399.
CodeEmptyValidator sdk.CodeType = 300
CodeInvalidUnbond sdk.CodeType = 301
CodeEmptyStake sdk.CodeType = 302
CodeIncorrectStakingToken sdk.CodeType = 303
)
// nolint
func ErrIncorrectStakingToken(codespace sdk.CodespaceType) sdk.Error {
return newError(codespace, CodeIncorrectStakingToken, "")
}
func ErrEmptyValidator(codespace sdk.CodespaceType) sdk.Error {
return newError(codespace, CodeEmptyValidator, "")
}
func ErrInvalidUnbond(codespace sdk.CodespaceType) sdk.Error {
return newError(codespace, CodeInvalidUnbond, "")
}
func ErrEmptyStake(codespace sdk.CodespaceType) sdk.Error {
return newError(codespace, CodeEmptyStake, "")
}
// -----------------------------
// Helpers
func newError(codespace sdk.CodespaceType, code sdk.CodeType, msg string) sdk.Error {
return sdk.NewError(codespace, code, msg)
}
@@ -0,0 +1,55 @@
package simplestake
import (
abci "github.com/tendermint/abci/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// NewHandler returns a handler for "simplestake" type messages.
func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case MsgBond:
return handleMsgBond(ctx, k, msg)
case MsgUnbond:
return handleMsgUnbond(ctx, k, msg)
default:
return sdk.ErrUnknownRequest("No match for message type.").Result()
}
}
}
func handleMsgBond(ctx sdk.Context, k Keeper, msg MsgBond) sdk.Result {
power, err := k.Bond(ctx, msg.Address, msg.PubKey, msg.Stake)
if err != nil {
return err.Result()
}
valSet := abci.Validator{
PubKey: msg.PubKey.Bytes(),
Power: power,
}
return sdk.Result{
Code: sdk.ABCICodeOK,
ValidatorUpdates: abci.Validators{valSet},
}
}
func handleMsgUnbond(ctx sdk.Context, k Keeper, msg MsgUnbond) sdk.Result {
pubKey, _, err := k.Unbond(ctx, msg.Address)
if err != nil {
return err.Result()
}
valSet := abci.Validator{
PubKey: pubKey.Bytes(),
Power: int64(0),
}
return sdk.Result{
Code: sdk.ABCICodeOK,
ValidatorUpdates: abci.Validators{valSet},
}
}
+135
View File
@@ -0,0 +1,135 @@
package simplestake
import (
crypto "github.com/tendermint/go-crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/bank"
)
const stakingToken = "steak"
const moduleName = "simplestake"
// simple stake keeper
type Keeper struct {
ck bank.Keeper
key sdk.StoreKey
cdc *wire.Codec
codespace sdk.CodespaceType
}
func NewKeeper(key sdk.StoreKey, coinKeeper bank.Keeper, codespace sdk.CodespaceType) Keeper {
cdc := wire.NewCodec()
wire.RegisterCrypto(cdc)
return Keeper{
key: key,
cdc: cdc,
ck: coinKeeper,
codespace: codespace,
}
}
func (k Keeper) getBondInfo(ctx sdk.Context, addr sdk.Address) bondInfo {
store := ctx.KVStore(k.key)
bz := store.Get(addr)
if bz == nil {
return bondInfo{}
}
var bi bondInfo
err := k.cdc.UnmarshalBinary(bz, &bi)
if err != nil {
panic(err)
}
return bi
}
func (k Keeper) setBondInfo(ctx sdk.Context, addr sdk.Address, bi bondInfo) {
store := ctx.KVStore(k.key)
bz, err := k.cdc.MarshalBinary(bi)
if err != nil {
panic(err)
}
store.Set(addr, bz)
}
func (k Keeper) deleteBondInfo(ctx sdk.Context, addr sdk.Address) {
store := ctx.KVStore(k.key)
store.Delete(addr)
}
// register a bond with the keeper
func (k Keeper) Bond(ctx sdk.Context, addr sdk.Address, pubKey crypto.PubKey, stake sdk.Coin) (int64, sdk.Error) {
if stake.Denom != stakingToken {
return 0, ErrIncorrectStakingToken(k.codespace)
}
_, err := k.ck.SubtractCoins(ctx, addr, []sdk.Coin{stake})
if err != nil {
return 0, err
}
bi := k.getBondInfo(ctx, addr)
if bi.isEmpty() {
bi = bondInfo{
PubKey: pubKey,
Power: 0,
}
}
bi.Power = bi.Power + stake.Amount
k.setBondInfo(ctx, addr, bi)
return bi.Power, nil
}
// register an unbond with the keeper
func (k Keeper) Unbond(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, int64, sdk.Error) {
bi := k.getBondInfo(ctx, addr)
if bi.isEmpty() {
return nil, 0, ErrInvalidUnbond(k.codespace)
}
k.deleteBondInfo(ctx, addr)
returnedBond := sdk.Coin{stakingToken, bi.Power}
_, err := k.ck.AddCoins(ctx, addr, []sdk.Coin{returnedBond})
if err != nil {
return bi.PubKey, bi.Power, err
}
return bi.PubKey, bi.Power, nil
}
// FOR TESTING PURPOSES -------------------------------------------------
func (k Keeper) bondWithoutCoins(ctx sdk.Context, addr sdk.Address, pubKey crypto.PubKey, stake sdk.Coin) (int64, sdk.Error) {
if stake.Denom != stakingToken {
return 0, ErrIncorrectStakingToken(k.codespace)
}
bi := k.getBondInfo(ctx, addr)
if bi.isEmpty() {
bi = bondInfo{
PubKey: pubKey,
Power: 0,
}
}
bi.Power = bi.Power + stake.Amount
k.setBondInfo(ctx, addr, bi)
return bi.Power, nil
}
func (k Keeper) unbondWithoutCoins(ctx sdk.Context, addr sdk.Address) (crypto.PubKey, int64, sdk.Error) {
bi := k.getBondInfo(ctx, addr)
if bi.isEmpty() {
return nil, 0, ErrInvalidUnbond(k.codespace)
}
k.deleteBondInfo(ctx, addr)
return bi.PubKey, bi.Power, nil
}
@@ -0,0 +1,86 @@
package simplestake
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"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
)
func setupMultiStore() (sdk.MultiStore, *sdk.KVStoreKey, *sdk.KVStoreKey) {
db := dbm.NewMemDB()
authKey := sdk.NewKVStoreKey("authkey")
capKey := sdk.NewKVStoreKey("capkey")
ms := store.NewCommitMultiStore(db)
ms.MountStoreWithDB(capKey, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(authKey, sdk.StoreTypeIAVL, db)
ms.LoadLatestVersion()
return ms, authKey, capKey
}
func TestKeeperGetSet(t *testing.T) {
ms, _, capKey := setupMultiStore()
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
stakeKeeper := NewKeeper(capKey, bank.NewKeeper(nil), DefaultCodespace)
addr := sdk.Address([]byte("some-address"))
bi := stakeKeeper.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())
stakeKeeper.setBondInfo(ctx, addr, bi)
savedBi := stakeKeeper.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, authKey, capKey := setupMultiStore()
cdc := wire.NewCodec()
auth.RegisterBaseAccount(cdc)
ctx := sdk.NewContext(ms, abci.Header{}, false, nil)
accountMapper := auth.NewAccountMapper(cdc, authKey, &auth.BaseAccount{})
coinKeeper := bank.NewKeeper(accountMapper)
stakeKeeper := NewKeeper(capKey, coinKeeper, DefaultCodespace)
addr := sdk.Address([]byte("some-address"))
privKey := crypto.GenPrivKeyEd25519()
pubKey := privKey.PubKey()
_, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr)
assert.Equal(t, err, ErrInvalidUnbond(DefaultCodespace))
_, err = stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.Coin{"steak", 10})
assert.Nil(t, err)
power, err := stakeKeeper.bondWithoutCoins(ctx, addr, pubKey, sdk.Coin{"steak", 10})
assert.Equal(t, int64(20), power)
pk, _, err := stakeKeeper.unbondWithoutCoins(ctx, addr)
assert.Nil(t, err)
assert.Equal(t, pubKey, pk)
_, _, err = stakeKeeper.unbondWithoutCoins(ctx, addr)
assert.Equal(t, err, ErrInvalidUnbond(DefaultCodespace))
}
+81
View File
@@ -0,0 +1,81 @@
package simplestake
import (
"encoding/json"
crypto "github.com/tendermint/go-crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
)
//_________________________________________________________----
// simple bond message
type MsgBond struct {
Address sdk.Address `json:"address"`
Stake sdk.Coin `json:"coins"`
PubKey crypto.PubKey `json:"pub_key"`
}
func NewMsgBond(addr sdk.Address, stake sdk.Coin, pubKey crypto.PubKey) MsgBond {
return MsgBond{
Address: addr,
Stake: stake,
PubKey: pubKey,
}
}
//nolint
func (msg MsgBond) Type() string { return moduleName } //TODO update "stake/declarecandidacy"
func (msg MsgBond) Get(key interface{}) (value interface{}) { return nil }
func (msg MsgBond) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} }
// basic validation of the bond message
func (msg MsgBond) ValidateBasic() sdk.Error {
if msg.Stake.IsZero() {
return ErrEmptyStake(DefaultCodespace)
}
if msg.PubKey == nil {
return sdk.ErrInvalidPubKey("MsgBond.PubKey must not be empty")
}
return nil
}
// get bond message sign bytes
func (msg MsgBond) GetSignBytes() []byte {
bz, err := json.Marshal(msg)
if err != nil {
panic(err)
}
return bz
}
//_______________________________________________________________
// simple unbond message
type MsgUnbond struct {
Address sdk.Address `json:"address"`
}
func NewMsgUnbond(addr sdk.Address) MsgUnbond {
return MsgUnbond{
Address: addr,
}
}
//nolint
func (msg MsgUnbond) Type() string { return moduleName } //TODO update "stake/declarecandidacy"
func (msg MsgUnbond) Get(key interface{}) (value interface{}) { return nil }
func (msg MsgUnbond) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} }
func (msg MsgUnbond) ValidateBasic() sdk.Error { return nil }
// get unbond message sign bytes
func (msg MsgUnbond) GetSignBytes() []byte {
bz, err := json.Marshal(msg)
if err != nil {
panic(err)
}
return bz
}
@@ -0,0 +1,31 @@
package simplestake
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
msgBond MsgBond
}{
{true, NewMsgBond(sdk.Address{}, sdk.Coin{"mycoin", 5}, privKey.PubKey())},
{false, NewMsgBond(sdk.Address{}, sdk.Coin{"mycoin", 0}, privKey.PubKey())},
}
for i, tc := range cases {
err := tc.msgBond.ValidateBasic()
if tc.valid {
assert.Nil(t, err, "%d: %+v", i, err)
} else {
assert.NotNil(t, err, "%d", i)
}
}
}
+15
View File
@@ -0,0 +1,15 @@
package simplestake
import crypto "github.com/tendermint/go-crypto"
type bondInfo struct {
PubKey crypto.PubKey
Power int64
}
func (bi bondInfo) isEmpty() bool {
if bi == (bondInfo{}) {
return true
}
return false
}
+11
View File
@@ -0,0 +1,11 @@
package simplestake
import (
"github.com/cosmos/cosmos-sdk/wire"
)
// Register concrete types on wire codec
func RegisterWire(cdc *wire.Codec) {
cdc.RegisterConcrete(MsgBond{}, "simplestake/BondMsg", nil)
cdc.RegisterConcrete(MsgUnbond{}, "simplestake/UnbondMsg", nil)
}