Merge remote-tracking branch 'origin/develop' into rigel/a-validator-on-a-cliff

This commit is contained in:
rigelrozanski 2018-07-06 18:04:49 -04:00
commit 2bf0b842fa
109 changed files with 2690 additions and 1369 deletions

7
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,7 @@
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
# Primary repo maintainers
* @ebuchman @rigelrozanski @cwgoes
# Precious documentation
/docs/ @zramsay @jolesbi

View File

@ -5,6 +5,7 @@
*TBD* *TBD*
BREAKING CHANGES BREAKING CHANGES
* msg.GetSignBytes() returns sorted JSON (by key)
* Update Tendermint to v0.22.0 * Update Tendermint to v0.22.0
* Default ports changed from 466xx to 266xx * Default ports changed from 466xx to 266xx
* Amino JSON uses type names instead of prefix bytes * Amino JSON uses type names instead of prefix bytes
@ -36,7 +37,13 @@ BREAKING CHANGES
to an infraction, slash them proportional to their stake at the time to an infraction, slash them proportional to their stake at the time
* Add REST endpoint to unrevoke a validator previously revoked for downtime * Add REST endpoint to unrevoke a validator previously revoked for downtime
* Add REST endpoint to retrieve liveness signing information for a validator * Add REST endpoint to retrieve liveness signing information for a validator
* [types] renamed rational.Evaluate to rational.Round{Int64, Int}
* [x/stake] most index keys nolonger hold a value - inputs are rearranged to form the desired key
* [lcd] Switch key creation output to return bech32 * [lcd] Switch key creation output to return bech32
* [x/stake] store-value for delegation, validator, ubd, and red do not hold duplicate information contained store-key
DEPRECATED
* [cli] Deprecate `--name` flag in commands that send txs, in favor of `--from`
FEATURES FEATURES
* [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag * [gaiacli] You can now attach a simple text-only memo to any transaction, with the `--memo` flag
@ -67,7 +74,13 @@ FEATURES
* [gaiacli] Ledger support added * [gaiacli] Ledger support added
- You can now use a Ledger with `gaiacli --ledger` for all key-related commands - You can now use a Ledger with `gaiacli --ledger` for all key-related commands
- Ledger keys can be named and tracked locally in the key DB - Ledger keys can be named and tracked locally in the key DB
* [gaiacli] added an --async flag to the cli to deliver transactions without waiting for a tendermint response * [testing] created a randomized testing framework.
- Currently bank has limited functionality in the framework
- Auth has its invariants checked within the framework
* [gaiacli] added the following flags for commands that post transactions to the chain:
* async -- send the tx without waiting for a tendermint response
* json -- return the output in json format for increased readability
* print-response -- return the tx response. (includes fields like gas cost)
IMPROVEMENTS IMPROVEMENTS
* bank module uses go-wire codec instead of 'encoding/json' * bank module uses go-wire codec instead of 'encoding/json'
@ -76,12 +89,15 @@ IMPROVEMENTS
* [stake] module reorganized to include `types` and `keeper` package * [stake] module reorganized to include `types` and `keeper` package
* [stake] keeper always loads the store (instead passing around which doesn't really boost efficiency) * [stake] keeper always loads the store (instead passing around which doesn't really boost efficiency)
* [stake] edit-validator changes now can use the keyword [do-not-modify] to not modify unspecified `--flag` (aka won't set them to `""` value) * [stake] edit-validator changes now can use the keyword [do-not-modify] to not modify unspecified `--flag` (aka won't set them to `""` value)
* [types] added common tag constants
* [stake] offload more generic functionality from the handler into the keeper * [stake] offload more generic functionality from the handler into the keeper
* [types] added common tag constants
* [keys] improve error message when deleting non-existent key
* [gaiacli] improve error messages on `send` and `account` commands
* added contributing guidelines * added contributing guidelines
BUG FIXES BUG FIXES
* [x/slashing] \#1510 Unrevoked validators cannot un-revoke themselves * [x/slashing] \#1510 Unrevoked validators cannot un-revoke themselves
* [x/stake] \#1567 Validators decreased in power but not unbonded are now updated in Tendermint
* [gaia] Added self delegation for validators in the genesis creation * [gaia] Added self delegation for validators in the genesis creation
* [lcd] tests now don't depend on raw json text * [lcd] tests now don't depend on raw json text
* [stake] error strings lower case * [stake] error strings lower case
@ -96,6 +112,8 @@ BUG FIXES
* \#1353 - CLI: Show pool shares fractions in human-readable format * \#1353 - CLI: Show pool shares fractions in human-readable format
* \#1258 - printing big.rat's can no longer overflow int64 * \#1258 - printing big.rat's can no longer overflow int64
* \#887 - limit the size of rationals that can be passed in from user input * \#887 - limit the size of rationals that can be passed in from user input
* \#1461 - CLI tests now no longer reset your local environment data
* \#1505 - `gaiacli stake validator` no longer panics if validator doesn't exist
## 0.19.0 ## 0.19.0

7
Gopkg.lock generated
View File

@ -137,6 +137,7 @@
".", ".",
"hcl/ast", "hcl/ast",
"hcl/parser", "hcl/parser",
"hcl/printer",
"hcl/scanner", "hcl/scanner",
"hcl/strconv", "hcl/strconv",
"hcl/token", "hcl/token",
@ -240,7 +241,7 @@
"nfs", "nfs",
"xfs" "xfs"
] ]
revision = "40f013a808ec4fa79def444a1a56de4d1727efcb" revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a"
[[projects]] [[projects]]
branch = "master" branch = "master"
@ -433,13 +434,13 @@
"netutil", "netutil",
"trace" "trace"
] ]
revision = "87b3feba568e144938625fc5d80ec92566c1a8fe" revision = "ed29d75add3d7c4bf7ca65aac0c6df3d1420216f"
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "golang.org/x/sys" name = "golang.org/x/sys"
packages = ["unix"] packages = ["unix"]
revision = "7138fd3d9dc8335c567ca206f4333fb75eb05d56" revision = "151529c776cdc58ddbe7963ba9af779f3577b419"
[[projects]] [[projects]]
name = "golang.org/x/text" name = "golang.org/x/text"

View File

@ -1,7 +1,6 @@
package baseapp package baseapp
import ( import (
"encoding/json"
"fmt" "fmt"
"os" "os"
"testing" "testing"
@ -19,7 +18,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
) )
func defaultLogger() log.Logger { func defaultLogger() log.Logger {
@ -651,323 +649,6 @@ func TestValidatorChange(t *testing.T) {
//---------------------------------------- //----------------------------------------
// Use burn and send msg types to test multiple msgs in one tx
type testBurnMsg struct {
Addr sdk.Address
Amount sdk.Coins
}
const msgType3 = "burn"
func (msg testBurnMsg) Type() string { return msgType3 }
func (msg testBurnMsg) GetSignBytes() []byte {
bz, _ := json.Marshal(msg)
return bz
}
func (msg testBurnMsg) ValidateBasic() sdk.Error {
if msg.Addr == nil {
return sdk.ErrInvalidAddress("Cannot use nil as Address")
}
return nil
}
func (msg testBurnMsg) GetSigners() []sdk.Address {
return []sdk.Address{msg.Addr}
}
type testSendMsg struct {
Sender sdk.Address
Receiver sdk.Address
Amount sdk.Coins
}
const msgType4 = "send"
func (msg testSendMsg) Type() string { return msgType4 }
func (msg testSendMsg) GetSignBytes() []byte {
bz, _ := json.Marshal(msg)
return bz
}
func (msg testSendMsg) ValidateBasic() sdk.Error {
if msg.Sender == nil || msg.Receiver == nil {
return sdk.ErrInvalidAddress("Cannot use nil as Address")
}
return nil
}
func (msg testSendMsg) GetSigners() []sdk.Address {
return []sdk.Address{msg.Sender}
}
// Simple Handlers for burn and send
func newHandleBurn(keeper bank.Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
burnMsg := msg.(testBurnMsg)
_, _, err := keeper.SubtractCoins(ctx, burnMsg.Addr, burnMsg.Amount)
if err != nil {
return err.Result()
}
return sdk.Result{}
}
}
func newHandleSpend(keeper bank.Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
spendMsg := msg.(testSendMsg)
_, _, err := keeper.SubtractCoins(ctx, spendMsg.Sender, spendMsg.Amount)
if err != nil {
return err.Result()
}
_, _, err = keeper.AddCoins(ctx, spendMsg.Receiver, spendMsg.Amount)
if err != nil {
return err.Result()
}
return sdk.Result{}
}
}
// generate a signed transaction
func GenTx(chainID string, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx {
// make the transaction free
fee := auth.StdFee{
sdk.Coins{{"foocoin", sdk.NewInt(0)}},
100000,
}
sigs := make([]auth.StdSignature, len(priv))
for i, p := range priv {
sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, ""))
// TODO: replace with proper error handling:
if err != nil {
panic(err)
}
sigs[i] = auth.StdSignature{
PubKey: p.PubKey(),
Signature: sig,
AccountNumber: accnums[i],
Sequence: seq[i],
}
}
return auth.NewStdTx(msgs, fee, sigs, "")
}
// spin up simple app for testing
type testApp struct {
*BaseApp
accountMapper auth.AccountMapper
accountKeeper bank.Keeper
}
func newTestApp(name string) testApp {
return testApp{
BaseApp: newBaseApp(name),
}
}
func MakeCodec() *wire.Codec {
cdc := wire.NewCodec()
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
crypto.RegisterAmino(cdc)
cdc.RegisterInterface((*auth.Account)(nil), nil)
cdc.RegisterConcrete(&auth.BaseAccount{}, "cosmos-sdk/BaseAccount", nil)
return cdc
}
// tests multiple msgs of same type from same address in single tx
func TestMultipleBurn(t *testing.T) {
// Create app.
app := newTestApp(t.Name())
capKey := sdk.NewKVStoreKey("key")
app.MountStoresIAVL(capKey)
app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx auth.StdTx
fromJSON(txBytes, &tx)
return tx, nil
})
err := app.LoadLatestVersion(capKey)
if err != nil {
panic(err)
}
app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{})
app.accountKeeper = bank.NewKeeper(app.accountMapper)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{}))
app.Router().
AddRoute("burn", newHandleBurn(app.accountKeeper)).
AddRoute("send", newHandleSpend(app.accountKeeper))
app.InitChain(abci.RequestInitChain{})
app.BeginBlock(abci.RequestBeginBlock{})
// Set chain-id
app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name())
priv := makePrivKey("my secret")
addr := priv.PubKey().Address()
app.accountKeeper.AddCoins(app.deliverState.ctx, addr, sdk.Coins{{"foocoin", sdk.NewInt(100)}})
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr), "Balance did not update")
msg := testBurnMsg{addr, sdk.Coins{{"foocoin", sdk.NewInt(50)}}}
tx := GenTx(t.Name(), []sdk.Msg{msg, msg}, []int64{0}, []int64{0}, priv)
res := app.Deliver(tx)
require.Equal(t, true, res.IsOK(), res.Log)
require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr), "Double burn did not work")
}
// tests multiples msgs of same type from different addresses in single tx
func TestBurnMultipleOwners(t *testing.T) {
// Create app.
app := newTestApp(t.Name())
capKey := sdk.NewKVStoreKey("key")
app.MountStoresIAVL(capKey)
app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx auth.StdTx
fromJSON(txBytes, &tx)
return tx, nil
})
err := app.LoadLatestVersion(capKey)
if err != nil {
panic(err)
}
app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{})
app.accountKeeper = bank.NewKeeper(app.accountMapper)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{}))
app.Router().
AddRoute("burn", newHandleBurn(app.accountKeeper)).
AddRoute("send", newHandleSpend(app.accountKeeper))
app.InitChain(abci.RequestInitChain{})
app.BeginBlock(abci.RequestBeginBlock{})
// Set chain-id
app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name())
priv1 := makePrivKey("my secret 1")
addr1 := priv1.PubKey().Address()
priv2 := makePrivKey("my secret 2")
addr2 := priv2.PubKey().Address()
// fund accounts
app.accountKeeper.AddCoins(app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}})
app.accountKeeper.AddCoins(app.deliverState.ctx, addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}})
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not update")
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not update")
msg1 := testBurnMsg{addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}}
msg2 := testBurnMsg{addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}}}
// test wrong signers: Address 1 signs both messages
tx := GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 0}, []int64{0, 0}, priv1, priv1)
res := app.Deliver(tx)
require.Equal(t, sdk.ABCICodeType(0x10003), res.Code, "Wrong signatures passed")
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 changed after invalid sig")
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 changed after invalid sig")
// test valid tx
tx = GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 1}, []int64{1, 0}, priv1, priv2)
res = app.Deliver(tx)
require.Equal(t, true, res.IsOK(), res.Log)
require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not change after valid tx")
require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not change after valid tx")
}
// tests different msg types in single tx with different addresses
func TestSendBurn(t *testing.T) {
// Create app.
app := newTestApp(t.Name())
capKey := sdk.NewKVStoreKey("key")
app.MountStoresIAVL(capKey)
app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx auth.StdTx
fromJSON(txBytes, &tx)
return tx, nil
})
err := app.LoadLatestVersion(capKey)
if err != nil {
panic(err)
}
app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{})
app.accountKeeper = bank.NewKeeper(app.accountMapper)
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{}))
app.Router().
AddRoute("burn", newHandleBurn(app.accountKeeper)).
AddRoute("send", newHandleSpend(app.accountKeeper))
app.InitChain(abci.RequestInitChain{})
app.BeginBlock(abci.RequestBeginBlock{})
// Set chain-id
app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name())
priv1 := makePrivKey("my secret 1")
addr1 := priv1.PubKey().Address()
priv2 := makePrivKey("my secret 2")
addr2 := priv2.PubKey().Address()
// fund accounts
app.accountKeeper.AddCoins(app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}})
acc := app.accountMapper.NewAccountWithAddress(app.deliverState.ctx, addr2)
app.accountMapper.SetAccount(app.deliverState.ctx, acc)
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not update")
sendMsg := testSendMsg{addr1, addr2, sdk.Coins{{"foocoin", sdk.NewInt(50)}}}
msg1 := testBurnMsg{addr1, sdk.Coins{{"foocoin", sdk.NewInt(50)}}}
msg2 := testBurnMsg{addr2, sdk.Coins{{"foocoin", sdk.NewInt(50)}}}
// send then burn
tx := GenTx(t.Name(), []sdk.Msg{sendMsg, msg2, msg1}, []int64{0, 1}, []int64{0, 0}, priv1, priv2)
res := app.Deliver(tx)
require.Equal(t, true, res.IsOK(), res.Log)
require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Balance1 did not change after valid tx")
require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 did not change after valid tx")
// Check that state is only updated if all msgs in tx pass.
app.accountKeeper.AddCoins(app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(50)}})
// burn then send
tx = GenTx(t.Name(), []sdk.Msg{msg1, sendMsg}, []int64{0}, []int64{1}, priv1)
res = app.Deliver(tx)
// Double check that state is correct after Commit.
app.EndBlock(abci.RequestEndBlock{})
app.Commit()
app.BeginBlock(abci.RequestBeginBlock{})
app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name())
require.Equal(t, sdk.ABCICodeType(0x1000a), res.Code, "Allowed tx to pass with insufficient funds")
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(50)}}, app.accountKeeper.GetCoins(app.deliverState.ctx, addr1), "Allowed valid msg to pass in invalid tx")
require.Equal(t, sdk.Coins(nil), app.accountKeeper.GetCoins(app.deliverState.ctx, addr2), "Balance2 changed after invalid tx")
}
//----------------------------------------
func randPower() int64 { func randPower() int64 {
return cmn.RandInt64() return cmn.RandInt64()
} }

352
baseapp/multimsg_test.go Normal file
View File

@ -0,0 +1,352 @@
package baseapp
import (
"encoding/json"
"fmt"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
)
// tests multiple msgs of same type from same address in single tx
func TestMultipleBurn(t *testing.T) {
// Create app.
app := newTestApp(t.Name())
capKey := sdk.NewKVStoreKey("key")
app.MountStoresIAVL(capKey)
app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx auth.StdTx
fromJSON(txBytes, &tx)
return tx, nil
})
err := app.LoadLatestVersion(capKey)
if err != nil {
panic(err)
}
app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{})
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{}))
app.Router().
AddRoute("burn", newHandleBurn(app.accountMapper)).
AddRoute("send", newHandleSpend(app.accountMapper))
app.InitChain(abci.RequestInitChain{})
app.BeginBlock(abci.RequestBeginBlock{})
// Set chain-id
app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name())
priv := makePrivKey("my secret")
addr := priv.PubKey().Address()
addCoins(app.accountMapper, app.deliverState.ctx, addr, sdk.Coins{{"foocoin", sdk.NewInt(100)}})
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, app.accountMapper.GetAccount(app.deliverState.ctx, addr).GetCoins(), "Balance did not update")
msg := testBurnMsg{addr, sdk.Coins{{"foocoin", sdk.NewInt(50)}}}
tx := GenTx(t.Name(), []sdk.Msg{msg, msg}, []int64{0}, []int64{0}, priv)
res := app.Deliver(tx)
require.Equal(t, true, res.IsOK(), res.Log)
require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr), "Double burn did not work")
}
// tests multiples msgs of same type from different addresses in single tx
func TestBurnMultipleOwners(t *testing.T) {
// Create app.
app := newTestApp(t.Name())
capKey := sdk.NewKVStoreKey("key")
app.MountStoresIAVL(capKey)
app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx auth.StdTx
fromJSON(txBytes, &tx)
return tx, nil
})
err := app.LoadLatestVersion(capKey)
if err != nil {
panic(err)
}
app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{})
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{}))
app.Router().
AddRoute("burn", newHandleBurn(app.accountMapper)).
AddRoute("send", newHandleSpend(app.accountMapper))
app.InitChain(abci.RequestInitChain{})
app.BeginBlock(abci.RequestBeginBlock{})
// Set chain-id
app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name())
priv1 := makePrivKey("my secret 1")
addr1 := priv1.PubKey().Address()
priv2 := makePrivKey("my secret 2")
addr2 := priv2.PubKey().Address()
// fund accounts
addCoins(app.accountMapper, app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}})
addCoins(app.accountMapper, app.deliverState.ctx, addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}})
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 did not update")
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 did not update")
msg1 := testBurnMsg{addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}}}
msg2 := testBurnMsg{addr2, sdk.Coins{{"foocoin", sdk.NewInt(100)}}}
// test wrong signers: Address 1 signs both messages
tx := GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 0}, []int64{0, 0}, priv1, priv1)
res := app.Deliver(tx)
require.Equal(t, sdk.ABCICodeType(0x10003), res.Code, "Wrong signatures passed")
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 changed after invalid sig")
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 changed after invalid sig")
// test valid tx
tx = GenTx(t.Name(), []sdk.Msg{msg1, msg2}, []int64{0, 1}, []int64{1, 0}, priv1, priv2)
res = app.Deliver(tx)
require.Equal(t, true, res.IsOK(), res.Log)
require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 did not change after valid tx")
require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 did not change after valid tx")
}
func getCoins(am auth.AccountMapper, ctx sdk.Context, addr sdk.Address) sdk.Coins {
return am.GetAccount(ctx, addr).GetCoins()
}
func addCoins(am auth.AccountMapper, ctx sdk.Context, addr sdk.Address, coins sdk.Coins) sdk.Error {
acc := am.GetAccount(ctx, addr)
if acc == nil {
acc = am.NewAccountWithAddress(ctx, addr)
}
err := acc.SetCoins(acc.GetCoins().Plus(coins))
if err != nil {
fmt.Println(err)
return sdk.ErrInternal(err.Error())
}
am.SetAccount(ctx, acc)
return nil
}
// tests different msg types in single tx with different addresses
func TestSendBurn(t *testing.T) {
// Create app.
app := newTestApp(t.Name())
capKey := sdk.NewKVStoreKey("key")
app.MountStoresIAVL(capKey)
app.SetTxDecoder(func(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx auth.StdTx
fromJSON(txBytes, &tx)
return tx, nil
})
err := app.LoadLatestVersion(capKey)
if err != nil {
panic(err)
}
app.accountMapper = auth.NewAccountMapper(app.cdc, capKey, &auth.BaseAccount{})
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, auth.FeeCollectionKeeper{}))
app.Router().
AddRoute("burn", newHandleBurn(app.accountMapper)).
AddRoute("send", newHandleSpend(app.accountMapper))
app.InitChain(abci.RequestInitChain{})
app.BeginBlock(abci.RequestBeginBlock{})
// Set chain-id
app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name())
priv1 := makePrivKey("my secret 1")
addr1 := priv1.PubKey().Address()
priv2 := makePrivKey("my secret 2")
addr2 := priv2.PubKey().Address()
// fund accounts
addCoins(app.accountMapper, app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(100)}})
acc := app.accountMapper.NewAccountWithAddress(app.deliverState.ctx, addr2)
app.accountMapper.SetAccount(app.deliverState.ctx, acc)
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(100)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 did not update")
sendMsg := testSendMsg{addr1, addr2, sdk.Coins{{"foocoin", sdk.NewInt(50)}}}
msg1 := testBurnMsg{addr1, sdk.Coins{{"foocoin", sdk.NewInt(50)}}}
msg2 := testBurnMsg{addr2, sdk.Coins{{"foocoin", sdk.NewInt(50)}}}
// send then burn
tx := GenTx(t.Name(), []sdk.Msg{sendMsg, msg2, msg1}, []int64{0, 1}, []int64{0, 0}, priv1, priv2)
res := app.Deliver(tx)
require.Equal(t, true, res.IsOK(), res.Log)
require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Balance1 did not change after valid tx")
require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 did not change after valid tx")
// Check that state is only updated if all msgs in tx pass.
addCoins(app.accountMapper, app.deliverState.ctx, addr1, sdk.Coins{{"foocoin", sdk.NewInt(50)}})
// burn then send, with fee thats greater than individual tx, but less than combination
tx = GenTxWithFeeAmt(50000, t.Name(), []sdk.Msg{msg1, sendMsg}, []int64{0}, []int64{1}, priv1)
res = app.Deliver(tx)
require.Equal(t, sdk.ABCICodeType(0x1000c), res.Code, "Allowed tx to pass with insufficient funds")
// Double check that state is correct after Commit.
app.EndBlock(abci.RequestEndBlock{})
app.Commit()
app.BeginBlock(abci.RequestBeginBlock{})
app.deliverState.ctx = app.deliverState.ctx.WithChainID(t.Name())
require.Equal(t, sdk.Coins{{"foocoin", sdk.NewInt(50)}}, getCoins(app.accountMapper, app.deliverState.ctx, addr1), "Allowed valid msg to pass in invalid tx")
require.Equal(t, sdk.Coins(nil), getCoins(app.accountMapper, app.deliverState.ctx, addr2), "Balance2 changed after invalid tx")
}
// Use burn and send msg types to test multiple msgs in one tx
type testBurnMsg struct {
Addr sdk.Address
Amount sdk.Coins
}
const msgType3 = "burn"
func (msg testBurnMsg) Type() string { return msgType3 }
func (msg testBurnMsg) GetSignBytes() []byte {
bz, _ := json.Marshal(msg)
return sdk.MustSortJSON(bz)
}
func (msg testBurnMsg) ValidateBasic() sdk.Error {
if msg.Addr == nil {
return sdk.ErrInvalidAddress("Cannot use nil as Address")
}
return nil
}
func (msg testBurnMsg) GetSigners() []sdk.Address {
return []sdk.Address{msg.Addr}
}
type testSendMsg struct {
Sender sdk.Address
Receiver sdk.Address
Amount sdk.Coins
}
const msgType4 = "send"
func (msg testSendMsg) Type() string { return msgType4 }
func (msg testSendMsg) GetSignBytes() []byte {
bz, _ := json.Marshal(msg)
return sdk.MustSortJSON(bz)
}
func (msg testSendMsg) ValidateBasic() sdk.Error {
if msg.Sender == nil || msg.Receiver == nil {
return sdk.ErrInvalidAddress("Cannot use nil as Address")
}
return nil
}
func (msg testSendMsg) GetSigners() []sdk.Address {
return []sdk.Address{msg.Sender}
}
// Simple Handlers for burn and send
func newHandleBurn(am auth.AccountMapper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
ctx.GasMeter().ConsumeGas(20000, "burning coins")
burnMsg := msg.(testBurnMsg)
err := addCoins(am, ctx, burnMsg.Addr, burnMsg.Amount.Negative())
if err != nil {
return err.Result()
}
return sdk.Result{}
}
}
func newHandleSpend(am auth.AccountMapper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
ctx.GasMeter().ConsumeGas(40000, "spending coins")
spendMsg := msg.(testSendMsg)
err := addCoins(am, ctx, spendMsg.Sender, spendMsg.Amount.Negative())
if err != nil {
return err.Result()
}
err = addCoins(am, ctx, spendMsg.Receiver, spendMsg.Amount)
if err != nil {
return err.Result()
}
return sdk.Result{}
}
}
// generate a signed transaction
func GenTx(chainID string, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx {
return GenTxWithFeeAmt(100000, chainID, msgs, accnums, seq, priv...)
}
// generate a signed transaction with the given fee amount
func GenTxWithFeeAmt(feeAmt int64, chainID string, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx {
// make the transaction free
fee := auth.StdFee{
sdk.Coins{{"foocoin", sdk.NewInt(0)}},
feeAmt,
}
sigs := make([]auth.StdSignature, len(priv))
for i, p := range priv {
sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, ""))
// TODO: replace with proper error handling:
if err != nil {
panic(err)
}
sigs[i] = auth.StdSignature{
PubKey: p.PubKey(),
Signature: sig,
AccountNumber: accnums[i],
Sequence: seq[i],
}
}
return auth.NewStdTx(msgs, fee, sigs, "")
}
// spin up simple app for testing
type testApp struct {
*BaseApp
accountMapper auth.AccountMapper
}
func newTestApp(name string) testApp {
return testApp{
BaseApp: newBaseApp(name),
}
}
func MakeCodec() *wire.Codec {
cdc := wire.NewCodec()
cdc.RegisterInterface((*sdk.Msg)(nil), nil)
crypto.RegisterAmino(cdc)
cdc.RegisterInterface((*auth.Account)(nil), nil)
cdc.RegisterConcrete(&auth.BaseAccount{}, "cosmos-sdk/BaseAccount", nil)
cdc.Seal()
return cdc
}

View File

@ -224,25 +224,58 @@ func (ctx CoreContext) ensureSignBuild(name string, msgs []sdk.Msg, cdc *wire.Co
} }
// sign and build the transaction from the msg // sign and build the transaction from the msg
func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTxCommit, err error) { func (ctx CoreContext) EnsureSignBuildBroadcast(name string, msgs []sdk.Msg, cdc *wire.Codec) (err error) {
txBytes, err := ctx.ensureSignBuild(name, msgs, cdc) txBytes, err := ctx.ensureSignBuild(name, msgs, cdc)
if err != nil { if err != nil {
return nil, err return err
} }
return ctx.BroadcastTx(txBytes) if ctx.Async {
} res, err := ctx.BroadcastTxAsync(txBytes)
// sign and build the async transaction from the msg
func (ctx CoreContext) EnsureSignBuildBroadcastAsync(name string, msgs []sdk.Msg, cdc *wire.Codec) (res *ctypes.ResultBroadcastTx, err error) {
txBytes, err := ctx.ensureSignBuild(name, msgs, cdc)
if err != nil { if err != nil {
return nil, err return err
} }
if ctx.JSON {
return ctx.BroadcastTxAsync(txBytes) type toJSON struct {
TxHash string
}
valueToJSON := toJSON{res.Hash.String()}
JSON, err := cdc.MarshalJSON(valueToJSON)
if err != nil {
return err
}
fmt.Println(string(JSON))
} else {
fmt.Println("Async tx sent. tx hash: ", res.Hash.String())
}
return nil
}
res, err := ctx.BroadcastTx(txBytes)
if err != nil {
return err
}
if ctx.JSON {
// Since JSON is intended for automated scripts, always include response in JSON mode
type toJSON struct {
Height int64
TxHash string
Response string
}
valueToJSON := toJSON{res.Height, res.Hash.String(), fmt.Sprintf("%+v", res.DeliverTx)}
JSON, err := cdc.MarshalJSON(valueToJSON)
if err != nil {
return err
}
fmt.Println(string(JSON))
return nil
}
if ctx.PrintResponse {
fmt.Printf("Committed at block %d. Hash: %s Response:%+v \n", res.Height, res.Hash.String(), res.DeliverTx)
} else {
fmt.Printf("Committed at block %d. Hash: %s \n", res.Height, res.Hash.String())
}
return nil
} }
// get the next sequence for the account address // get the next sequence for the account address

View File

@ -22,6 +22,9 @@ type CoreContext struct {
Decoder auth.AccountDecoder Decoder auth.AccountDecoder
AccountStore string AccountStore string
UseLedger bool UseLedger bool
Async bool
JSON bool
PrintResponse bool
} }
// WithChainID - return a copy of the context with an updated chainID // WithChainID - return a copy of the context with an updated chainID

View File

@ -27,13 +27,20 @@ func NewCoreContextFromViper() CoreContext {
chainID = def chainID = def
} }
} }
// TODO: Remove the following deprecation code after Gaia-7000 is launched
keyName := viper.GetString(client.FlagName)
if keyName != "" {
fmt.Println("** Note --name is deprecated and will be removed next release. Please use --from instead **")
} else {
keyName = viper.GetString(client.FlagFrom)
}
return CoreContext{ return CoreContext{
ChainID: chainID, ChainID: chainID,
Height: viper.GetInt64(client.FlagHeight), Height: viper.GetInt64(client.FlagHeight),
Gas: viper.GetInt64(client.FlagGas), Gas: viper.GetInt64(client.FlagGas),
Fee: viper.GetString(client.FlagFee), Fee: viper.GetString(client.FlagFee),
TrustNode: viper.GetBool(client.FlagTrustNode), TrustNode: viper.GetBool(client.FlagTrustNode),
FromAddressName: viper.GetString(client.FlagName), FromAddressName: keyName,
NodeURI: nodeURI, NodeURI: nodeURI,
AccountNumber: viper.GetInt64(client.FlagAccountNumber), AccountNumber: viper.GetInt64(client.FlagAccountNumber),
Sequence: viper.GetInt64(client.FlagSequence), Sequence: viper.GetInt64(client.FlagSequence),
@ -42,6 +49,9 @@ func NewCoreContextFromViper() CoreContext {
Decoder: nil, Decoder: nil,
AccountStore: "acc", AccountStore: "acc",
UseLedger: viper.GetBool(client.FlagUseLedger), UseLedger: viper.GetBool(client.FlagUseLedger),
Async: viper.GetBool(client.FlagAsync),
JSON: viper.GetBool(client.FlagJson),
PrintResponse: viper.GetBool(client.FlagPrintResponse),
} }
} }

View File

@ -10,11 +10,15 @@ const (
FlagHeight = "height" FlagHeight = "height"
FlagGas = "gas" FlagGas = "gas"
FlagTrustNode = "trust-node" FlagTrustNode = "trust-node"
FlagFrom = "from"
FlagName = "name" FlagName = "name"
FlagAccountNumber = "account-number" FlagAccountNumber = "account-number"
FlagSequence = "sequence" FlagSequence = "sequence"
FlagMemo = "memo" FlagMemo = "memo"
FlagFee = "fee" FlagFee = "fee"
FlagAsync = "async"
FlagJson = "json"
FlagPrintResponse = "print-response"
) )
// LineBreak can be included in a command list to provide a blank line // LineBreak can be included in a command list to provide a blank line
@ -37,7 +41,8 @@ func GetCommands(cmds ...*cobra.Command) []*cobra.Command {
// PostCommands adds common flags for commands to post tx // PostCommands adds common flags for commands to post tx
func PostCommands(cmds ...*cobra.Command) []*cobra.Command { func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
for _, c := range cmds { for _, c := range cmds {
c.Flags().String(FlagName, "", "Name of private key with which to sign") c.Flags().String(FlagFrom, "", "Name of private key with which to sign")
c.Flags().String(FlagName, "", "DEPRECATED - Name of private key with which to sign")
c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx") c.Flags().Int64(FlagAccountNumber, 0, "AccountNumber number to sign the tx")
c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx") c.Flags().Int64(FlagSequence, 0, "Sequence number to sign the tx")
c.Flags().String(FlagMemo, "", "Memo to send along with transaction") c.Flags().String(FlagMemo, "", "Memo to send along with transaction")
@ -46,6 +51,9 @@ func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain") c.Flags().String(FlagNode, "tcp://localhost:26657", "<host>:<port> to tendermint rpc interface for this chain")
c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device") c.Flags().Bool(FlagUseLedger, false, "Use a connected Ledger device")
c.Flags().Int64(FlagGas, 200000, "gas limit to set per-transaction") c.Flags().Int64(FlagGas, 200000, "gas limit to set per-transaction")
c.Flags().Bool(FlagAsync, false, "broadcast transactions asynchronously")
c.Flags().Bool(FlagJson, false, "return output in json format")
c.Flags().Bool(FlagPrintResponse, false, "return tx response (only works with async = false)")
} }
return cmds return cmds
} }

View File

@ -7,7 +7,6 @@ import (
"net/http" "net/http"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -162,12 +161,6 @@ type NewKeyBody struct {
Password string `json:"password"` Password string `json:"password"`
} }
// new key response REST body
type NewKeyResponse struct {
Address string `json:"address"`
Mnemonic string `json:"mnemonic"`
}
// add new key REST handler // add new key REST handler
func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) { func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
var kb keys.Keybase var kb keys.Keybase
@ -216,22 +209,24 @@ func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
return return
} }
bech32Account, err := sdk.Bech32ifyAcc(sdk.Address(info.GetPubKey().Address().Bytes()))
keyOutput, err := Bech32KeyOutput(info)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
return return
} }
bz, err := json.Marshal(NewKeyResponse{
Address: bech32Account, keyOutput.Seed = mnemonic
Mnemonic: mnemonic,
}) output, err := json.MarshalIndent(keyOutput, "", " ")
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
return return
} }
w.Write(bz)
w.Write(output)
} }
// function to just a new seed to display in the UI before actually persisting it in the keybase // function to just a new seed to display in the UI before actually persisting it in the keybase

View File

@ -25,14 +25,19 @@ func deleteKeyCommand() *cobra.Command {
func runDeleteCmd(cmd *cobra.Command, args []string) error { func runDeleteCmd(cmd *cobra.Command, args []string) error {
name := args[0] name := args[0]
buf := client.BufferStdin() kb, err := GetKeyBase()
oldpass, err := client.GetPassword(
"DANGER - enter password to permanently delete key:", buf)
if err != nil { if err != nil {
return err return err
} }
kb, err := GetKeyBase() _, err = kb.Get(name)
if err != nil {
return err
}
buf := client.BufferStdin()
oldpass, err := client.GetPassword(
"DANGER - enter password to permanently delete key:", buf)
if err != nil { if err != nil {
return err return err
} }

View File

@ -56,7 +56,7 @@ func TestKeys(t *testing.T) {
res, body = Request(t, port, "POST", "/keys", jsonStr) res, body = Request(t, port, "POST", "/keys", jsonStr)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
var resp keys.NewKeyResponse var resp keys.KeyOutput
err = wire.Cdc.UnmarshalJSON([]byte(body), &resp) err = wire.Cdc.UnmarshalJSON([]byte(body), &resp)
require.Nil(t, err, body) require.Nil(t, err, body)

View File

@ -3,6 +3,7 @@ package clitest
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -21,37 +22,44 @@ import (
"github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake"
) )
func TestGaiaCLISend(t *testing.T) { var (
pass = "1234567890"
gaiadHome = ""
gaiacliHome = ""
)
tests.ExecuteT(t, "gaiad unsafe_reset_all") func init() {
pass := "1234567890" gaiadHome, gaiacliHome = getTestingHomeDirs()
executeWrite(t, "gaiacli keys delete foo", pass) }
executeWrite(t, "gaiacli keys delete bar", pass)
chainID := executeInit(t, "gaiad init -o --name=foo") func TestGaiaCLISend(t *testing.T) {
executeWrite(t, "gaiacli keys add bar", pass) tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome))
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass)
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass)
chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome))
executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass)
// get a free port, also setup some common flags // get a free port, also setup some common flags
servAddr, port, err := server.FreeTCPAddr() servAddr, port, err := server.FreeTCPAddr()
require.NoError(t, err) require.NoError(t, err)
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID)
// start gaiad server // start gaiad server
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr))
defer proc.Stop(false) defer proc.Stop(false)
tests.WaitForTMStart(port) tests.WaitForTMStart(port)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
fooCech, err := sdk.Bech32ifyAcc(fooAddr) fooCech := sdk.MustBech32ifyAcc(fooAddr)
require.NoError(t, err) barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") barCech := sdk.MustBech32ifyAcc(barAddr)
barCech, err := sdk.Bech32ifyAcc(barAddr)
require.NoError(t, err)
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo", flags, barCech), pass)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
@ -60,7 +68,7 @@ func TestGaiaCLISend(t *testing.T) {
require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64())
// test autosequencing // test autosequencing
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo", flags, barCech), pass)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
@ -69,7 +77,7 @@ func TestGaiaCLISend(t *testing.T) {
require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64()) require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64())
// test memo // test memo
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo --memo 'testmemo'", flags, barCech), pass) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo --memo 'testmemo'", flags, barCech), pass)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
@ -79,35 +87,31 @@ func TestGaiaCLISend(t *testing.T) {
} }
func TestGaiaCLICreateValidator(t *testing.T) { func TestGaiaCLICreateValidator(t *testing.T) {
tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome))
tests.ExecuteT(t, "gaiad unsafe_reset_all") executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass)
pass := "1234567890" executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass)
executeWrite(t, "gaiacli keys delete foo", pass) chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome))
executeWrite(t, "gaiacli keys delete bar", pass) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass)
chainID := executeInit(t, "gaiad init -o --name=foo")
executeWrite(t, "gaiacli keys add bar", pass)
// get a free port, also setup some common flags // get a free port, also setup some common flags
servAddr, port, err := server.FreeTCPAddr() servAddr, port, err := server.FreeTCPAddr()
require.NoError(t, err) require.NoError(t, err)
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID)
// start gaiad server // start gaiad server
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr))
defer proc.Stop(false) defer proc.Stop(false)
tests.WaitForTMStart(port) tests.WaitForTMStart(port)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
fooCech, err := sdk.Bech32ifyAcc(fooAddr) fooCech := sdk.MustBech32ifyAcc(fooAddr)
require.NoError(t, err) barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
barAddr, barPubKey := executeGetAddrPK(t, "gaiacli keys show bar --output=json") barCech := sdk.MustBech32ifyAcc(barAddr)
barCech, err := sdk.Bech32ifyAcc(barAddr) barCeshPubKey := sdk.MustBech32ifyValPub(barPubKey)
require.NoError(t, err)
barCeshPubKey, err := sdk.Bech32ifyValPub(barPubKey)
require.NoError(t, err)
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --name=foo", flags, barCech), pass) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%v --from=foo", flags, barCech), pass)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags)) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
@ -117,7 +121,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
// create validator // create validator
cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags) cvStr := fmt.Sprintf("gaiacli stake create-validator %v", flags)
cvStr += fmt.Sprintf(" --name=%v", "bar") cvStr += fmt.Sprintf(" --from=%v", "bar")
cvStr += fmt.Sprintf(" --address-validator=%v", barCech) cvStr += fmt.Sprintf(" --address-validator=%v", barCech)
cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey) cvStr += fmt.Sprintf(" --pubkey=%v", barCeshPubKey)
cvStr += fmt.Sprintf(" --amount=%v", "2steak") cvStr += fmt.Sprintf(" --amount=%v", "2steak")
@ -135,7 +139,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
// unbond a single share // unbond a single share
unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags) unbondStr := fmt.Sprintf("gaiacli stake unbond begin %v", flags)
unbondStr += fmt.Sprintf(" --name=%v", "bar") unbondStr += fmt.Sprintf(" --from=%v", "bar")
unbondStr += fmt.Sprintf(" --address-validator=%v", barCech) unbondStr += fmt.Sprintf(" --address-validator=%v", barCech)
unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech) unbondStr += fmt.Sprintf(" --address-delegator=%v", barCech)
unbondStr += fmt.Sprintf(" --shares-amount=%v", "1") unbondStr += fmt.Sprintf(" --shares-amount=%v", "1")
@ -153,33 +157,31 @@ func TestGaiaCLICreateValidator(t *testing.T) {
} }
func TestGaiaCLISubmitProposal(t *testing.T) { func TestGaiaCLISubmitProposal(t *testing.T) {
tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome))
tests.ExecuteT(t, "gaiad unsafe_reset_all") executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass)
pass := "1234567890" executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass)
executeWrite(t, "gaiacli keys delete foo", pass) chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome))
executeWrite(t, "gaiacli keys delete bar", pass) executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass)
chainID := executeInit(t, "gaiad init -o --name=foo")
executeWrite(t, "gaiacli keys add bar", pass)
// get a free port, also setup some common flags // get a free port, also setup some common flags
servAddr, port, err := server.FreeTCPAddr() servAddr, port, err := server.FreeTCPAddr()
require.NoError(t, err) require.NoError(t, err)
flags := fmt.Sprintf("--node=%v --chain-id=%v", servAddr, chainID) flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID)
// start gaiad server // start gaiad server
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr))
defer proc.Stop(false) defer proc.Stop(false)
tests.WaitForTMStart(port) tests.WaitForTMStart(port)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
fooCech, err := sdk.Bech32ifyAcc(fooAddr) fooCech := sdk.MustBech32ifyAcc(fooAddr)
require.NoError(t, err)
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
executeWrite(t, fmt.Sprintf("gaiacli gov submitproposal %v --proposer=%v --deposit=5steak --type=Text --title=Test --description=test --name=foo", flags, fooCech), pass) executeWrite(t, fmt.Sprintf("gaiacli gov submit-proposal %v --proposer=%v --deposit=5steak --type=Text --title=Test --description=test --from=foo", flags, fooCech), pass)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
@ -189,7 +191,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
require.Equal(t, int64(1), proposal1.ProposalID) require.Equal(t, int64(1), proposal1.ProposalID)
require.Equal(t, gov.StatusToString(gov.StatusDepositPeriod), proposal1.Status) require.Equal(t, gov.StatusToString(gov.StatusDepositPeriod), proposal1.Status)
executeWrite(t, fmt.Sprintf("gaiacli gov deposit %v --depositer=%v --deposit=10steak --proposalID=1 --name=foo", flags, fooCech), pass) executeWrite(t, fmt.Sprintf("gaiacli gov deposit %v --depositer=%v --deposit=10steak --proposalID=1 --from=foo", flags, fooCech), pass)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags)) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
@ -198,7 +200,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
require.Equal(t, int64(1), proposal1.ProposalID) require.Equal(t, int64(1), proposal1.ProposalID)
require.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal1.Status) require.Equal(t, gov.StatusToString(gov.StatusVotingPeriod), proposal1.Status)
executeWrite(t, fmt.Sprintf("gaiacli gov vote %v --proposalID=1 --voter=%v --option=Yes --name=foo", flags, fooCech), pass) executeWrite(t, fmt.Sprintf("gaiacli gov vote %v --proposalID=1 --voter=%v --option=Yes --from=foo", flags, fooCech), pass)
tests.WaitForNextHeightTM(port) tests.WaitForNextHeightTM(port)
vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposalID=1 --voter=%v --output=json %v", fooCech, flags)) vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposalID=1 --voter=%v --output=json %v", fooCech, flags))
@ -206,6 +208,16 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
require.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option) require.Equal(t, gov.VoteOptionToString(gov.OptionYes), vote.Option)
} }
//___________________________________________________________________________________
// helper methods
func getTestingHomeDirs() (string, string) {
tmpDir := os.TempDir()
gaiadHome := fmt.Sprintf("%s%s.test_gaiad", tmpDir, string(os.PathSeparator))
gaiacliHome := fmt.Sprintf("%s%s.test_gaiacli", tmpDir, string(os.PathSeparator))
return gaiadHome, gaiacliHome
}
//___________________________________________________________________________________ //___________________________________________________________________________________
// executors // executors

View File

@ -197,6 +197,7 @@ func MakeCodec() *wire.Codec {
auth.RegisterWire(cdc) auth.RegisterWire(cdc)
sdk.RegisterWire(cdc) sdk.RegisterWire(cdc)
wire.RegisterCrypto(cdc) wire.RegisterCrypto(cdc)
cdc.Seal()
return cdc return cdc
} }

View File

@ -220,7 +220,7 @@ gaiacli stake create-validator \
--address-validator=<account_cosmosaccaddr> --address-validator=<account_cosmosaccaddr>
--moniker="choose a moniker" \ --moniker="choose a moniker" \
--chain-id=gaia-6002 \ --chain-id=gaia-6002 \
--name=<key_name> --from=<key_name>
``` ```
### Edit Validator Description ### Edit Validator Description
@ -237,7 +237,7 @@ gaiacli stake edit-validator
--keybase-sig="6A0D65E29A4CBC8E" --keybase-sig="6A0D65E29A4CBC8E"
--details="To infinity and beyond!" --details="To infinity and beyond!"
--chain-id=gaia-6002 \ --chain-id=gaia-6002 \
--name=<key_name> --from=<key_name>
``` ```
### View Validator Description ### View Validator Description
@ -272,7 +272,7 @@ gaiad start
Wait for your full node to catch up to the latest block. Next, run the following command. Note that `<cosmosaccaddr>` is the address of your validator account, and `<name>` is the name of the validator account. You can find this info by running `gaiacli keys list`. Wait for your full node to catch up to the latest block. Next, run the following command. Note that `<cosmosaccaddr>` is the address of your validator account, and `<name>` is the name of the validator account. You can find this info by running `gaiacli keys list`.
```bash ```bash
gaiacli stake unrevoke <cosmosaccaddr> --chain-id=gaia-6002 --name=<name> gaiacli stake unrevoke <cosmosaccaddr> --chain-id=gaia-6002 --from=<name>
``` ```
**WARNING:** If you don't wait for `gaiad` to sync before running `unrevoke`, you will receive an error message telling you your validator is still jailed. **WARNING:** If you don't wait for `gaiad` to sync before running `unrevoke`, you will receive an error message telling you your validator is still jailed.
@ -320,8 +320,8 @@ On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond t
gaiacli stake delegate \ gaiacli stake delegate \
--amount=10steak \ --amount=10steak \
--address-delegator=<account_cosmosaccaddr> \ --address-delegator=<account_cosmosaccaddr> \
--address-validator=$(gaiad tendermint show_validator) \ --address-validator=<validator_cosmosaccaddr> \
--name=<key_name> \ --from=<key_name> \
--chain-id=gaia-6002 --chain-id=gaia-6002
``` ```
@ -336,9 +336,9 @@ If for any reason the validator misbehaves, or you want to unbond a certain amou
```bash ```bash
gaiacli stake unbond \ gaiacli stake unbond \
--address-delegator=<account_cosmosaccaddr> \ --address-delegator=<account_cosmosaccaddr> \
--address-validator=$(gaiad tendermint show_validator) \ --address-validator=<validator_cosmosaccaddr> \
--shares=MAX \ --shares=MAX \
--name=<key_name> \ --from=<key_name> \
--chain-id=gaia-6002 --chain-id=gaia-6002
``` ```
@ -349,7 +349,7 @@ gaiacli account <account_cosmosaccaddr>
gaiacli stake delegation \ gaiacli stake delegation \
--address-delegator=<account_cosmosaccaddr> \ --address-delegator=<account_cosmosaccaddr> \
--address-validator=$(gaiad tendermint show_validator) \ --address-validator=<validator_cosmosaccaddr> \
--chain-id=gaia-6002 --chain-id=gaia-6002
``` ```
@ -361,7 +361,7 @@ gaiacli stake delegation \
gaiacli send \ gaiacli send \
--amount=10faucetToken \ --amount=10faucetToken \
--chain-id=gaia-6002 \ --chain-id=gaia-6002 \
--name=<key_name> \ --from=<key_name> \
--to=<destination_cosmosaccaddr> --to=<destination_cosmosaccaddr>
``` ```

View File

@ -188,6 +188,9 @@ func (kb dbKeybase) List() ([]Info, error) {
// Get returns the public information about one key. // Get returns the public information about one key.
func (kb dbKeybase) Get(name string) (Info, error) { func (kb dbKeybase) Get(name string) (Info, error) {
bs := kb.db.Get(infoKey(name)) bs := kb.db.Get(infoKey(name))
if len(bs) == 0 {
return nil, fmt.Errorf("Key %s not found", name)
}
return readInfo(bs) return readInfo(bs)
} }

View File

@ -197,9 +197,9 @@ We'll have ``alice`` send some ``mycoin`` to ``bob``, who has now joined the net
:: ::
gaiacli send --amount=1000mycoin --sequence=0 --name=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 --chain-id=test-chain-Uv1EVU gaiacli send --amount=1000mycoin --sequence=0 --from=alice --to=5A35E4CC7B7DC0A5CB49CEA91763213A9AE92AD6 --chain-id=test-chain-Uv1EVU
where the ``--sequence`` flag is to be incremented for each transaction, the ``--name`` flag is the sender (alice), and the ``--to`` flag takes ``bob``'s address. You'll see something like: where the ``--sequence`` flag is to be incremented for each transaction, the ``--from`` flag is the sender (alice), and the ``--to`` flag takes ``bob``'s address. You'll see something like:
:: ::
@ -264,7 +264,7 @@ Now ``bob`` can create a validator with that pubkey.
:: ::
gaiacli stake create-validator --amount=10mycoin --name=bob --address-validator=<address> --pub-key=<pubkey> --moniker=bobby gaiacli stake create-validator --amount=10mycoin --from=bob --address-validator=<address> --pub-key=<pubkey> --moniker=bobby
with an output like: with an output like:
@ -306,13 +306,13 @@ First let's have ``alice`` send some coins to ``charlie``:
:: ::
gaiacli send --amount=1000mycoin --sequence=2 --name=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF gaiacli send --amount=1000mycoin --sequence=2 --from=alice --to=48F74F48281C89E5E4BE9092F735EA519768E8EF
Then ``charlie`` will delegate some mycoin to ``bob``: Then ``charlie`` will delegate some mycoin to ``bob``:
:: ::
gaiacli stake delegate --amount=10mycoin --address-delegator=<charlie's address> --address-validator=<bob's address> --name=charlie gaiacli stake delegate --amount=10mycoin --address-delegator=<charlie's address> --address-validator=<bob's address> --from=charlie
You'll see output like: You'll see output like:
@ -396,7 +396,7 @@ your VotingPower reduce and your account balance increase.
:: ::
gaiacli stake unbond --amount=5mycoin --name=charlie --address-delegator=<address> --address-validator=<address> gaiacli stake unbond --amount=5mycoin --from=charlie --address-delegator=<address> --address-validator=<address>
gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF gaiacli account 48F74F48281C89E5E4BE9092F735EA519768E8EF
See the bond decrease with ``gaiacli stake delegation`` like above. See the bond decrease with ``gaiacli stake delegation`` like above.

View File

@ -63,7 +63,7 @@ Then, we try to transfer some `steak` to another account:
``` ```
gaiacli account <FOO-ADDR> gaiacli account <FOO-ADDR>
gaiacli account <BAR-ADDR> gaiacli account <BAR-ADDR>
gaiacli send --amount=10steak --to=<BAR-ADDR> --name=foo --chain-id=test-chain gaiacli send --amount=10steak --to=<BAR-ADDR> --from=foo --chain-id=test-chain
``` ```
**Note:** We need to be careful with the `chain-id` and `sequence` **Note:** We need to be careful with the `chain-id` and `sequence`
@ -84,7 +84,7 @@ Finally, to relinquish all your power, unbond some coins. You should see
your VotingPower reduce and your account balance increase. your VotingPower reduce and your account balance increase.
``` ```
gaiacli unbond --chain-id=<chain-id> --name=test gaiacli unbond --chain-id=<chain-id> --from=test
``` ```
That's it! That's it!

29
docs/clients/ledger.md Normal file
View File

@ -0,0 +1,29 @@
# Ledger // Cosmos
### Ledger Support for account keys
`gaiacli` now supports derivation of account keys from a Ledger seed. To use this functionality you will need the following:
- A running `gaiad` instance connected to the network you wish to use.
- A `gaiacli` instance configured to connect to your chosen `gaiad` instance.
- A LedgerNano with the `ledger-cosmos` app installed
* Install the Cosmos app onto your Ledger by following the instructions in the [`ledger-cosmos`](https://github.com/cosmos/ledger-cosmos/blob/master/docs/BUILD.md) repository.
* A production-ready version of this app will soon be included in the [Ledger Apps Store](https://www.ledgerwallet.com/apps)
> **NOTE:** Cosmos keys are derived acording to the [BIP 44 Hierarchical Deterministic wallet spec](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki). For more information on Cosmos derivation paths [see the hd package](https://github.com/cosmos/cosmos-sdk/blob/develop/crypto/keys/hd/hdpath.go#L30).
Once you have the Cosmos app installed on your Ledger, and the Ledger is accessible from the machine you are using `gaiacli` from you can create a new account key using the Ledger:
```bash
$ gaiacli keys add {{ .Key.Name }} --ledger
NAME: TYPE: ADDRESS: PUBKEY:
{{ .Key.Name }} ledger cosmosaccaddr1aw64xxr80lwqqdk8u2xhlrkxqaxamkr3e2g943 cosmosaccpub1addwnpepqvhs678gh9aqrjc2tg2vezw86csnvgzqq530ujkunt5tkuc7lhjkz5mj629
```
This key will only be accessible while the Ledger is plugged in and unlocked. To send some coins with this key, run the following:
```bash
$ gaiacli send --from {{ .Key.Name }} --to {{ .Destination.AccAddr }} --chain-id=gaia-7000
```
You will be asked to review and confirm the transaction on the Ledger. Once you do this you should see the result in the console! Now you can use your Ledger to manage your Atoms and Stake!

View File

@ -189,7 +189,7 @@ docs](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Context) for more det
### Result ### Result
Handler takes a Context and Msg and returns a Result. Handler takes a Context and Msg and returns a Result.
Result is motivated by the corresponding [ABCI result](https://github.com/tendermint/tendermint/abci/blob/master/types/types.proto#L165). Result is motivated by the corresponding [ABCI result](https://github.com/tendermint/tendermint/blob/master/abci/types/types.proto#L165).
It contains return values, error information, logs, and meta data about the transaction: It contains return values, error information, logs, and meta data about the transaction:
```go ```go
@ -409,7 +409,7 @@ func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
Finally, we stitch it all together using the `BaseApp`. Finally, we stitch it all together using the `BaseApp`.
The BaseApp is an abstraction over the [Tendermint The BaseApp is an abstraction over the [Tendermint
ABCI](https://github.com/tendermint/tendermint/abci) that ABCI](https://github.com/tendermint/tendermint/tree/master/abci) that
simplifies application development by handling common low-level concerns. simplifies application development by handling common low-level concerns.
It serves as the mediator between the two key components of an SDK app: the store It serves as the mediator between the two key components of an SDK app: the store
and the message handlers. The BaseApp implements the and the message handlers. The BaseApp implements the
@ -473,7 +473,7 @@ Tendermint consensus engine. It would be initialized by a Genesis file, and it
would be driven by blocks of transactions committed by the underlying Tendermint would be driven by blocks of transactions committed by the underlying Tendermint
consensus. We'll talk more about ABCI and how this all works a bit later, but consensus. We'll talk more about ABCI and how this all works a bit later, but
feel free to check the feel free to check the
[specification](https://github.com/tendermint/tendermint/abci/blob/master/specification.md). [specification](https://github.com/tendermint/tendermint/blob/master/docs/abci-spec.md).
We'll also see how to connect our app to a complete suite of components We'll also see how to connect our app to a complete suite of components
for running and using a live blockchain application. for running and using a live blockchain application.

View File

@ -16,7 +16,7 @@ here we will introduce the other ABCI requests sent by Tendermint, and
how we can use them to build more advanced applications. For a more complete how we can use them to build more advanced applications. For a more complete
depiction of the ABCI and how its used, see depiction of the ABCI and how its used, see
[the [the
specification](https://github.com/tendermint/tendermint/abci/blob/master/specification.md) specification](https://github.com/tendermint/tendermint/blob/master/docs/abci-spec.md)
## InitChain ## InitChain

View File

@ -59,7 +59,7 @@ func newApp(logger log.Logger, db dbm.DB) abci.Application {
Note we utilize the popular [cobra library](https://github.com/spf13/cobra) Note we utilize the popular [cobra library](https://github.com/spf13/cobra)
for the CLI, in concert with the [viper library](https://github.com/spf13/library) for the CLI, in concert with the [viper library](https://github.com/spf13/library)
for managing configuration. See our [cli library](https://github.com/tendermint/tmlibs/blob/master/cli/setup.go) for managing configuration. See our [cli library](https://github.com/tendermint/blob/master/tmlibs/cli/setup.go)
for more details. for more details.
TODO: compile and run the binary TODO: compile and run the binary

View File

@ -85,7 +85,7 @@ func (msg MsgSend) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return bz return sdk.MustSortJSON(bz)
} }
// Implements Msg. Return the signer. // Implements Msg. Return the signer.

View File

@ -100,7 +100,7 @@ func (msg MsgIssue) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return bz return sdk.MustSortJSON(bz)
} }
// Implements Msg. Return the signer. // Implements Msg. Return the signer.

View File

@ -6,7 +6,7 @@ Tendermint blocks can include
[Evidence](https://github.com/tendermint/tendermint/blob/develop/docs/spec/blockchain/blockchain.md#evidence), which indicates that a validator [Evidence](https://github.com/tendermint/tendermint/blob/develop/docs/spec/blockchain/blockchain.md#evidence), which indicates that a validator
committed malicious behaviour. The relevant information is forwarded to the committed malicious behaviour. The relevant information is forwarded to the
application as [ABCI application as [ABCI
Evidence](https://github.com/tendermint/tendermint/abci/blob/develop/types/types.proto#L259), so the validator an be accordingly punished. Evidence](https://github.com/tendermint/tendermint/blob/develop/abci/types/types.proto#L259), so the validator an be accordingly punished.
For some `evidence` to be valid, it must satisfy: For some `evidence` to be valid, it must satisfy:

View File

@ -123,12 +123,12 @@ Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alice's address we got from
The following command will send coins from alice, to bob: The following command will send coins from alice, to bob:
``` ```
basecli send --name=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D basecli send --from=alice --amount=10000mycoin --to=29D721F054537C91F618A0FDBF770DA51EF8C48D
--sequence=0 --chain-id=test-chain-AE4XQo --sequence=0 --chain-id=test-chain-AE4XQo
``` ```
Flag Descriptions: Flag Descriptions:
- `name` is the name you gave your key - `from` is the name you gave your key
- `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file - `mycoin` is the name of the token for this basecoin demo, initialized in the genesis.json file
- `sequence` is a tally of how many transactions have been made by this account. Since this is the first tx on this account, it is 0 - `sequence` is a tally of how many transactions have been made by this account. Since this is the first tx on this account, it is 0
- `chain-id` is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/genesis.json` - `chain-id` is the unique ID that helps tendermint identify which network to connect to. You can find it in the terminal output from the gaiad daemon in the header block , or in the genesis.json file at `~/.basecoind/config/genesis.json`
@ -142,16 +142,16 @@ basecli account 29D721F054537C91F618A0FDBF770DA51EF8C48D
Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail: Now lets send some from bob to charlie. Make sure you send less than bob has, otherwise the transaction will fail:
``` ```
basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E basecli send --from=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E
--sequence=0 --chain-id=test-chain-AE4XQo --sequence=0 --chain-id=test-chain-AE4XQo
``` ```
Note how we use the ``--name`` flag to select a different account to send from. Note how we use the ``--from`` flag to select a different account to send from.
Lets now try to send from bob back to alice: Lets now try to send from bob back to alice:
``` ```
basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD basecli send --from=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD
--sequence=1 --chain-id=test-chain-AE4XQo --sequence=1 --chain-id=test-chain-AE4XQo
``` ```
@ -256,7 +256,7 @@ Accounts are serialized and stored in a Merkle tree under the key
Typically, the address of the account is the 20-byte ``RIPEMD160`` hash Typically, the address of the account is the 20-byte ``RIPEMD160`` hash
of the public key, but other formats are acceptable as well, as defined of the public key, but other formats are acceptable as well, as defined
in the `Tendermint crypto in the `Tendermint crypto
library <https://github.com/tendermint/tendermint/crypto>`__. The Merkle tree library <https://github.com/tendermint/tendermint/tree/master/crypto>`__. The Merkle tree
used in Basecoin is a balanced, binary search tree, which we call an used in Basecoin is a balanced, binary search tree, which we call an
`IAVL tree <https://github.com/tendermint/iavl>`__. `IAVL tree <https://github.com/tendermint/iavl>`__.

View File

@ -103,6 +103,8 @@ func MakeCodec() *wire.Codec {
cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterInterface((*auth.Account)(nil), nil)
cdc.RegisterConcrete(&types.AppAccount{}, "basecoin/Account", nil) cdc.RegisterConcrete(&types.AppAccount{}, "basecoin/Account", nil)
cdc.Seal()
return cdc return cdc
} }

View File

@ -113,6 +113,9 @@ func MakeCodec() *wire.Codec {
// Register AppAccount // Register AppAccount
cdc.RegisterInterface((*auth.Account)(nil), nil) cdc.RegisterInterface((*auth.Account)(nil), nil)
cdc.RegisterConcrete(&types.AppAccount{}, "democoin/Account", nil) cdc.RegisterConcrete(&types.AppAccount{}, "democoin/Account", nil)
cdc.Seal()
return cdc return cdc
} }

View File

@ -4,14 +4,12 @@ import (
"os" "os"
"testing" "testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/examples/democoin/types" "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/cool"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
dbm "github.com/tendermint/tendermint/libs/db" dbm "github.com/tendermint/tendermint/libs/db"

View File

@ -29,20 +29,24 @@ func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso
if err != nil { if err != nil {
return return
} }
key := "cool" key := "cool"
value := json.RawMessage(`{ value := json.RawMessage(`{
"trend": "ice-cold" "trend": "ice-cold"
}`) }`)
appState, err = server.AppendJSON(cdc, appState, key, value)
appState, err = server.InsertKeyJSON(cdc, appState, key, value)
if err != nil { if err != nil {
return return
} }
key = "pow" key = "pow"
value = json.RawMessage(`{ value = json.RawMessage(`{
"difficulty": 1, "difficulty": 1,
"count": 0 "count": 0
}`) }`)
appState, err = server.AppendJSON(cdc, appState, key, value)
appState, err = server.InsertKeyJSON(cdc, appState, key, value)
return return
} }

View File

@ -3,15 +3,13 @@ package cool
import ( import (
"testing" "testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock"
bank "github.com/cosmos/cosmos-sdk/x/bank" bank "github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/mock"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
) )
var ( var (

View File

@ -1,8 +1,6 @@
package cli package cli
import ( import (
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -37,12 +35,11 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command {
name := viper.GetString(client.FlagName) name := viper.GetString(client.FlagName)
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
res, err := ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }
@ -70,12 +67,11 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command {
msg := cool.NewMsgSetTrend(from, args[0]) msg := cool.NewMsgSetTrend(from, args[0])
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
res, err := ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }

View File

@ -58,7 +58,7 @@ func (msg MsgSetTrend) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
//_______________________________________________________________________ //_______________________________________________________________________
@ -102,5 +102,5 @@ func (msg MsgQuiz) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }

View File

@ -48,6 +48,8 @@ func makeCodec() *wire.Codec {
cdc.RegisterInterface((*Payload)(nil), nil) cdc.RegisterInterface((*Payload)(nil), nil)
cdc.RegisterConcrete(seqOracle{}, "test/oracle/seqOracle", nil) cdc.RegisterConcrete(seqOracle{}, "test/oracle/seqOracle", nil)
cdc.Seal()
return cdc return cdc
} }

View File

@ -18,7 +18,7 @@ func (msg Msg) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return bz return sdk.MustSortJSON(bz)
} }
// GetSigners implements sdk.Msg // GetSigners implements sdk.Msg

View File

@ -7,8 +7,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock"
"github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/mock"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"

View File

@ -1,7 +1,6 @@
package cli package cli
import ( import (
"fmt"
"strconv" "strconv"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -49,12 +48,11 @@ func MineCmd(cdc *wire.Codec) *cobra.Command {
name := ctx.FromAddressName name := ctx.FromAddressName
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
res, err := ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(name, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }

View File

@ -76,5 +76,5 @@ func (msg MsgMine) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }

View File

@ -62,7 +62,7 @@ func TestMsgMineGetSignBytes(t *testing.T) {
addr := sdk.Address([]byte("sender")) addr := sdk.Address([]byte("sender"))
msg := MsgMine{addr, 1, 1, 1, []byte("abc")} msg := MsgMine{addr, 1, 1, 1, []byte("abc")}
res := msg.GetSignBytes() res := msg.GetSignBytes()
require.Equal(t, string(res), `{"sender":"73656E646572","difficulty":1,"count":1,"nonce":1,"proof":"YWJj"}`) require.Equal(t, string(res), `{"count":1,"difficulty":1,"nonce":1,"proof":"YWJj","sender":"73656E646572"}`)
} }
func TestMsgMineGetSigners(t *testing.T) { func TestMsgMineGetSigners(t *testing.T) {

View File

@ -87,11 +87,10 @@ func UnbondTxCmd(cdc *wire.Codec) *cobra.Command {
func sendMsg(cdc *wire.Codec, msg sdk.Msg) error { func sendMsg(cdc *wire.Codec, msg sdk.Msg) error {
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
} }

View File

@ -48,7 +48,7 @@ func (msg MsgBond) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return bz return sdk.MustSortJSON(bz)
} }
//_______________________________________________________________ //_______________________________________________________________

View File

@ -27,7 +27,7 @@ func (tx kvstoreTx) GetMemo() string {
} }
func (tx kvstoreTx) GetSignBytes() []byte { func (tx kvstoreTx) GetSignBytes() []byte {
return tx.bytes return sdk.MustSortJSON(tx.bytes)
} }
// Should the app be calling this? Or only handlers? // Should the app be calling this? Or only handlers?

View File

@ -332,32 +332,20 @@ func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
return privValidator.GetPubKey() return privValidator.GetPubKey()
} }
// create the genesis file // writeGenesisFile creates and writes the genesis configuration to disk. An
// error is returned if building or writing the configuration to file fails.
func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error {
genDoc := tmtypes.GenesisDoc{ genDoc := tmtypes.GenesisDoc{
ChainID: chainID, ChainID: chainID,
Validators: validators, Validators: validators,
AppStateJSON: appState,
} }
if err := genDoc.ValidateAndComplete(); err != nil { if err := genDoc.ValidateAndComplete(); err != nil {
return err return err
} }
if err := genDoc.SaveAs(genesisFile); err != nil {
return err
}
return addAppStateToGenesis(cdc, genesisFile, appState)
}
// Add one line to the genesis file return genDoc.SaveAs(genesisFile)
func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState json.RawMessage) error {
bz, err := ioutil.ReadFile(genesisConfigPath)
if err != nil {
return err
}
out, err := AppendJSON(cdc, bz, "app_state", appState)
if err != nil {
return err
}
return ioutil.WriteFile(genesisConfigPath, out, 0600)
} }
//_____________________________________________________________________ //_____________________________________________________________________

View File

@ -123,15 +123,21 @@ func AddCommands(
//___________________________________________________________________________________ //___________________________________________________________________________________
// append a new json field to existing json message // InsertKeyJSON inserts a new JSON field/key with a given value to an existing
func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) { // JSON message. An error is returned if any serialization operation fails.
//
// NOTE: The ordering of the keys returned as the resulting JSON message is
// non-deterministic, so the client should not rely on key ordering.
func InsertKeyJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) ([]byte, error) {
var jsonMap map[string]json.RawMessage var jsonMap map[string]json.RawMessage
err = cdc.UnmarshalJSON(baseJSON, &jsonMap)
if err != nil { if err := cdc.UnmarshalJSON(baseJSON, &jsonMap); err != nil {
return nil, err return nil, err
} }
jsonMap[key] = value jsonMap[key] = value
bz, err := wire.MarshalJSONIndent(cdc, jsonMap) bz, err := wire.MarshalJSONIndent(cdc, jsonMap)
return json.RawMessage(bz), err return json.RawMessage(bz), err
} }

View File

@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func TestAppendJSON(t *testing.T) { func TestInsertKeyJSON(t *testing.T) {
cdc := wire.NewCodec() cdc := wire.NewCodec()
foo := map[string]string{"foo": "foofoo"} foo := map[string]string{"foo": "foofoo"}
@ -24,7 +24,7 @@ func TestAppendJSON(t *testing.T) {
barRaw := json.RawMessage(bz) barRaw := json.RawMessage(bz)
// make the append // make the append
appBz, err := AppendJSON(cdc, fooRaw, "barOuter", barRaw) appBz, err := InsertKeyJSON(cdc, fooRaw, "barOuter", barRaw)
require.NoError(t, err) require.NoError(t, err)
// test the append // test the append

View File

@ -36,7 +36,7 @@ echo; echo "Empty account:" $TO
./build/basecli account $TO ./build/basecli account $TO
# send some money # send some money
TX=`echo $PASS | ./build/basecli send --to=$TO --amount=1000mycoin --name=demo --seq=0` TX=`echo $PASS | ./build/basecli send --to=$TO --amount=1000mycoin --from=demo --seq=0`
echo; echo "SendTx"; echo $TX echo; echo "SendTx"; echo $TX
HASH=`echo $TX | cut -d' ' -f6` HASH=`echo $TX | cut -d' ' -f6`
echo "tx hash:" $HASH echo "tx hash:" $HASH

View File

@ -13,8 +13,12 @@ import (
//Address is a go crypto-style Address //Address is a go crypto-style Address
type Address = cmn.HexBytes type Address = cmn.HexBytes
// Bech32 prefixes // nolint
const ( const (
// expected address length
AddrLen = 20
// Bech32 prefixes
Bech32PrefixAccAddr = "cosmosaccaddr" Bech32PrefixAccAddr = "cosmosaccaddr"
Bech32PrefixAccPub = "cosmosaccpub" Bech32PrefixAccPub = "cosmosaccpub"
Bech32PrefixValAddr = "cosmosvaladdr" Bech32PrefixValAddr = "cosmosvaladdr"

View File

@ -41,6 +41,10 @@ func NewRat(Numerator int64, Denominator ...int64) Rat {
// precision is the number of values after the decimal point which should be read // precision is the number of values after the decimal point which should be read
func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) { func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) {
// first extract any negative symbol // first extract any negative symbol
if len(decimalStr) == 0 {
return f, ErrUnknownRequest("decimal string is empty")
}
neg := false neg := false
if string(decimalStr[0]) == "-" { if string(decimalStr[0]) == "-" {
neg = true neg = true

View File

@ -27,6 +27,7 @@ func TestNewFromDecimal(t *testing.T) {
expErr bool expErr bool
exp Rat exp Rat
}{ }{
{"", true, Rat{}},
{"0", false, NewRat(0)}, {"0", false, NewRat(0)},
{"1", false, NewRat(1)}, {"1", false, NewRat(1)},
{"1.1", false, NewRat(11, 10)}, {"1.1", false, NewRat(11, 10)},

View File

@ -60,7 +60,7 @@ func (msg *TestMsg) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return bz return MustSortJSON(bz)
} }
func (msg *TestMsg) ValidateBasic() Error { return nil } func (msg *TestMsg) ValidateBasic() Error { return nil }
func (msg *TestMsg) GetSigners() []Address { func (msg *TestMsg) GetSigners() []Address {

31
types/utils.go Normal file
View File

@ -0,0 +1,31 @@
package types
import "encoding/json"
// SortedJSON takes any JSON and returns it sorted by keys. Also, all white-spaces
// are removed.
// This method can be used to canonicalize JSON to be returned by GetSignBytes,
// e.g. for the ledger integration.
// If the passed JSON isn't valid it will return an error.
func SortJSON(toSortJSON []byte) ([]byte, error) {
var c interface{}
err := json.Unmarshal(toSortJSON, &c)
if err != nil {
return nil, err
}
js, err := json.Marshal(c)
if err != nil {
return nil, err
}
return js, nil
}
// MustSortJSON is like SortJSON but panic if an error occurs, e.g., if
// the passed JSON isn't valid.
func MustSortJSON(toSortJSON []byte) []byte {
js, err := SortJSON(toSortJSON)
if err != nil {
panic(err)
}
return js
}

39
types/utils_test.go Normal file
View File

@ -0,0 +1,39 @@
package types
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestSortJSON(t *testing.T) {
cases := []struct {
unsortedJSON string
want string
wantErr bool
}{
// simple case
{unsortedJSON: `{"cosmos":"foo", "atom":"bar", "tendermint":"foobar"}`,
want: `{"atom":"bar","cosmos":"foo","tendermint":"foobar"}`, wantErr: false},
// failing case (invalid JSON):
{unsortedJSON: `"cosmos":"foo",,,, "atom":"bar", "tendermint":"foobar"}`,
want: "",
wantErr: true},
// genesis.json
{unsortedJSON: `{"consensus_params":{"block_size_params":{"max_bytes":22020096,"max_txs":100000,"max_gas":-1},"tx_size_params":{"max_bytes":10240,"max_gas":-1},"block_gossip_params":{"block_part_size_bytes":65536},"evidence_params":{"max_age":100000}},"validators":[{"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="},"power":100,"name":""}],"app_hash":"","genesis_time":"2018-05-11T15:52:25.424795506Z","chain_id":"test-chain-Q6VeoW","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"denom":"Token","amount":1000},{"denom":"steak","amount":50}]}],"stake":{"pool":{"total_supply":50,"bonded_shares":"0","unbonded_shares":"0","bonded_pool":0,"unbonded_pool":0,"inflation_last_time":0,"inflation":"7/100"},"params":{"inflation_rate_change":"13/100","inflation_max":"1/5","inflation_min":"7/100","goal_bonded":"67/100","max_validators":100,"bond_denom":"steak"},"candidates":null,"bonds":null}}}`,
want: `{"app_hash":"","app_state":{"accounts":[{"address":"718C9C23F98C9642569742ADDD9F9AB9743FBD5D","coins":[{"amount":1000,"denom":"Token"},{"amount":50,"denom":"steak"}]}],"stake":{"bonds":null,"candidates":null,"params":{"bond_denom":"steak","goal_bonded":"67/100","inflation_max":"1/5","inflation_min":"7/100","inflation_rate_change":"13/100","max_validators":100},"pool":{"bonded_pool":0,"bonded_shares":"0","inflation":"7/100","inflation_last_time":0,"total_supply":50,"unbonded_pool":0,"unbonded_shares":"0"}}},"chain_id":"test-chain-Q6VeoW","consensus_params":{"block_gossip_params":{"block_part_size_bytes":65536},"block_size_params":{"max_bytes":22020096,"max_gas":-1,"max_txs":100000},"evidence_params":{"max_age":100000},"tx_size_params":{"max_bytes":10240,"max_gas":-1}},"genesis_time":"2018-05-11T15:52:25.424795506Z","validators":[{"name":"","power":100,"pub_key":{"type":"AC26791624DE60","value":"c7UMMAbjFuc5GhGPy0E5q5tefy12p9Tq0imXqdrKXwo="}}]}`,
wantErr: false},
// from the TXSpec:
{unsortedJSON: `{"chain_id":"test-chain-1","sequence":1,"fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"alt_bytes":null}`,
want: `{"alt_bytes":null,"chain_id":"test-chain-1","fee_bytes":{"amount":[{"amount":5,"denom":"photon"}],"gas":10000},"msg_bytes":{"inputs":[{"address":"696E707574","coins":[{"amount":10,"denom":"atom"}]}],"outputs":[{"address":"6F7574707574","coins":[{"amount":10,"denom":"atom"}]}]},"sequence":1}`,
wantErr: false},
}
for _, tc := range cases {
got, err := SortJSON([]byte(tc.unsortedJSON))
if tc.wantErr != (err != nil) {
t.Fatalf("got %t, want: %t, err=%s", err != nil, tc.wantErr, err)
}
require.Equal(t, string(got), tc.want)
}
}

View File

@ -44,6 +44,5 @@ var Cdc *Codec
func init() { func init() {
cdc := NewCodec() cdc := NewCodec()
RegisterCrypto(cdc) RegisterCrypto(cdc)
Cdc = cdc Cdc = cdc.Seal()
//Cdc = cdc.Seal() // TODO uncomment once amino upgraded to 0.9.10
} }

View File

@ -1,6 +1,7 @@
package cli package cli
import ( import (
"errors"
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -54,7 +55,7 @@ func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecode
// Check if account was found // Check if account was found
if res == nil { if res == nil {
return sdk.ErrUnknownAddress("No account with address " + addr + return errors.New("No account with address " + addr +
" was found in the state.\nAre you sure there has been a transaction involving it?") " was found in the state.\nAre you sure there has been a transaction involving it?")
} }

View File

@ -1,110 +0,0 @@
package mock
import (
"os"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/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"
)
// Extended ABCI application
type App struct {
*bam.BaseApp
Cdc *wire.Codec // public since the codec is passed into the module anyways.
KeyMain *sdk.KVStoreKey
KeyAccount *sdk.KVStoreKey
// TODO: Abstract this out from not needing to be auth specifically
AccountMapper auth.AccountMapper
FeeCollectionKeeper auth.FeeCollectionKeeper
GenesisAccounts []auth.Account
}
// partially construct a new app on the memstore for module and genesis testing
func NewApp() *App {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
// create the cdc with some standard codecs
cdc := wire.NewCodec()
sdk.RegisterWire(cdc)
wire.RegisterCrypto(cdc)
auth.RegisterWire(cdc)
// create your application object
app := &App{
BaseApp: bam.NewBaseApp("mock", cdc, logger, db),
Cdc: cdc,
KeyMain: sdk.NewKVStoreKey("main"),
KeyAccount: sdk.NewKVStoreKey("acc"),
}
// define the accountMapper
app.AccountMapper = auth.NewAccountMapper(
app.Cdc,
app.KeyAccount, // target store
&auth.BaseAccount{}, // prototype
)
// initialize the app, the chainers and blockers can be overwritten before calling complete setup
app.SetInitChainer(app.InitChainer)
app.SetAnteHandler(auth.NewAnteHandler(app.AccountMapper, app.FeeCollectionKeeper))
return app
}
// complete the application setup after the routes have been registered
func (app *App) CompleteSetup(newKeys []*sdk.KVStoreKey) error {
newKeys = append(newKeys, app.KeyMain)
newKeys = append(newKeys, app.KeyAccount)
app.MountStoresIAVL(newKeys...)
err := app.LoadLatestVersion(app.KeyMain)
return err
}
// custom logic for initialization
func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain {
// load the accounts
for _, genacc := range app.GenesisAccounts {
acc := app.AccountMapper.NewAccountWithAddress(ctx, genacc.GetAddress())
err := acc.SetCoins(genacc.GetCoins())
if err != nil {
// TODO: Handle with #870
panic(err)
}
app.AccountMapper.SetAccount(ctx, acc)
}
return abci.ResponseInitChain{}
}
// Generate genesis accounts loaded with coins, and returns their addresses, pubkeys, and privkeys
func CreateGenAccounts(numAccs int64, genCoins sdk.Coins) (genAccs []auth.Account, addrs []sdk.Address, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) {
for i := int64(0); i < numAccs; i++ {
privKey := crypto.GenPrivKeyEd25519()
pubKey := privKey.PubKey()
addr := pubKey.Address()
genAcc := &auth.BaseAccount{
Address: addr,
Coins: genCoins,
}
genAccs = append(genAccs, genAcc)
privKeys = append(privKeys, privKey)
pubKeys = append(pubKeys, pubKey)
addrs = append(addrs, addr)
}
return
}

View File

@ -1,92 +0,0 @@
package mock
import (
"testing"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
)
// A mock transaction that has a validation which can fail.
type testMsg struct {
signers []sdk.Address
positiveNum int64
}
// TODO: Clean this up, make it public
const msgType = "testMsg"
func (tx testMsg) Type() string { return msgType }
func (tx testMsg) GetMsg() sdk.Msg { return tx }
func (tx testMsg) GetMemo() string { return "" }
func (tx testMsg) GetSignBytes() []byte { return nil }
func (tx testMsg) GetSigners() []sdk.Address { return tx.signers }
func (tx testMsg) GetSignatures() []auth.StdSignature { return nil }
func (tx testMsg) ValidateBasic() sdk.Error {
if tx.positiveNum >= 0 {
return nil
}
return sdk.ErrTxDecode("positiveNum should be a non-negative integer.")
}
// test auth module messages
var (
priv1 = crypto.GenPrivKeyEd25519()
addr1 = priv1.PubKey().Address()
priv2 = crypto.GenPrivKeyEd25519()
addr2 = priv2.PubKey().Address()
coins = sdk.Coins{sdk.NewCoin("foocoin", 10)}
testMsg1 = testMsg{signers: []sdk.Address{addr1}, positiveNum: 1}
)
// initialize the mock application for this module
func getMockApp(t *testing.T) *App {
mapp := NewApp()
mapp.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return })
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{}))
return mapp
}
func TestMsgPrivKeys(t *testing.T) {
mapp := getMockApp(t)
mapp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil)
// Construct some genesis bytes to reflect basecoin/types/AppAccount
// Give 77 foocoin to the first key
coins := sdk.Coins{sdk.NewCoin("foocoin", 77)}
acc1 := &auth.BaseAccount{
Address: addr1,
Coins: coins,
}
accs := []auth.Account{acc1}
// Construct genesis state
SetGenesis(mapp, accs)
// A checkTx context (true)
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
res1 := mapp.AccountMapper.GetAccount(ctxCheck, addr1)
require.Equal(t, acc1, res1.(*auth.BaseAccount))
// Run a CheckDeliver
SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{0}, true, priv1)
// signing a SendMsg with the wrong privKey should be an auth error
mapp.BeginBlock(abci.RequestBeginBlock{})
tx := GenTx([]sdk.Msg{testMsg1}, []int64{0}, []int64{1}, priv2)
res := mapp.Deliver(tx)
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
// resigning the tx with the correct priv key should still work
res = SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{testMsg1}, []int64{0}, []int64{1}, true, priv1)
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeOK), res.Code, res.Log)
}

View File

@ -1,110 +0,0 @@
package mock
import (
"testing"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
abci "github.com/tendermint/tendermint/abci/types"
)
var chainID = "" // TODO
// set the mock app genesis
func SetGenesis(app *App, accs []auth.Account) {
// pass the accounts in via the application (lazy) instead of through RequestInitChain
app.GenesisAccounts = accs
app.InitChain(abci.RequestInitChain{})
app.Commit()
}
// check an account balance
func CheckBalance(t *testing.T, app *App, addr sdk.Address, exp sdk.Coins) {
ctxCheck := app.BaseApp.NewContext(true, abci.Header{})
res := app.AccountMapper.GetAccount(ctxCheck, addr)
require.Equal(t, exp, res.GetCoins())
}
// generate a signed transaction
func GenTx(msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyEd25519) auth.StdTx {
// make the transaction free
fee := auth.StdFee{
sdk.Coins{sdk.NewCoin("foocoin", 0)},
100000,
}
sigs := make([]auth.StdSignature, len(priv))
memo := "testmemotestmemo"
for i, p := range priv {
sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, memo))
if err != nil {
panic(err)
}
sigs[i] = auth.StdSignature{
PubKey: p.PubKey(),
Signature: sig,
AccountNumber: accnums[i],
Sequence: seq[i],
}
}
return auth.NewStdTx(msgs, fee, sigs, memo)
}
// generate a set of signed transactions a msg, that differ only by having the
// sequence numbers incremented between every transaction.
func GenSequenceOfTxs(msgs []sdk.Msg, accnums []int64, initSeqNums []int64, numToGenerate int, priv ...crypto.PrivKeyEd25519) []auth.StdTx {
txs := make([]auth.StdTx, numToGenerate, numToGenerate)
for i := 0; i < numToGenerate; i++ {
txs[i] = GenTx(msgs, accnums, initSeqNums, priv...)
incrementAllSequenceNumbers(initSeqNums)
}
return txs
}
func incrementAllSequenceNumbers(initSeqNums []int64) {
for i := 0; i < len(initSeqNums); i++ {
initSeqNums[i]++
}
}
// check a transaction result
func SignCheck(app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKeyEd25519) sdk.Result {
tx := GenTx(msgs, accnums, seq, priv...)
res := app.Check(tx)
return res
}
// simulate a block
func SignCheckDeliver(t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accnums []int64, seq []int64, expPass bool, priv ...crypto.PrivKeyEd25519) sdk.Result {
// Sign the tx
tx := GenTx(msgs, accnums, seq, priv...)
// Run a Check
res := app.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
app.BeginBlock(abci.RequestBeginBlock{})
res = app.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
app.EndBlock(abci.RequestEndBlock{})
app.Commit()
return res
}

View File

@ -141,7 +141,7 @@ func StdSignBytes(chainID string, accnum int64, sequence int64, fee StdFee, msgs
if err != nil { if err != nil {
panic(err) panic(err)
} }
return bz return sdk.MustSortJSON(bz)
} }
// StdSignMsg is a convenience structure for passing along // StdSignMsg is a convenience structure for passing along

View File

@ -5,9 +5,11 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"math/rand"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/mock"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
@ -81,17 +83,19 @@ func getMockApp(t *testing.T) *mock.App {
return mapp return mapp
} }
// getBenchmarkMockApp initializes a mock application for this module, for purposes of benchmarking func TestBankWithRandomMessages(t *testing.T) {
// Any long term API support commitments do not apply to this function. mapp := getMockApp(t)
func getBenchmarkMockApp() (*mock.App, error) { setup := func(r *rand.Rand, keys []crypto.PrivKey) {
mapp := mock.NewApp() return
}
RegisterWire(mapp.Cdc) mapp.RandomizedTesting(
coinKeeper := NewKeeper(mapp.AccountMapper) t,
mapp.Router().AddRoute("bank", NewHandler(coinKeeper)) []mock.TestAndRunTx{TestAndRunSingleInputMsgSend},
[]mock.RandSetup{setup},
err := mapp.CompleteSetup([]*sdk.KVStoreKey{}) []mock.Invariant{ModuleInvariants},
return mapp, err 100, 30, 30,
)
} }
func TestMsgSendWithAccounts(t *testing.T) { func TestMsgSendWithAccounts(t *testing.T) {

View File

@ -5,11 +5,24 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/mock"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
) )
// getBenchmarkMockApp initializes a mock application for this module, for purposes of benchmarking
// Any long term API support commitments do not apply to this function.
func getBenchmarkMockApp() (*mock.App, error) {
mapp := mock.NewApp()
RegisterWire(mapp.Cdc)
coinKeeper := NewKeeper(mapp.AccountMapper)
mapp.Router().AddRoute("bank", NewHandler(coinKeeper))
err := mapp.CompleteSetup([]*sdk.KVStoreKey{})
return mapp, err
}
func BenchmarkOneBankSendTxPerBlock(b *testing.B) { func BenchmarkOneBankSendTxPerBlock(b *testing.B) {
benchmarkApp, _ := getBenchmarkMockApp() benchmarkApp, _ := getBenchmarkMockApp()

View File

@ -1,25 +1,24 @@
package cli package cli
import ( import (
"fmt" "errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/bank/client" "github.com/cosmos/cosmos-sdk/x/bank/client"
"github.com/spf13/cobra"
"github.com/spf13/viper"
) )
const ( const (
flagTo = "to" flagTo = "to"
flagAmount = "amount" flagAmount = "amount"
flagAsync = "async"
) )
// SendTxCommand will create a send tx and sign it with the given key // SendTxCmd will create a send tx and sign it with the given key
func SendTxCmd(cdc *wire.Codec) *cobra.Command { func SendTxCmd(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "send", Use: "send",
@ -33,35 +32,48 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
return err return err
} }
fromAcc, err := ctx.QueryStore(auth.AddressStoreKey(from), ctx.AccountStore)
if err != nil {
return err
}
bech32From := sdk.MustBech32ifyAcc(from)
// Check if account was found
if fromAcc == nil {
return errors.New("No account with address " + bech32From +
" was found in the state.\nAre you sure there has been a transaction involving it?")
}
toStr := viper.GetString(flagTo) toStr := viper.GetString(flagTo)
to, err := sdk.GetAccAddressBech32(toStr) to, err := sdk.GetAccAddressBech32(toStr)
if err != nil { if err != nil {
return err return err
} }
// parse coins // parse coins trying to be sent
amount := viper.GetString(flagAmount) amount := viper.GetString(flagAmount)
coins, err := sdk.ParseCoins(amount) coins, err := sdk.ParseCoins(amount)
if err != nil { if err != nil {
return err return err
} }
// ensure account has enough coins
account, err := ctx.Decoder(fromAcc)
if err != nil {
return err
}
if !account.GetCoins().IsGTE(coins) {
return errors.New("Address " + bech32From +
" doesn't have enough coins to pay for this transaction.")
}
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
msg := client.BuildMsg(from, to, coins) msg := client.BuildMsg(from, to, coins)
if viper.GetBool(flagAsync) { err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
res, err := ctx.EnsureSignBuildBroadcastAsync(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Println("Async tx sent. tx hash: ", res.Hash.String())
return nil
}
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil {
return err
}
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
@ -69,7 +81,6 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
cmd.Flags().String(flagTo, "", "Address to send coins") cmd.Flags().String(flagTo, "", "Address to send coins")
cmd.Flags().String(flagAmount, "", "Amount of coins to send") cmd.Flags().String(flagAmount, "", "Amount of coins to send")
cmd.Flags().Bool(flagAsync, false, "Pass the async flag to send a tx without waiting for the tx to be included in a block")
return cmd return cmd
} }

View File

@ -72,7 +72,7 @@ func (msg MsgSend) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// Implements Msg. // Implements Msg.
@ -133,7 +133,7 @@ func (msg MsgIssue) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// Implements Msg. // Implements Msg.
@ -162,7 +162,7 @@ func (in Input) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return bin return sdk.MustSortJSON(bin)
} }
// ValidateBasic - validate transaction input // ValidateBasic - validate transaction input
@ -209,7 +209,7 @@ func (out Output) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return bin return sdk.MustSortJSON(bin)
} }
// ValidateBasic - validate transaction output // ValidateBasic - validate transaction output

View File

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

150
x/bank/test_helpers.go Normal file
View File

@ -0,0 +1,150 @@
package bank
import (
"errors"
"fmt"
"math/big"
"math/rand"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/mock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
)
// ModuleInvariants runs all invariants of the bank module.
// Currently runs non-negative balance invariant and TotalCoinsInvariant
func ModuleInvariants(t *testing.T, app *mock.App, log string) {
NonnegativeBalanceInvariant(t, app, log)
TotalCoinsInvariant(t, app, log)
}
// NonnegativeBalanceInvariant checks that all accounts in the application have non-negative balances
func NonnegativeBalanceInvariant(t *testing.T, app *mock.App, log string) {
ctx := app.NewContext(false, abci.Header{})
accts := mock.GetAllAccounts(app.AccountMapper, ctx)
for _, acc := range accts {
coins := acc.GetCoins()
assert.True(t, coins.IsNotNegative(),
fmt.Sprintf("%s has a negative denomination of %s\n%s",
acc.GetAddress().String(),
coins.String(),
log),
)
}
}
// TotalCoinsInvariant checks that the sum of the coins across all accounts
// is what is expected
func TotalCoinsInvariant(t *testing.T, app *mock.App, log string) {
ctx := app.BaseApp.NewContext(false, abci.Header{})
totalCoins := sdk.Coins{}
chkAccount := func(acc auth.Account) bool {
coins := acc.GetCoins()
totalCoins = totalCoins.Plus(coins)
return false
}
app.AccountMapper.IterateAccounts(ctx, chkAccount)
require.Equal(t, app.TotalCoinsSupply, totalCoins, log)
}
// TestAndRunSingleInputMsgSend tests and runs a single msg send, with one input and one output, where both
// accounts already exist.
func TestAndRunSingleInputMsgSend(t *testing.T, r *rand.Rand, app *mock.App, ctx sdk.Context, keys []crypto.PrivKey, log string) (action string, err sdk.Error) {
fromKey := keys[r.Intn(len(keys))]
fromAddr := fromKey.PubKey().Address()
toKey := keys[r.Intn(len(keys))]
// Disallow sending money to yourself
for {
if !fromKey.Equals(toKey) {
break
}
toKey = keys[r.Intn(len(keys))]
}
toAddr := toKey.PubKey().Address()
initFromCoins := app.AccountMapper.GetAccount(ctx, fromAddr).GetCoins()
denomIndex := r.Intn(len(initFromCoins))
amt, goErr := randPositiveInt(r, initFromCoins[denomIndex].Amount)
if goErr != nil {
return "skipping bank send due to account having no coins of denomination " + initFromCoins[denomIndex].Denom, nil
}
action = fmt.Sprintf("%s is sending %s %s to %s",
fromAddr.String(),
amt.String(),
initFromCoins[denomIndex].Denom,
toAddr.String(),
)
log = fmt.Sprintf("%s\n%s", log, action)
coins := sdk.Coins{{initFromCoins[denomIndex].Denom, amt}}
var msg = MsgSend{
Inputs: []Input{NewInput(fromAddr, coins)},
Outputs: []Output{NewOutput(toAddr, coins)},
}
sendAndVerifyMsgSend(t, app, msg, ctx, log, []crypto.PrivKey{fromKey})
return action, nil
}
// Sends and verifies the transition of a msg send. This fails if there are repeated inputs or outputs
func sendAndVerifyMsgSend(t *testing.T, app *mock.App, msg MsgSend, ctx sdk.Context, log string, privkeys []crypto.PrivKey) {
initialInputAddrCoins := make([]sdk.Coins, len(msg.Inputs))
initialOutputAddrCoins := make([]sdk.Coins, len(msg.Outputs))
AccountNumbers := make([]int64, len(msg.Inputs))
SequenceNumbers := make([]int64, len(msg.Inputs))
for i := 0; i < len(msg.Inputs); i++ {
acc := app.AccountMapper.GetAccount(ctx, msg.Inputs[i].Address)
AccountNumbers[i] = acc.GetAccountNumber()
SequenceNumbers[i] = acc.GetSequence()
initialInputAddrCoins[i] = acc.GetCoins()
}
for i := 0; i < len(msg.Outputs); i++ {
acc := app.AccountMapper.GetAccount(ctx, msg.Outputs[i].Address)
initialOutputAddrCoins[i] = acc.GetCoins()
}
tx := mock.GenTx([]sdk.Msg{msg},
AccountNumbers,
SequenceNumbers,
privkeys...)
res := app.Deliver(tx)
if !res.IsOK() {
// TODO: Do this in a more 'canonical' way
fmt.Println(res)
fmt.Println(log)
t.FailNow()
}
for i := 0; i < len(msg.Inputs); i++ {
terminalInputCoins := app.AccountMapper.GetAccount(ctx, msg.Inputs[i].Address).GetCoins()
require.Equal(t,
initialInputAddrCoins[i].Minus(msg.Inputs[i].Coins),
terminalInputCoins,
fmt.Sprintf("Input #%d had an incorrect amount of coins\n%s", i, log),
)
}
for i := 0; i < len(msg.Outputs); i++ {
terminalOutputCoins := app.AccountMapper.GetAccount(ctx, msg.Outputs[i].Address).GetCoins()
require.Equal(t,
initialOutputAddrCoins[i].Plus(msg.Outputs[i].Coins),
terminalOutputCoins,
fmt.Sprintf("Output #%d had an incorrect amount of coins\n%s", i, log),
)
}
}
func randPositiveInt(r *rand.Rand, max sdk.Int) (sdk.Int, error) {
if !max.GT(sdk.OneInt()) {
return sdk.Int{}, errors.New("max too small")
}
max = max.Sub(sdk.OneInt())
return sdk.NewIntFromBigInt(new(big.Int).Rand(r, max.BigInt())).Add(sdk.OneInt()), nil
}

View File

@ -29,7 +29,7 @@ const (
// submit a proposal tx // submit a proposal tx
func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command { func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "submitproposal", Use: "submit-proposal",
Short: "Submit a proposal along with an initial deposit", Short: "Submit a proposal along with an initial deposit",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
title := viper.GetString(flagTitle) title := viper.GetString(flagTitle)
@ -63,13 +63,13 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
// proposalID must be returned, and it is a part of response
ctx.PrintResponse = true
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block:%d. Hash:%s.Response:%+v \n", res.Height, res.Hash.String(), res.DeliverTx)
return nil return nil
}, },
} }
@ -113,11 +113,10 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }
@ -164,11 +163,10 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }

View File

@ -82,7 +82,7 @@ func (msg MsgSubmitProposal) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// Implements Msg. // Implements Msg.
@ -149,7 +149,7 @@ func (msg MsgDeposit) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// Implements Msg. // Implements Msg.
@ -213,7 +213,7 @@ func (msg MsgVote) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// Implements Msg. // Implements Msg.

View File

@ -6,7 +6,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/mock" "github.com/cosmos/cosmos-sdk/x/mock"
) )
var ( var (

View File

@ -12,13 +12,13 @@ import (
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/mock"
"github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/mock"
"github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake"
) )
// initialize the mock application for this module // initialize the mock application for this module
func getMockApp(t *testing.T, numGenAccs int64) (*mock.App, Keeper, stake.Keeper, []sdk.Address, []crypto.PubKey, []crypto.PrivKey) { func getMockApp(t *testing.T, numGenAccs int) (*mock.App, Keeper, stake.Keeper, []sdk.Address, []crypto.PubKey, []crypto.PrivKey) {
mapp := mock.NewApp() mapp := mock.NewApp()
stake.RegisterWire(mapp.Cdc) stake.RegisterWire(mapp.Cdc)

View File

@ -7,8 +7,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock"
"github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/mock"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"

View File

@ -109,7 +109,7 @@ key2 DC26002735D3AA9573707CFA6D77C12349E49868
## Transfer coins (addr1:chain1 -> addr2:chain2) ## Transfer coins (addr1:chain1 -> addr2:chain2)
```console ```console
> basecli transfer --name key1 --to $ADDR2 --amount 10mycoin --chain $ID2 --chain-id $ID1 --node $NODE1 > basecli transfer --from key1 --to $ADDR2 --amount 10mycoin --chain $ID2 --chain-id $ID1 --node $NODE1
Password to sign with 'key1': Password to sign with 'key1':
Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0 Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0
> basecli account $ADDR1 --node $NODE1 > basecli account $ADDR1 --node $NODE1
@ -133,7 +133,7 @@ Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0
## Relay IBC packets ## Relay IBC packets
```console ```console
> basecli relay --name key2 --from-chain-id $ID1 --from-chain-node $NODE1 --to-chain-id $ID2 --to-chain-node $NODE2 --chain-id $ID2 > basecli relay --from key2 --from-chain-id $ID1 --from-chain-node $NODE1 --to-chain-id $ID2 --to-chain-node $NODE2 --chain-id $ID2
Password to sign with 'key2': Password to sign with 'key2':
I[04-03|16:18:59.984] Detected IBC packet number=0 I[04-03|16:18:59.984] Detected IBC packet number=0
I[04-03|16:19:00.869] Relayed IBC packet number=0 I[04-03|16:19:00.869] Relayed IBC packet number=0

View File

@ -2,7 +2,6 @@ package cli
import ( import (
"encoding/hex" "encoding/hex"
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -43,12 +42,10 @@ func IBCTransferCmd(cdc *wire.Codec) *cobra.Command {
} }
// get password // get password
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }

View File

@ -53,6 +53,8 @@ func makeCodec() *wire.Codec {
cdc.RegisterConcrete(&auth.BaseAccount{}, "test/ibc/Account", nil) cdc.RegisterConcrete(&auth.BaseAccount{}, "test/ibc/Account", nil)
wire.RegisterCrypto(cdc) wire.RegisterCrypto(cdc)
cdc.Seal()
return cdc return cdc
} }

View File

@ -59,7 +59,7 @@ func (p IBCPacket) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// validator the ibc packey // validator the ibc packey
@ -131,5 +131,5 @@ func (msg IBCReceiveMsg) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }

237
x/mock/app.go Normal file
View File

@ -0,0 +1,237 @@
package mock
import (
"math/rand"
"os"
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"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
)
const chainID = ""
// App extends an ABCI application, but with most of its parameters exported.
// They are exported for convenience in creating helper functions, as object
// capabilities aren't needed for testing.
type App struct {
*bam.BaseApp
Cdc *wire.Codec // Cdc is public since the codec is passed into the module anyways
KeyMain *sdk.KVStoreKey
KeyAccount *sdk.KVStoreKey
// TODO: Abstract this out from not needing to be auth specifically
AccountMapper auth.AccountMapper
FeeCollectionKeeper auth.FeeCollectionKeeper
GenesisAccounts []auth.Account
TotalCoinsSupply sdk.Coins
}
// NewApp partially constructs a new app on the memstore for module and genesis
// testing.
func NewApp() *App {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).With("module", "sdk/app")
db := dbm.NewMemDB()
// Create the cdc with some standard codecs
cdc := wire.NewCodec()
sdk.RegisterWire(cdc)
wire.RegisterCrypto(cdc)
auth.RegisterWire(cdc)
// Create your application object
app := &App{
BaseApp: bam.NewBaseApp("mock", cdc, logger, db),
Cdc: cdc,
KeyMain: sdk.NewKVStoreKey("main"),
KeyAccount: sdk.NewKVStoreKey("acc"),
TotalCoinsSupply: sdk.Coins{},
}
// Define the accountMapper
app.AccountMapper = auth.NewAccountMapper(
app.Cdc,
app.KeyAccount,
&auth.BaseAccount{},
)
// Initialize the app. The chainers and blockers can be overwritten before
// calling complete setup.
app.SetInitChainer(app.InitChainer)
app.SetAnteHandler(auth.NewAnteHandler(app.AccountMapper, app.FeeCollectionKeeper))
return app
}
// CompleteSetup completes the application setup after the routes have been
// registered.
func (app *App) CompleteSetup(newKeys []*sdk.KVStoreKey) error {
newKeys = append(newKeys, app.KeyMain)
newKeys = append(newKeys, app.KeyAccount)
app.MountStoresIAVL(newKeys...)
err := app.LoadLatestVersion(app.KeyMain)
return err
}
// InitChainer performs custom logic for initialization.
func (app *App) InitChainer(ctx sdk.Context, _ abci.RequestInitChain) abci.ResponseInitChain {
// Load the genesis accounts
for _, genacc := range app.GenesisAccounts {
acc := app.AccountMapper.NewAccountWithAddress(ctx, genacc.GetAddress())
acc.SetCoins(genacc.GetCoins())
app.AccountMapper.SetAccount(ctx, acc)
}
return abci.ResponseInitChain{}
}
// CreateGenAccounts generates genesis accounts loaded with coins, and returns
// their addresses, pubkeys, and privkeys.
func CreateGenAccounts(numAccs int, genCoins sdk.Coins) (genAccs []auth.Account, addrs []sdk.Address, pubKeys []crypto.PubKey, privKeys []crypto.PrivKey) {
for i := 0; i < numAccs; i++ {
privKey := crypto.GenPrivKeyEd25519()
pubKey := privKey.PubKey()
addr := pubKey.Address()
genAcc := &auth.BaseAccount{
Address: addr,
Coins: genCoins,
}
genAccs = append(genAccs, genAcc)
privKeys = append(privKeys, privKey)
pubKeys = append(pubKeys, pubKey)
addrs = append(addrs, addr)
}
return
}
// SetGenesis sets the mock app genesis accounts.
func SetGenesis(app *App, accs []auth.Account) {
// Pass the accounts in via the application (lazy) instead of through
// RequestInitChain.
app.GenesisAccounts = accs
app.InitChain(abci.RequestInitChain{})
app.Commit()
}
// GenTx generates a signed mock transaction.
func GenTx(msgs []sdk.Msg, accnums []int64, seq []int64, priv ...crypto.PrivKey) auth.StdTx {
// Make the transaction free
fee := auth.StdFee{
Amount: sdk.Coins{sdk.NewCoin("foocoin", 0)},
Gas: 100000,
}
sigs := make([]auth.StdSignature, len(priv))
memo := "testmemotestmemo"
for i, p := range priv {
sig, err := p.Sign(auth.StdSignBytes(chainID, accnums[i], seq[i], fee, msgs, memo))
if err != nil {
panic(err)
}
sigs[i] = auth.StdSignature{
PubKey: p.PubKey(),
Signature: sig,
AccountNumber: accnums[i],
Sequence: seq[i],
}
}
return auth.NewStdTx(msgs, fee, sigs, memo)
}
// GeneratePrivKeys generates a total n Ed25519 private keys.
func GeneratePrivKeys(n int) (keys []crypto.PrivKey) {
// TODO: Randomize this between ed25519 and secp256k1
keys = make([]crypto.PrivKey, n, n)
for i := 0; i < n; i++ {
keys[i] = crypto.GenPrivKeyEd25519()
}
return
}
// GeneratePrivKeyAddressPairs generates a total of n private key, address
// pairs.
func GeneratePrivKeyAddressPairs(n int) (keys []crypto.PrivKey, addrs []sdk.Address) {
keys = make([]crypto.PrivKey, n, n)
addrs = make([]sdk.Address, n, n)
for i := 0; i < n; i++ {
keys[i] = crypto.GenPrivKeyEd25519()
addrs[i] = keys[i].PubKey().Address()
}
return
}
// RandomSetGenesis set genesis accounts with random coin values using the
// provided addresses and coin denominations.
func RandomSetGenesis(r *rand.Rand, app *App, addrs []sdk.Address, denoms []string) {
accts := make([]auth.Account, len(addrs), len(addrs))
randCoinIntervals := []BigInterval{
{sdk.NewIntWithDecimal(1, 0), sdk.NewIntWithDecimal(1, 1)},
{sdk.NewIntWithDecimal(1, 2), sdk.NewIntWithDecimal(1, 3)},
{sdk.NewIntWithDecimal(1, 40), sdk.NewIntWithDecimal(1, 50)},
}
for i := 0; i < len(accts); i++ {
coins := make([]sdk.Coin, len(denoms), len(denoms))
// generate a random coin for each denomination
for j := 0; j < len(denoms); j++ {
coins[j] = sdk.Coin{Denom: denoms[j],
Amount: RandFromBigInterval(r, randCoinIntervals),
}
}
app.TotalCoinsSupply = app.TotalCoinsSupply.Plus(coins)
baseAcc := auth.NewBaseAccountWithAddress(addrs[i])
(&baseAcc).SetCoins(coins)
accts[i] = &baseAcc
}
SetGenesis(app, accts)
}
// GetAllAccounts returns all accounts in the accountMapper.
func GetAllAccounts(mapper auth.AccountMapper, ctx sdk.Context) []auth.Account {
accounts := []auth.Account{}
appendAccount := func(acc auth.Account) (stop bool) {
accounts = append(accounts, acc)
return false
}
mapper.IterateAccounts(ctx, appendAccount)
return accounts
}
// GenSequenceOfTxs generates a set of signed transactions of messages, such
// that they differ only by having the sequence numbers incremented between
// every transaction.
func GenSequenceOfTxs(msgs []sdk.Msg, accnums []int64, initSeqNums []int64, numToGenerate int, priv ...crypto.PrivKey) []auth.StdTx {
txs := make([]auth.StdTx, numToGenerate, numToGenerate)
for i := 0; i < numToGenerate; i++ {
txs[i] = GenTx(msgs, accnums, initSeqNums, priv...)
incrementAllSequenceNumbers(initSeqNums)
}
return txs
}
func incrementAllSequenceNumbers(initSeqNums []int64) {
for i := 0; i < len(initSeqNums); i++ {
initSeqNums[i]++
}
}

102
x/mock/app_test.go Normal file
View File

@ -0,0 +1,102 @@
package mock
import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
)
const msgType = "testMsg"
var (
numAccts = 2
genCoins = sdk.Coins{sdk.NewCoin("foocoin", 77)}
accs, addrs, pubKeys, privKeys = CreateGenAccounts(numAccts, genCoins)
)
// testMsg is a mock transaction that has a validation which can fail.
type testMsg struct {
signers []sdk.Address
positiveNum int64
}
func (tx testMsg) Type() string { return msgType }
func (tx testMsg) GetMsg() sdk.Msg { return tx }
func (tx testMsg) GetMemo() string { return "" }
func (tx testMsg) GetSignBytes() []byte { return nil }
func (tx testMsg) GetSigners() []sdk.Address { return tx.signers }
func (tx testMsg) GetSignatures() []auth.StdSignature { return nil }
func (tx testMsg) ValidateBasic() sdk.Error {
if tx.positiveNum >= 0 {
return nil
}
return sdk.ErrTxDecode("positiveNum should be a non-negative integer.")
}
// getMockApp returns an initialized mock application.
func getMockApp(t *testing.T) *App {
mApp := NewApp()
mApp.Router().AddRoute(msgType, func(ctx sdk.Context, msg sdk.Msg) (res sdk.Result) { return })
require.NoError(t, mApp.CompleteSetup([]*sdk.KVStoreKey{}))
return mApp
}
func TestCheckAndDeliverGenTx(t *testing.T) {
mApp := getMockApp(t)
mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil)
SetGenesis(mApp, accs)
ctxCheck := mApp.BaseApp.NewContext(true, abci.Header{})
msg := testMsg{signers: []sdk.Address{addrs[0]}, positiveNum: 1}
acct := mApp.AccountMapper.GetAccount(ctxCheck, addrs[0])
require.Equal(t, accs[0], acct.(*auth.BaseAccount))
SignCheckDeliver(
t, mApp.BaseApp, []sdk.Msg{msg},
[]int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence()},
true, privKeys[0],
)
// Signing a tx with the wrong privKey should result in an auth error
res := SignCheckDeliver(
t, mApp.BaseApp, []sdk.Msg{msg},
[]int64{accs[1].GetAccountNumber()}, []int64{accs[1].GetSequence() + 1},
false, privKeys[1],
)
require.Equal(t, sdk.ToABCICode(sdk.CodespaceRoot, sdk.CodeUnauthorized), res.Code, res.Log)
// Resigning the tx with the correct privKey should result in an OK result
SignCheckDeliver(
t, mApp.BaseApp, []sdk.Msg{msg},
[]int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence() + 1},
true, privKeys[0],
)
}
func TestCheckGenTx(t *testing.T) {
mApp := getMockApp(t)
mApp.Cdc.RegisterConcrete(testMsg{}, "mock/testMsg", nil)
SetGenesis(mApp, accs)
msg1 := testMsg{signers: []sdk.Address{addrs[0]}, positiveNum: 1}
CheckGenTx(
t, mApp.BaseApp, []sdk.Msg{msg1},
[]int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence()},
true, privKeys[0],
)
msg2 := testMsg{signers: []sdk.Address{addrs[0]}, positiveNum: -1}
CheckGenTx(
t, mApp.BaseApp, []sdk.Msg{msg2},
[]int64{accs[0].GetAccountNumber()}, []int64{accs[0].GetSequence()},
false, privKeys[0],
)
}

15
x/mock/doc.go Normal file
View File

@ -0,0 +1,15 @@
/*
Package mock provides functions for creating applications for testing.
This module also features randomized testing, so that various modules can test
that their operations are interoperable.
The intended method of using this randomized testing framework is that every
module provides TestAndRunTx methods for each of its desired methods of fuzzing
its own txs, and it also provides the invariants that it assumes to be true.
You then pick and choose from these tx types and invariants. To pick and choose
these, you first build a mock app with the correct keepers. Then you call the
app.RandomizedTesting method with the set of desired txs, invariants, along
with the setups each module requires.
*/
package mock

View File

@ -0,0 +1,95 @@
package mock
import (
"fmt"
"math/big"
"math/rand"
"testing"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
)
// RandomizedTesting tests application by sending random messages.
func (app *App) RandomizedTesting(
t *testing.T, ops []TestAndRunTx, setups []RandSetup,
invariants []Invariant, numKeys int, numBlocks int, blockSize int,
) {
time := time.Now().UnixNano()
app.RandomizedTestingFromSeed(t, time, ops, setups, invariants, numKeys, numBlocks, blockSize)
}
// RandomizedTestingFromSeed tests an application by running the provided
// operations, testing the provided invariants, but using the provided seed.
func (app *App) RandomizedTestingFromSeed(
t *testing.T, seed int64, ops []TestAndRunTx, setups []RandSetup,
invariants []Invariant, numKeys int, numBlocks int, blockSize int,
) {
log := fmt.Sprintf("Starting SingleModuleTest with randomness created with seed %d", int(seed))
keys, addrs := GeneratePrivKeyAddressPairs(numKeys)
r := rand.New(rand.NewSource(seed))
for i := 0; i < len(setups); i++ {
setups[i](r, keys)
}
RandomSetGenesis(r, app, addrs, []string{"foocoin"})
header := abci.Header{Height: 0}
for i := 0; i < numBlocks; i++ {
app.BeginBlock(abci.RequestBeginBlock{})
// Make sure invariants hold at beginning of block and when nothing was
// done.
app.assertAllInvariants(t, invariants, log)
ctx := app.NewContext(false, header)
// TODO: Add modes to simulate "no load", "medium load", and
// "high load" blocks.
for j := 0; j < blockSize; j++ {
logUpdate, err := ops[r.Intn(len(ops))](t, r, app, ctx, keys, log)
log += "\n" + logUpdate
require.Nil(t, err, log)
app.assertAllInvariants(t, invariants, log)
}
app.EndBlock(abci.RequestEndBlock{})
header.Height++
}
}
func (app *App) assertAllInvariants(t *testing.T, tests []Invariant, log string) {
for i := 0; i < len(tests); i++ {
tests[i](t, app, log)
}
}
// BigInterval is a representation of the interval [lo, hi), where
// lo and hi are both of type sdk.Int
type BigInterval struct {
lo sdk.Int
hi sdk.Int
}
// RandFromBigInterval chooses an interval uniformly from the provided list of
// BigIntervals, and then chooses an element from an interval uniformly at random.
func RandFromBigInterval(r *rand.Rand, intervals []BigInterval) sdk.Int {
if len(intervals) == 0 {
return sdk.ZeroInt()
}
interval := intervals[r.Intn(len(intervals))]
lo := interval.lo
hi := interval.hi
diff := hi.Sub(lo)
result := sdk.NewIntFromBigInt(new(big.Int).Rand(r, diff.BigInt()))
result = result.Add(lo)
return result
}

71
x/mock/test_utils.go Normal file
View File

@ -0,0 +1,71 @@
package mock
import (
"testing"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
)
// CheckBalance checks the balance of an account.
func CheckBalance(t *testing.T, app *App, addr sdk.Address, exp sdk.Coins) {
ctxCheck := app.BaseApp.NewContext(true, abci.Header{})
res := app.AccountMapper.GetAccount(ctxCheck, addr)
require.Equal(t, exp, res.GetCoins())
}
// CheckGenTx checks a generated signed transaction. The result of the check is
// compared against the parameter 'expPass'. A test assertion is made using the
// parameter 'expPass' against the result. A corresponding result is returned.
func CheckGenTx(
t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []int64,
seq []int64, expPass bool, priv ...crypto.PrivKey,
) sdk.Result {
tx := GenTx(msgs, accNums, seq, priv...)
res := app.Check(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
return res
}
// SignCheckDeliver checks a generated signed transaction and simulates a
// block commitment with the given transaction. A test assertion is made using
// the parameter 'expPass' against the result. A corresponding result is
// returned.
func SignCheckDeliver(
t *testing.T, app *baseapp.BaseApp, msgs []sdk.Msg, accNums []int64,
seq []int64, expPass bool, priv ...crypto.PrivKey,
) sdk.Result {
tx := GenTx(msgs, accNums, seq, priv...)
res := app.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 sending a transaction and committing a block
app.BeginBlock(abci.RequestBeginBlock{})
res = app.Deliver(tx)
if expPass {
require.Equal(t, sdk.ABCICodeOK, res.Code, res.Log)
} else {
require.NotEqual(t, sdk.ABCICodeOK, res.Code, res.Log)
}
app.EndBlock(abci.RequestEndBlock{})
app.Commit()
return res
}

38
x/mock/types.go Normal file
View File

@ -0,0 +1,38 @@
package mock
import (
"math/rand"
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tendermint/tendermint/crypto"
)
type (
// TestAndRunTx produces a fuzzed transaction, and ensures the state
// transition was as expected. It returns a descriptive message "action"
// about what this fuzzed tx actually did, for ease of debugging.
TestAndRunTx func(
t *testing.T, r *rand.Rand, app *App, ctx sdk.Context,
privKeys []crypto.PrivKey, log string,
) (action string, err sdk.Error)
// RandSetup performs the random setup the mock module needs.
RandSetup func(r *rand.Rand, privKeys []crypto.PrivKey)
// An Invariant is a function which tests a particular invariant.
// If the invariant has been broken, the function should halt the
// test and output the log.
Invariant func(t *testing.T, app *App, log string)
)
// PeriodicInvariant returns an Invariant function closure that asserts
// a given invariant if the mock application's last block modulo the given
// period is congruent to the given offset.
func PeriodicInvariant(invariant Invariant, period int, offset int) Invariant {
return func(t *testing.T, app *App, log string) {
if int(app.LastBlockHeight())%period == offset {
invariant(t, app, log)
}
}
}

View File

@ -5,11 +5,10 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock"
"github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/bank"
"github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/x/mock"
"github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
) )
@ -103,10 +102,9 @@ func TestSlashingMsgs(t *testing.T) {
require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded())) require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded()))
unrevokeMsg := MsgUnrevoke{ValidatorAddr: validator.PubKey.Address()} unrevokeMsg := MsgUnrevoke{ValidatorAddr: validator.PubKey.Address()}
// no signing info yet
checkValidatorSigningInfo(t, mapp, keeper, addr1, false) checkValidatorSigningInfo(t, mapp, keeper, addr1, false)
// unrevoke should fail with validator not revoked // unrevoke should fail with unknown validator
res := mock.SignCheck(mapp.BaseApp, []sdk.Msg{unrevokeMsg}, []int64{0}, []int64{1}, priv1) res := mock.CheckGenTx(t, mapp.BaseApp, []sdk.Msg{unrevokeMsg}, []int64{0}, []int64{1}, false, priv1)
require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotRevoked), res.Code) require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotRevoked), res.Code)
} }

View File

@ -1,8 +1,6 @@
package cli package cli
import ( import (
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
@ -29,12 +27,10 @@ func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command {
msg := slashing.NewMsgUnrevoke(validatorAddr) msg := slashing.NewMsgUnrevoke(validatorAddr)
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }

View File

@ -15,7 +15,8 @@ func TestCannotUnrevokeUnlessRevoked(t *testing.T) {
slh := NewHandler(keeper) slh := NewHandler(keeper)
amtInt := int64(100) amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt) addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt)) msg := newTestMsgCreateValidator(addr, val, amt)
got := stake.NewHandler(sk)(ctx, msg)
require.True(t, got.IsOK()) require.True(t, got.IsOK())
stake.EndBlocker(ctx, sk) stake.EndBlocker(ctx, sk)
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}}) require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})

View File

@ -38,7 +38,7 @@ func (msg MsgUnrevoke) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// quick validity check // quick validity check

View File

@ -23,16 +23,16 @@ import (
// TODO remove dependencies on staking (should only refer to validator set type from sdk) // TODO remove dependencies on staking (should only refer to validator set type from sdk)
var ( var (
addrs = []sdk.Address{
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"),
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"),
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6162"),
}
pks = []crypto.PubKey{ pks = []crypto.PubKey{
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"),
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"),
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"), newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"),
} }
addrs = []sdk.Address{
pks[0].Address(),
pks[1].Address(),
pks[2].Address(),
}
initCoins sdk.Int = sdk.NewInt(200) initCoins sdk.Int = sdk.NewInt(200)
) )

View File

@ -5,11 +5,9 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/mock"
"github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/bank"
"github.com/stretchr/testify/assert" "github.com/cosmos/cosmos-sdk/x/mock"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
) )
@ -22,81 +20,86 @@ var (
addr3 = crypto.GenPrivKeyEd25519().PubKey().Address() addr3 = crypto.GenPrivKeyEd25519().PubKey().Address()
priv4 = crypto.GenPrivKeyEd25519() priv4 = crypto.GenPrivKeyEd25519()
addr4 = priv4.PubKey().Address() addr4 = priv4.PubKey().Address()
coins = sdk.Coins{{"foocoin", sdk.NewInt(10)}} coins = sdk.NewCoin("foocoin", 10)
fee = auth.StdFee{ fee = auth.StdFee{sdk.Coins{sdk.NewCoin("foocoin", 0)}, 100000}
sdk.Coins{{"foocoin", sdk.NewInt(0)}},
100000,
}
) )
// initialize the mock application for this module // getMockApp returns an initialized mock application for this module.
func getMockApp(t *testing.T) (*mock.App, Keeper) { func getMockApp(t *testing.T) (*mock.App, Keeper) {
mapp := mock.NewApp() mApp := mock.NewApp()
RegisterWire(mApp.Cdc)
RegisterWire(mapp.Cdc)
keyStake := sdk.NewKVStoreKey("stake") keyStake := sdk.NewKVStoreKey("stake")
coinKeeper := bank.NewKeeper(mapp.AccountMapper) coinKeeper := bank.NewKeeper(mApp.AccountMapper)
keeper := NewKeeper(mapp.Cdc, keyStake, coinKeeper, mapp.RegisterCodespace(DefaultCodespace)) keeper := NewKeeper(mApp.Cdc, keyStake, coinKeeper, mApp.RegisterCodespace(DefaultCodespace))
mapp.Router().AddRoute("stake", NewHandler(keeper))
mapp.SetEndBlocker(getEndBlocker(keeper)) mApp.Router().AddRoute("stake", NewHandler(keeper))
mapp.SetInitChainer(getInitChainer(mapp, keeper)) mApp.SetEndBlocker(getEndBlocker(keeper))
mApp.SetInitChainer(getInitChainer(mApp, keeper))
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake})) require.NoError(t, mApp.CompleteSetup([]*sdk.KVStoreKey{keyStake}))
return mapp, keeper return mApp, keeper
} }
// stake endblocker // getEndBlocker returns a stake endblocker.
func getEndBlocker(keeper Keeper) sdk.EndBlocker { func getEndBlocker(keeper Keeper) sdk.EndBlocker {
return func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock { return func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
validatorUpdates := EndBlocker(ctx, keeper) validatorUpdates := EndBlocker(ctx, keeper)
return abci.ResponseEndBlock{ return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates, ValidatorUpdates: validatorUpdates,
} }
} }
} }
// overwrite the mock init chainer // getInitChainer initializes the chainer of the mock app and sets the genesis
// state. It returns an empty ResponseInitChain.
func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
mapp.InitChainer(ctx, req) mapp.InitChainer(ctx, req)
stakeGenesis := DefaultGenesisState() stakeGenesis := DefaultGenesisState()
stakeGenesis.Pool.LooseTokens = 100000 stakeGenesis.Pool.LooseTokens = 100000
InitGenesis(ctx, keeper, stakeGenesis) InitGenesis(ctx, keeper, stakeGenesis)
return abci.ResponseInitChain{} return abci.ResponseInitChain{}
} }
} }
//__________________________________________________________________________________________ func checkValidator(
t *testing.T, mapp *mock.App, keeper Keeper,
func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper, addr sdk.Address, expFound bool,
addr sdk.Address, expFound bool) Validator { ) Validator {
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
validator, found := keeper.GetValidator(ctxCheck, addr1) validator, found := keeper.GetValidator(ctxCheck, addr1)
require.Equal(t, expFound, found) require.Equal(t, expFound, found)
return validator return validator
} }
func checkDelegation(t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr, func checkDelegation(
validatorAddr sdk.Address, expFound bool, expShares sdk.Rat) { t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr,
validatorAddr sdk.Address, expFound bool, expShares sdk.Rat,
) {
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{}) ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr) delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr)
if expFound { if expFound {
require.True(t, found) require.True(t, found)
assert.True(sdk.RatEq(t, expShares, delegation.Shares)) require.True(sdk.RatEq(t, expShares, delegation.Shares))
return return
} }
require.False(t, found) require.False(t, found)
} }
func TestStakeMsgs(t *testing.T) { func TestStakeMsgs(t *testing.T) {
mapp, keeper := getMockApp(t) mApp, keeper := getMockApp(t)
genCoin := sdk.Coin{"steak", sdk.NewInt(42)} genCoin := sdk.NewCoin("steak", 42)
bondCoin := sdk.Coin{"steak", sdk.NewInt(10)} bondCoin := sdk.NewCoin("steak", 10)
acc1 := &auth.BaseAccount{ acc1 := &auth.BaseAccount{
Address: addr1, Address: addr1,
@ -108,56 +111,51 @@ func TestStakeMsgs(t *testing.T) {
} }
accs := []auth.Account{acc1, acc2} accs := []auth.Account{acc1, acc2}
mock.SetGenesis(mapp, accs) mock.SetGenesis(mApp, accs)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin}) mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin})
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin}) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
////////////////////
// Create Validator
// create validator
description := NewDescription("foo_moniker", "", "", "") description := NewDescription("foo_moniker", "", "", "")
createValidatorMsg := NewMsgCreateValidator( createValidatorMsg := NewMsgCreateValidator(
addr1, priv1.PubKey(), bondCoin, description, addr1, priv1.PubKey(), bondCoin, description,
) )
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1)
mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin.Minus(bondCoin)})
mapp.BeginBlock(abci.RequestBeginBlock{})
validator := checkValidator(t, mapp, keeper, addr1, true) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsg}, []int64{0}, []int64{0}, true, priv1)
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin)})
mApp.BeginBlock(abci.RequestBeginBlock{})
validator := checkValidator(t, mApp, keeper, addr1, true)
require.Equal(t, addr1, validator.Owner) require.Equal(t, addr1, validator.Owner)
require.Equal(t, sdk.Bonded, validator.Status()) require.Equal(t, sdk.Bonded, validator.Status())
require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded())) require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded()))
// check the bond that should have been created as well // check the bond that should have been created as well
checkDelegation(t, mapp, keeper, addr1, addr1, true, sdk.NewRat(10)) checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10))
////////////////////
// Edit Validator
// edit the validator
description = NewDescription("bar_moniker", "", "", "") description = NewDescription("bar_moniker", "", "", "")
editValidatorMsg := NewMsgEditValidator(addr1, description) editValidatorMsg := NewMsgEditValidator(addr1, description)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{1}, true, priv1)
validator = checkValidator(t, mapp, keeper, addr1, true) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{editValidatorMsg}, []int64{0}, []int64{1}, true, priv1)
validator = checkValidator(t, mApp, keeper, addr1, true)
require.Equal(t, description, validator.Description) require.Equal(t, description, validator.Description)
//////////////////// // delegate
// Delegate mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin})
delegateMsg := NewMsgDelegate(addr2, addr1, bondCoin) delegateMsg := NewMsgDelegate(addr2, addr1, bondCoin)
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{0}, true, priv2)
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
checkDelegation(t, mapp, keeper, addr2, addr1, true, sdk.NewRat(10))
//////////////////// mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{0}, true, priv2)
// Begin Unbonding mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
checkDelegation(t, mApp, keeper, addr2, addr1, true, sdk.NewRat(10))
// begin unbonding
beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewRat(10)) beginUnbondingMsg := NewMsgBeginUnbonding(addr2, addr1, sdk.NewRat(10))
mock.SignCheckDeliver(t, mapp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{1}, true, priv2) mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{1}, true, priv2)
// delegation should exist anymore // delegation should exist anymore
checkDelegation(t, mapp, keeper, addr2, addr1, false, sdk.Rat{}) checkDelegation(t, mApp, keeper, addr2, addr1, false, sdk.Rat{})
// balance should be the same because bonding not yet complete // balance should be the same because bonding not yet complete
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin.Minus(bondCoin)}) mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
} }

View File

@ -11,6 +11,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
) )
// get the command to query a validator // get the command to query a validator
@ -30,9 +31,10 @@ func GetCmdQueryValidator(storeName string, cdc *wire.Codec) *cobra.Command {
res, err := ctx.QueryStore(key, storeName) res, err := ctx.QueryStore(key, storeName)
if err != nil { if err != nil {
return err return err
} else if len(res) == 0 {
return fmt.Errorf("No validator found with address %s", args[0])
} }
validator := new(stake.Validator) validator := types.MustUnmarshalValidator(cdc, addr, res)
cdc.MustUnmarshalBinary(res, validator)
switch viper.Get(cli.OutputFlag) { switch viper.Get(cli.OutputFlag) {
case "text": case "text":
@ -74,9 +76,9 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command {
// parse out the validators // parse out the validators
var validators []stake.Validator var validators []stake.Validator
for _, KV := range resKVs { for _, kv := range resKVs {
var validator stake.Validator addr := kv.Key[1:]
cdc.MustUnmarshalBinary(KV.Value, &validator) validator := types.MustUnmarshalValidator(cdc, addr, kv.Value)
validators = append(validators, validator) validators = append(validators, validator)
} }
@ -117,12 +119,12 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
return err return err
} }
delAddr, err := sdk.GetValAddressHex(viper.GetString(FlagAddressDelegator)) delAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
if err != nil { if err != nil {
return err return err
} }
key := stake.GetDelegationKey(delAddr, valAddr, cdc) key := stake.GetDelegationKey(delAddr, valAddr)
ctx := context.NewCoreContextFromViper() ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName) res, err := ctx.QueryStore(key, storeName)
if err != nil { if err != nil {
@ -130,7 +132,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
} }
// parse out the delegation // parse out the delegation
delegation := new(stake.Delegation) delegation := types.MustUnmarshalDelegation(cdc, key, res)
switch viper.Get(cli.OutputFlag) { switch viper.Get(cli.OutputFlag) {
case "text": case "text":
@ -140,7 +142,6 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
} }
fmt.Println(resp) fmt.Println(resp)
case "json": case "json":
cdc.MustUnmarshalBinary(res, delegation)
output, err := wire.MarshalJSONIndent(cdc, delegation) output, err := wire.MarshalJSONIndent(cdc, delegation)
if err != nil { if err != nil {
return err return err
@ -169,7 +170,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
if err != nil { if err != nil {
return err return err
} }
key := stake.GetDelegationsKey(delegatorAddr, cdc) key := stake.GetDelegationsKey(delegatorAddr)
ctx := context.NewCoreContextFromViper() ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName) resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
if err != nil { if err != nil {
@ -178,9 +179,8 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
// parse out the validators // parse out the validators
var delegations []stake.Delegation var delegations []stake.Delegation
for _, KV := range resKVs { for _, kv := range resKVs {
var delegation stake.Delegation delegation := types.MustUnmarshalDelegation(cdc, kv.Key, kv.Value)
cdc.MustUnmarshalBinary(KV.Value, &delegation)
delegations = append(delegations, delegation) delegations = append(delegations, delegation)
} }
@ -214,7 +214,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
return err return err
} }
key := stake.GetUBDKey(delAddr, valAddr, cdc) key := stake.GetUBDKey(delAddr, valAddr)
ctx := context.NewCoreContextFromViper() ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName) res, err := ctx.QueryStore(key, storeName)
if err != nil { if err != nil {
@ -222,7 +222,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
} }
// parse out the unbonding delegation // parse out the unbonding delegation
ubd := new(stake.UnbondingDelegation) ubd := types.MustUnmarshalUBD(cdc, key, res)
switch viper.Get(cli.OutputFlag) { switch viper.Get(cli.OutputFlag) {
case "text": case "text":
@ -232,7 +232,6 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
} }
fmt.Println(resp) fmt.Println(resp)
case "json": case "json":
cdc.MustUnmarshalBinary(res, ubd)
output, err := wire.MarshalJSONIndent(cdc, ubd) output, err := wire.MarshalJSONIndent(cdc, ubd)
if err != nil { if err != nil {
return err return err
@ -261,7 +260,7 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C
if err != nil { if err != nil {
return err return err
} }
key := stake.GetUBDsKey(delegatorAddr, cdc) key := stake.GetUBDsKey(delegatorAddr)
ctx := context.NewCoreContextFromViper() ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName) resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
if err != nil { if err != nil {
@ -270,9 +269,8 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C
// parse out the validators // parse out the validators
var ubds []stake.UnbondingDelegation var ubds []stake.UnbondingDelegation
for _, KV := range resKVs { for _, kv := range resKVs {
var ubd stake.UnbondingDelegation ubd := types.MustUnmarshalUBD(cdc, kv.Key, kv.Value)
cdc.MustUnmarshalBinary(KV.Value, &ubd)
ubds = append(ubds, ubd) ubds = append(ubds, ubd)
} }
@ -309,7 +307,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
return err return err
} }
key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr, cdc) key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr)
ctx := context.NewCoreContextFromViper() ctx := context.NewCoreContextFromViper()
res, err := ctx.QueryStore(key, storeName) res, err := ctx.QueryStore(key, storeName)
if err != nil { if err != nil {
@ -317,7 +315,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
} }
// parse out the unbonding delegation // parse out the unbonding delegation
red := new(stake.Redelegation) red := types.MustUnmarshalRED(cdc, key, res)
switch viper.Get(cli.OutputFlag) { switch viper.Get(cli.OutputFlag) {
case "text": case "text":
@ -327,7 +325,6 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
} }
fmt.Println(resp) fmt.Println(resp)
case "json": case "json":
cdc.MustUnmarshalBinary(res, red)
output, err := wire.MarshalJSONIndent(cdc, red) output, err := wire.MarshalJSONIndent(cdc, red)
if err != nil { if err != nil {
return err return err
@ -356,7 +353,7 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command
if err != nil { if err != nil {
return err return err
} }
key := stake.GetREDsKey(delegatorAddr, cdc) key := stake.GetREDsKey(delegatorAddr)
ctx := context.NewCoreContextFromViper() ctx := context.NewCoreContextFromViper()
resKVs, err := ctx.QuerySubspace(cdc, key, storeName) resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
if err != nil { if err != nil {
@ -365,9 +362,8 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command
// parse out the validators // parse out the validators
var reds []stake.Redelegation var reds []stake.Redelegation
for _, KV := range resKVs { for _, kv := range resKVs {
var red stake.Redelegation red := types.MustUnmarshalRED(cdc, kv.Key, kv.Value)
cdc.MustUnmarshalBinary(KV.Value, &red)
reds = append(reds, red) reds = append(reds, red)
} }

View File

@ -53,12 +53,10 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description) msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description)
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }
@ -92,12 +90,11 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }
@ -132,12 +129,11 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }
@ -197,12 +193,11 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }
@ -240,7 +235,7 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent
} }
// make a query to get the existing delegation shares // make a query to get the existing delegation shares
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc) key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
ctx := context.NewCoreContextFromViper() ctx := context.NewCoreContextFromViper()
resQuery, err := ctx.QueryStore(key, storeName) resQuery, err := ctx.QueryStore(key, storeName)
if err != nil { if err != nil {
@ -282,12 +277,11 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }
@ -340,12 +334,11 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }
@ -377,12 +370,11 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint // build and sign the transaction, then broadcast to Tendermint
ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc)) ctx := context.NewCoreContextFromViper().WithDecoder(authcmd.GetAccountDecoder(cdc))
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc) err = ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
if err != nil { if err != nil {
return err return err
} }
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
return nil return nil
}, },
} }

View File

@ -9,7 +9,9 @@ import (
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake"
"github.com/cosmos/cosmos-sdk/x/stake/types"
) )
const storeName = "stake" const storeName = "stake"
@ -60,7 +62,7 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
return return
} }
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc) key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
res, err := ctx.QueryStore(key, storeName) res, err := ctx.QueryStore(key, storeName)
if err != nil { if err != nil {
@ -75,11 +77,10 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
return return
} }
var delegation stake.Delegation delegation, err := types.UnmarshalDelegation(cdc, key, res)
err = cdc.UnmarshalBinary(res, &delegation)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(fmt.Sprintf("couldn't decode delegation. Error: %s", err.Error()))) w.Write([]byte(err.Error()))
return return
} }
@ -117,7 +118,7 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
return return
} }
key := stake.GetUBDKey(delegatorAddr, validatorAddr, cdc) key := stake.GetUBDKey(delegatorAddr, validatorAddr)
res, err := ctx.QueryStore(key, storeName) res, err := ctx.QueryStore(key, storeName)
if err != nil { if err != nil {
@ -132,11 +133,10 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
return return
} }
var ubd stake.UnbondingDelegation ubd, err := types.UnmarshalUBD(cdc, key, res)
err = cdc.UnmarshalBinary(res, &ubd)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode unbonding-delegation. Error: %s", err.Error()))) w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error())))
return return
} }
@ -182,7 +182,7 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
return return
} }
key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr, cdc) key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr)
res, err := ctx.QueryStore(key, storeName) res, err := ctx.QueryStore(key, storeName)
if err != nil { if err != nil {
@ -197,11 +197,10 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
return return
} }
var red stake.Redelegation red, err := types.UnmarshalRED(cdc, key, res)
err = cdc.UnmarshalBinary(res, &red)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode redelegation. Error: %s", err.Error()))) w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error())))
return return
} }
@ -291,15 +290,19 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
// parse out the validators // parse out the validators
validators := make([]StakeValidatorOutput, len(kvs)) validators := make([]StakeValidatorOutput, len(kvs))
for i, kv := range kvs { for i, kv := range kvs {
var validator stake.Validator
var bech32Validator StakeValidatorOutput addr := kv.Key[1:]
err = cdc.UnmarshalBinary(kv.Value, &validator) validator, err := types.UnmarshalValidator(cdc, addr, kv.Value)
if err == nil {
bech32Validator, err = bech32StakeValidatorOutput(validator)
}
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("couldn't decode validator. Error: %s", err.Error()))) w.Write([]byte(fmt.Sprintf("couldn't query unbonding-delegation. Error: %s", err.Error())))
return
}
bech32Validator, err := bech32StakeValidatorOutput(validator)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte(err.Error()))
return return
} }
validators[i] = bech32Validator validators[i] = bech32Validator

View File

@ -1,50 +1,58 @@
package stake package stake
import ( import (
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/cosmos/cosmos-sdk/x/stake/types"
tmtypes "github.com/tendermint/tendermint/types"
) )
// InitGenesis - store genesis parameters // InitGenesis sets the pool and parameters for the provided keeper and
// initializes the IntraTxCounter. For each validator in data, it sets that
// validator in the keeper along with manually setting the indexes. In
// addition, it also sets any delegations found in data. Finally, it updates
// the bonded validators.
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) { func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) {
keeper.SetPool(ctx, data.Pool) keeper.SetPool(ctx, data.Pool)
keeper.SetNewParams(ctx, data.Params) keeper.SetNewParams(ctx, data.Params)
keeper.InitIntraTxCounter(ctx) keeper.InitIntraTxCounter(ctx)
for _, validator := range data.Validators {
// set validator for _, validator := range data.Validators {
keeper.SetValidator(ctx, validator) keeper.SetValidator(ctx, validator)
// manually set indexes for the first time // Manually set indexes for the first time
keeper.SetValidatorByPubKeyIndex(ctx, validator) keeper.SetValidatorByPubKeyIndex(ctx, validator)
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool) keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
if validator.Status() == sdk.Bonded { if validator.Status() == sdk.Bonded {
keeper.SetValidatorBondedIndex(ctx, validator) keeper.SetValidatorBondedIndex(ctx, validator)
} }
} }
for _, bond := range data.Bonds { for _, bond := range data.Bonds {
keeper.SetDelegation(ctx, bond) keeper.SetDelegation(ctx, bond)
} }
keeper.UpdateBondedValidatorsFull(ctx) keeper.UpdateBondedValidatorsFull(ctx)
} }
// WriteGenesis - output genesis parameters // WriteGenesis returns a GenesisState for a given context and keeper. The
// GenesisState will contain the pool, params, validators, and bonds found in
// the keeper.
func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState { func WriteGenesis(ctx sdk.Context, keeper Keeper) types.GenesisState {
pool := keeper.GetPool(ctx) pool := keeper.GetPool(ctx)
params := keeper.GetParams(ctx) params := keeper.GetParams(ctx)
validators := keeper.GetAllValidators(ctx) validators := keeper.GetAllValidators(ctx)
bonds := keeper.GetAllDelegations(ctx) bonds := keeper.GetAllDelegations(ctx)
return types.GenesisState{ return types.GenesisState{
pool, Pool: pool,
params, Params: params,
validators, Validators: validators,
bonds, Bonds: bonds,
} }
} }
// WriteValidators - output current validator set // WriteValidators returns a slice of bonded genesis validators.
func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisValidator) { func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisValidator) {
keeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) { keeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) {
vals = append(vals, tmtypes.GenesisValidator{ vals = append(vals, tmtypes.GenesisValidator{
@ -52,7 +60,9 @@ func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisVali
Power: validator.GetPower().RoundInt64(), Power: validator.GetPower().RoundInt64(),
Name: validator.GetMoniker(), Name: validator.GetMoniker(),
}) })
return false return false
}) })
return return
} }

View File

@ -12,12 +12,13 @@ func (k Keeper) GetDelegation(ctx sdk.Context,
delegatorAddr, validatorAddr sdk.Address) (delegation types.Delegation, found bool) { delegatorAddr, validatorAddr sdk.Address) (delegation types.Delegation, found bool) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
delegatorBytes := store.Get(GetDelegationKey(delegatorAddr, validatorAddr, k.cdc)) key := GetDelegationKey(delegatorAddr, validatorAddr)
if delegatorBytes == nil { value := store.Get(key)
if value == nil {
return delegation, false return delegation, false
} }
k.cdc.MustUnmarshalBinary(delegatorBytes, &delegation) delegation = types.MustUnmarshalDelegation(k.cdc, key, value)
return delegation, true return delegation, true
} }
@ -31,9 +32,7 @@ func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegati
if !iterator.Valid() { if !iterator.Valid() {
break break
} }
bondBytes := iterator.Value() delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
var delegation types.Delegation
k.cdc.MustUnmarshalBinary(bondBytes, &delegation)
delegations = append(delegations, delegation) delegations = append(delegations, delegation)
iterator.Next() iterator.Next()
} }
@ -46,7 +45,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address,
maxRetrieve int16) (delegations []types.Delegation) { maxRetrieve int16) (delegations []types.Delegation) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
delegatorPrefixKey := GetDelegationsKey(delegator, k.cdc) delegatorPrefixKey := GetDelegationsKey(delegator)
iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest
delegations = make([]types.Delegation, maxRetrieve) delegations = make([]types.Delegation, maxRetrieve)
@ -55,9 +54,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address,
if !iterator.Valid() || i > int(maxRetrieve-1) { if !iterator.Valid() || i > int(maxRetrieve-1) {
break break
} }
bondBytes := iterator.Value() delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
var delegation types.Delegation
k.cdc.MustUnmarshalBinary(bondBytes, &delegation)
delegations[i] = delegation delegations[i] = delegation
iterator.Next() iterator.Next()
} }
@ -68,14 +65,14 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address,
// set the delegation // set the delegation
func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) { func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
b := k.cdc.MustMarshalBinary(delegation) b := types.MustMarshalDelegation(k.cdc, delegation)
store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr, k.cdc), b) store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b)
} }
// remove the delegation // remove the delegation
func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) { func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr, k.cdc)) store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr))
} }
//_____________________________________________________________________________________ //_____________________________________________________________________________________
@ -85,51 +82,49 @@ func (k Keeper) GetUnbondingDelegation(ctx sdk.Context,
DelegatorAddr, ValidatorAddr sdk.Address) (ubd types.UnbondingDelegation, found bool) { DelegatorAddr, ValidatorAddr sdk.Address) (ubd types.UnbondingDelegation, found bool) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
ubdKey := GetUBDKey(DelegatorAddr, ValidatorAddr, k.cdc) key := GetUBDKey(DelegatorAddr, ValidatorAddr)
bz := store.Get(ubdKey) value := store.Get(key)
if bz == nil { if value == nil {
return ubd, false return ubd, false
} }
k.cdc.MustUnmarshalBinary(bz, &ubd) ubd = types.MustUnmarshalUBD(k.cdc, key, value)
return ubd, true return ubd, true
} }
// load all unbonding delegations from a particular validator // load all unbonding delegations from a particular validator
func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (unbondingDelegations []types.UnbondingDelegation) { func (k Keeper) GetUnbondingDelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (ubds []types.UnbondingDelegation) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr, k.cdc)) iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr))
i := 0 for {
for ; ; i++ {
if !iterator.Valid() { if !iterator.Valid() {
break break
} }
unbondingKey := iterator.Value() key := GetUBDKeyFromValIndexKey(iterator.Key())
unbondingBytes := store.Get(unbondingKey) value := store.Get(key)
var unbondingDelegation types.UnbondingDelegation ubd := types.MustUnmarshalUBD(k.cdc, key, value)
k.cdc.MustUnmarshalBinary(unbondingBytes, &unbondingDelegation) ubds = append(ubds, ubd)
unbondingDelegations = append(unbondingDelegations, unbondingDelegation)
iterator.Next() iterator.Next()
} }
iterator.Close() iterator.Close()
return unbondingDelegations return ubds
} }
// set the unbonding delegation and associated index // set the unbonding delegation and associated index
func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(ubd) bz := types.MustMarshalUBD(k.cdc, ubd)
ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc) key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr)
store.Set(ubdKey, bz) store.Set(key, bz)
store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc), ubdKey) store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) // index, store empty bytes
} }
// remove the unbonding delegation object and associated index // remove the unbonding delegation object and associated index
func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) { func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc) key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr)
store.Delete(ubdKey) store.Delete(key)
store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc)) store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr))
} }
//_____________________________________________________________________________________ //_____________________________________________________________________________________
@ -139,34 +134,32 @@ func (k Keeper) GetRedelegation(ctx sdk.Context,
DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr sdk.Address) (red types.Redelegation, found bool) { DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr sdk.Address) (red types.Redelegation, found bool) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
redKey := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr, k.cdc) key := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr)
bz := store.Get(redKey) value := store.Get(key)
if bz == nil { if value == nil {
return red, false return red, false
} }
k.cdc.MustUnmarshalBinary(bz, &red) red = types.MustUnmarshalRED(k.cdc, key, value)
return red, true return red, true
} }
// load all redelegations from a particular validator // load all redelegations from a particular validator
func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (redelegations []types.Redelegation) { func (k Keeper) GetRedelegationsFromValidator(ctx sdk.Context, valAddr sdk.Address) (reds []types.Redelegation) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr, k.cdc)) iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr))
i := 0 for {
for ; ; i++ {
if !iterator.Valid() { if !iterator.Valid() {
break break
} }
redelegationKey := iterator.Value() key := GetREDKeyFromValSrcIndexKey(iterator.Key())
redelegationBytes := store.Get(redelegationKey) value := store.Get(key)
var redelegation types.Redelegation red := types.MustUnmarshalRED(k.cdc, key, value)
k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation) reds = append(reds, red)
redelegations = append(redelegations, redelegation)
iterator.Next() iterator.Next()
} }
iterator.Close() iterator.Close()
return redelegations return reds
} }
// has a redelegation // has a redelegation
@ -174,7 +167,7 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context,
DelegatorAddr, ValidatorDstAddr sdk.Address) bool { DelegatorAddr, ValidatorDstAddr sdk.Address) bool {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr, k.cdc) prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr)
iterator := sdk.KVStorePrefixIterator(store, prefix) //smallest to largest iterator := sdk.KVStorePrefixIterator(store, prefix) //smallest to largest
found := false found := false
@ -189,20 +182,20 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context,
// set a redelegation and associated index // set a redelegation and associated index
func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) { func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(red) bz := types.MustMarshalRED(k.cdc, red)
redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc) key := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)
store.Set(redKey, bz) store.Set(key, bz)
store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey) store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{})
store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey) store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{})
} }
// remove a redelegation object and associated index // remove a redelegation object and associated index
func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) { func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc) redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)
store.Delete(redKey) store.Delete(redKey)
store.Delete(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc)) store.Delete(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr))
store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc)) store.Delete(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr))
} }
//_____________________________________________________________________________________ //_____________________________________________________________________________________

View File

@ -179,6 +179,36 @@ func TestUnbondDelegation(t *testing.T) {
require.Equal(t, int64(4), pool.BondedTokens) require.Equal(t, int64(4), pool.BondedTokens)
} }
// Make sure that that the retrieving the delegations doesn't affect the state
func TestGetRedelegationsFromValidator(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 0)
rd := types.Redelegation{
DelegatorAddr: addrDels[0],
ValidatorSrcAddr: addrVals[0],
ValidatorDstAddr: addrVals[1],
CreationHeight: 0,
MinTime: 0,
SharesSrc: sdk.NewRat(5),
SharesDst: sdk.NewRat(5),
}
// set and retrieve a record
keeper.SetRedelegation(ctx, rd)
resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.True(t, found)
// get the redelegations one time
redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
require.Equal(t, 1, len(redelegations))
require.True(t, redelegations[0].Equal(resBond))
// get the redelegations a second time, should be exactly the same
redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
require.Equal(t, 1, len(redelegations))
require.True(t, redelegations[0].Equal(resBond))
}
// tests Get/Set/Remove/Has UnbondingDelegation // tests Get/Set/Remove/Has UnbondingDelegation
func TestRedelegation(t *testing.T) { func TestRedelegation(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 0) ctx, _, keeper := CreateTestInput(t, false, 0)
@ -201,7 +231,10 @@ func TestRedelegation(t *testing.T) {
keeper.SetRedelegation(ctx, rd) keeper.SetRedelegation(ctx, rd)
resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.True(t, found) require.True(t, found)
require.True(t, rd.Equal(resBond))
redelegations := keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
require.Equal(t, 1, len(redelegations))
require.True(t, redelegations[0].Equal(resBond))
// check if has the redelegation // check if has the redelegation
has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1]) has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1])
@ -211,10 +244,15 @@ func TestRedelegation(t *testing.T) {
rd.SharesSrc = sdk.NewRat(21) rd.SharesSrc = sdk.NewRat(21)
rd.SharesDst = sdk.NewRat(21) rd.SharesDst = sdk.NewRat(21)
keeper.SetRedelegation(ctx, rd) keeper.SetRedelegation(ctx, rd)
resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
require.True(t, found) require.True(t, found)
require.True(t, rd.Equal(resBond)) require.True(t, rd.Equal(resBond))
redelegations = keeper.GetRedelegationsFromValidator(ctx, addrVals[0])
require.Equal(t, 1, len(redelegations))
require.True(t, redelegations[0].Equal(resBond))
// delete a record // delete a record
keeper.RemoveRedelegation(ctx, rd) keeper.RemoveRedelegation(ctx, rd)
_, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1]) _, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])

View File

@ -6,7 +6,6 @@ import (
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/cosmos/cosmos-sdk/x/stake/types"
) )
@ -29,41 +28,49 @@ var (
UnbondingDelegationKey = []byte{0x0B} // key for an unbonding-delegation UnbondingDelegationKey = []byte{0x0B} // key for an unbonding-delegation
UnbondingDelegationByValIndexKey = []byte{0x0C} // prefix for each key for an unbonding-delegation, by validator owner UnbondingDelegationByValIndexKey = []byte{0x0C} // prefix for each key for an unbonding-delegation, by validator owner
RedelegationKey = []byte{0x0D} // key for a redelegation RedelegationKey = []byte{0x0D} // key for a redelegation
RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by validator owner RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by source validator owner
RedelegationByValDstIndexKey = []byte{0x0F} // prefix for each key for an redelegation, by validator owner RedelegationByValDstIndexKey = []byte{0x0F} // prefix for each key for an redelegation, by destination validator owner
) )
const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
// get the key for the validator with address // get the key for the validator with address.
// VALUE: stake/types.Validator
func GetValidatorKey(ownerAddr sdk.Address) []byte { func GetValidatorKey(ownerAddr sdk.Address) []byte {
return append(ValidatorsKey, ownerAddr.Bytes()...) return append(ValidatorsKey, ownerAddr.Bytes()...)
} }
// get the key for the validator with pubkey // get the key for the validator with pubkey.
// VALUE: validator owner address ([]byte)
func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte { func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte {
return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...) return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...)
} }
// get the key for the current validator group, ordered like tendermint // get the key for the current validator group
// VALUE: none (key rearrangement with GetValKeyFromValBondedIndexKey)
func GetValidatorsBondedIndexKey(ownerAddr sdk.Address) []byte { func GetValidatorsBondedIndexKey(ownerAddr sdk.Address) []byte {
return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...) return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...)
} }
// get the power which is the key for the validator used in the power-store // Get the validator owner address from ValBondedIndexKey
func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte { func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte {
return IndexKey[1:] // remove prefix bytes
// NOTE the address doesn't need to be stored because counter bytes must always be different
return GetValidatorPowerRank(validator, pool)
} }
// get the power of a validator // get the validator by power index. power index is the key used in the power-store,
func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte { // and represents the relative power ranking of the validator.
// VALUE: validator owner address ([]byte)
func GetValidatorsByPowerIndexKey(validator types.Validator, pool types.Pool) []byte {
// NOTE the address doesn't need to be stored because counter bytes must always be different
return getValidatorPowerRank(validator, pool)
}
// get the power ranking of a validator
func getValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
power := validator.EquivalentBondedShares(pool) power := validator.EquivalentBondedShares(pool)
powerBytes := []byte(power.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first) powerBytes := []byte(power.ToLeftPadded(maxDigitsForAccount)) // power big-endian (more powerful validators first)
// TODO ensure that the key will be a readable string.. probably should add seperators and have
revokedBytes := make([]byte, 1) revokedBytes := make([]byte, 1)
if validator.Revoked { if validator.Revoked {
revokedBytes[0] = byte(0x01) revokedBytes[0] = byte(0x01)
@ -71,127 +78,162 @@ func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
revokedBytes[0] = byte(0x00) revokedBytes[0] = byte(0x00)
} }
// TODO ensure that the key will be a readable string.. probably should add seperators and have
// heightBytes and counterBytes represent strings like powerBytes does // heightBytes and counterBytes represent strings like powerBytes does
heightBytes := make([]byte, binary.MaxVarintLen64) heightBytes := make([]byte, binary.MaxVarintLen64)
binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first) binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first)
counterBytes := make([]byte, 2) counterBytes := make([]byte, 2)
binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority) binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority)
return append(ValidatorsByPowerIndexKey, return append(append(append(append(
append(revokedBytes, ValidatorsByPowerIndexKey,
append(powerBytes, revokedBytes...),
append(heightBytes, counterBytes...)...)...)...) powerBytes...),
heightBytes...),
counterBytes...)
} }
// get the key for the accumulated update validators // get the key for the accumulated update validators.
// VALUE: abci.Validator
// note records using these keys should never persist between blocks
func GetTendermintUpdatesKey(ownerAddr sdk.Address) []byte { func GetTendermintUpdatesKey(ownerAddr sdk.Address) []byte {
return append(TendermintUpdatesKey, ownerAddr.Bytes()...) return append(TendermintUpdatesKey, ownerAddr.Bytes()...)
} }
//________________________________________________________________________________ //________________________________________________________________________________
// get the key for delegator bond with validator // get the key for delegator bond with validator.
func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { // VALUE: stake/types.Delegation
return append(GetDelegationsKey(delegatorAddr, cdc), validatorAddr.Bytes()...) func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address) []byte {
return append(GetDelegationsKey(delegatorAddr), validatorAddr.Bytes()...)
} }
// get the prefix for a delegator for all validators // get the prefix for a delegator for all validators
func GetDelegationsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { func GetDelegationsKey(delegatorAddr sdk.Address) []byte {
res := cdc.MustMarshalBinary(&delegatorAddr) return append(DelegationKey, delegatorAddr.Bytes()...)
return append(DelegationKey, res...)
} }
//________________________________________________________________________________ //________________________________________________________________________________
// get the key for an unbonding delegation // get the key for an unbonding delegation by delegator and validator addr.
func GetUBDKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { // VALUE: stake/types.UnbondingDelegation
return append(GetUBDsKey(delegatorAddr, cdc), validatorAddr.Bytes()...) func GetUBDKey(delegatorAddr, validatorAddr sdk.Address) []byte {
return append(
GetUBDsKey(delegatorAddr.Bytes()),
validatorAddr.Bytes()...)
} }
// get the index-key for an unbonding delegation, stored by validator-index // get the index-key for an unbonding delegation, stored by validator-index
func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte { // VALUE: none (key rearrangement used)
return append(GetUBDsByValIndexKey(validatorAddr, cdc), delegatorAddr.Bytes()...) func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address) []byte {
return append(GetUBDsByValIndexKey(validatorAddr), delegatorAddr.Bytes()...)
}
// rearrange the ValIndexKey to get the UBDKey
func GetUBDKeyFromValIndexKey(IndexKey []byte) []byte {
addrs := IndexKey[1:] // remove prefix bytes
if len(addrs) != 2*sdk.AddrLen {
panic("unexpected key length")
}
valAddr := addrs[:sdk.AddrLen]
delAddr := addrs[sdk.AddrLen:]
return GetUBDKey(delAddr, valAddr)
} }
//______________ //______________
// get the prefix for all unbonding delegations from a delegator // get the prefix for all unbonding delegations from a delegator
func GetUBDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { func GetUBDsKey(delegatorAddr sdk.Address) []byte {
res := cdc.MustMarshalBinary(&delegatorAddr) return append(UnbondingDelegationKey, delegatorAddr.Bytes()...)
return append(UnbondingDelegationKey, res...)
} }
// get the prefix keyspace for the indexs of unbonding delegations for a validator // get the prefix keyspace for the indexes of unbonding delegations for a validator
func GetUBDsByValIndexKey(validatorAddr sdk.Address, cdc *wire.Codec) []byte { func GetUBDsByValIndexKey(validatorAddr sdk.Address) []byte {
res := cdc.MustMarshalBinary(&validatorAddr) return append(UnbondingDelegationByValIndexKey, validatorAddr.Bytes()...)
return append(UnbondingDelegationByValIndexKey, res...)
} }
//________________________________________________________________________________ //________________________________________________________________________________
// get the key for a redelegation // get the key for a redelegation
// VALUE: stake/types.RedelegationKey
func GetREDKey(delegatorAddr, validatorSrcAddr, func GetREDKey(delegatorAddr, validatorSrcAddr,
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { validatorDstAddr sdk.Address) []byte {
return append( return append(append(
GetREDsKey(delegatorAddr, cdc), GetREDsKey(delegatorAddr.Bytes()),
append( validatorSrcAddr.Bytes()...),
validatorSrcAddr.Bytes(), validatorDstAddr.Bytes()...)
validatorDstAddr.Bytes()...)...,
)
} }
// get the index-key for a redelegation, stored by source-validator-index // get the index-key for a redelegation, stored by source-validator-index
// VALUE: none (key rearrangement used)
func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr, func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr,
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { validatorDstAddr sdk.Address) []byte {
return append( return append(append(
GetREDsFromValSrcIndexKey(validatorSrcAddr, cdc), GetREDsFromValSrcIndexKey(validatorSrcAddr),
append( delegatorAddr.Bytes()...),
delegatorAddr.Bytes(), validatorDstAddr.Bytes()...)
validatorDstAddr.Bytes()...)...,
)
} }
// get the index-key for a redelegation, stored by destination-validator-index // get the index-key for a redelegation, stored by destination-validator-index
// VALUE: none (key rearrangement used)
func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr, func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr,
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { validatorDstAddr sdk.Address) []byte {
return append( return append(append(
GetREDsToValDstIndexKey(validatorDstAddr, cdc), GetREDsToValDstIndexKey(validatorDstAddr),
append( delegatorAddr.Bytes()...),
delegatorAddr.Bytes(), validatorSrcAddr.Bytes()...)
validatorSrcAddr.Bytes()...)..., }
)
// rearrange the ValSrcIndexKey to get the REDKey
func GetREDKeyFromValSrcIndexKey(IndexKey []byte) []byte {
addrs := IndexKey[1:] // remove prefix bytes
if len(addrs) != 3*sdk.AddrLen {
panic("unexpected key length")
}
valSrcAddr := addrs[:sdk.AddrLen]
delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen]
valDstAddr := addrs[2*sdk.AddrLen:]
return GetREDKey(delAddr, valSrcAddr, valDstAddr)
}
// rearrange the ValDstIndexKey to get the REDKey
func GetREDKeyFromValDstIndexKey(IndexKey []byte) []byte {
addrs := IndexKey[1:] // remove prefix bytes
if len(addrs) != 3*sdk.AddrLen {
panic("unexpected key length")
}
valDstAddr := addrs[:sdk.AddrLen]
delAddr := addrs[sdk.AddrLen : 2*sdk.AddrLen]
valSrcAddr := addrs[2*sdk.AddrLen:]
return GetREDKey(delAddr, valSrcAddr, valDstAddr)
} }
//______________ //______________
// get the prefix keyspace for redelegations from a delegator // get the prefix keyspace for redelegations from a delegator
func GetREDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte { func GetREDsKey(delegatorAddr sdk.Address) []byte {
res := cdc.MustMarshalBinary(&delegatorAddr) return append(RedelegationKey, delegatorAddr.Bytes()...)
return append(RedelegationKey, res...)
} }
// get the prefix keyspace for all redelegations redelegating away from a source validator // get the prefix keyspace for all redelegations redelegating away from a source validator
func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address, cdc *wire.Codec) []byte { func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address) []byte {
res := cdc.MustMarshalBinary(&validatorSrcAddr) return append(RedelegationByValSrcIndexKey, validatorSrcAddr.Bytes()...)
return append(RedelegationByValSrcIndexKey, res...)
} }
// get the prefix keyspace for all redelegations redelegating towards a destination validator // get the prefix keyspace for all redelegations redelegating towards a destination validator
func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address) []byte {
res := cdc.MustMarshalBinary(&validatorDstAddr) return append(RedelegationByValDstIndexKey, validatorDstAddr.Bytes()...)
return append(RedelegationByValDstIndexKey, res...)
} }
// get the prefix keyspace for all redelegations redelegating towards a destination validator // get the prefix keyspace for all redelegations redelegating towards a destination validator
// from a particular delegator // from a particular delegator
func GetREDsByDelToValDstIndexKey(delegatorAddr sdk.Address, func GetREDsByDelToValDstIndexKey(delegatorAddr sdk.Address,
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte { validatorDstAddr sdk.Address) []byte {
return append( return append(
GetREDsToValDstIndexKey(validatorDstAddr, cdc), GetREDsToValDstIndexKey(validatorDstAddr),
delegatorAddr.Bytes()...) delegatorAddr.Bytes()...)
} }

View File

@ -16,9 +16,8 @@ func (k Keeper) IterateValidators(ctx sdk.Context, fn func(index int64, validato
iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey) iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey)
i := int64(0) i := int64(0)
for ; iterator.Valid(); iterator.Next() { for ; iterator.Valid(); iterator.Next() {
bz := iterator.Value() addr := iterator.Key()[1:]
var validator types.Validator validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
k.cdc.MustUnmarshalBinary(bz, &validator)
stop := fn(i, validator) // XXX is this safe will the validator unexposed fields be able to get written to? stop := fn(i, validator) // XXX is this safe will the validator unexposed fields be able to get written to?
if stop { if stop {
break break
@ -34,7 +33,7 @@ func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, va
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
i := int64(0) i := int64(0)
for ; iterator.Valid(); iterator.Next() { for ; iterator.Valid(); iterator.Next() {
address := iterator.Value() address := GetAddressFromValBondedIndexKey(iterator.Key())
validator, found := k.GetValidator(ctx, address) validator, found := k.GetValidator(ctx, address)
if !found { if !found {
panic(fmt.Sprintf("validator record not found for address: %v\n", address)) panic(fmt.Sprintf("validator record not found for address: %v\n", address))
@ -87,13 +86,11 @@ func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.Address, addrVal sdk.Add
// iterate through the active validator set and perform the provided function // iterate through the active validator set and perform the provided function
func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.Address, fn func(index int64, delegation sdk.Delegation) (stop bool)) { func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.Address, fn func(index int64, delegation sdk.Delegation) (stop bool)) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
key := GetDelegationsKey(delAddr, k.cdc) key := GetDelegationsKey(delAddr)
iterator := sdk.KVStorePrefixIterator(store, key) iterator := sdk.KVStorePrefixIterator(store, key)
i := int64(0) i := int64(0)
for ; iterator.Valid(); iterator.Next() { for ; iterator.Valid(); iterator.Next() {
bz := iterator.Value() delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
var delegation types.Delegation
k.cdc.MustUnmarshalBinary(bz, &delegation)
stop := fn(i, delegation) // XXX is this safe will the fields be able to get written to? stop := fn(i, delegation) // XXX is this safe will the fields be able to get written to?
if stop { if stop {
break break

View File

@ -14,11 +14,11 @@ import (
// get a single validator // get a single validator
func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator types.Validator, found bool) { func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator types.Validator, found bool) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
b := store.Get(GetValidatorKey(addr)) value := store.Get(GetValidatorKey(addr))
if b == nil { if value == nil {
return validator, false return validator, false
} }
k.cdc.MustUnmarshalBinary(b, &validator) validator = types.MustUnmarshalValidator(k.cdc, addr, value)
return validator, true return validator, true
} }
@ -35,15 +35,13 @@ func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (val
// set the main record holding validator details // set the main record holding validator details
func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) { func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
// set main store bz := types.MustMarshalValidator(k.cdc, validator)
bz := k.cdc.MustMarshalBinary(validator)
store.Set(GetValidatorKey(validator.Owner), bz) store.Set(GetValidatorKey(validator.Owner), bz)
} }
// validator index // validator index
func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) { func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
// set pointer by pubkey
store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner) store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner)
} }
@ -56,7 +54,7 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida
// validator index // validator index
func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) { func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner) store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{})
} }
// used in testing // used in testing
@ -75,9 +73,8 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator)
if !iterator.Valid() { if !iterator.Valid() {
break break
} }
bz := iterator.Value() addr := iterator.Key()[1:]
var validator types.Validator validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
k.cdc.MustUnmarshalBinary(bz, &validator)
validators = append(validators, validator) validators = append(validators, validator)
iterator.Next() iterator.Next()
} }
@ -96,9 +93,8 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators []
if !iterator.Valid() || i > int(maxRetrieve-1) { if !iterator.Valid() || i > int(maxRetrieve-1) {
break break
} }
bz := iterator.Value() addr := iterator.Key()[1:]
var validator types.Validator validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
k.cdc.MustUnmarshalBinary(bz, &validator)
validators[i] = validator validators[i] = validator
iterator.Next() iterator.Next()
} }
@ -124,7 +120,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat
if i > int(maxValidators-1) { if i > int(maxValidators-1) {
panic("maxValidators is less than the number of records in ValidatorsBonded Store, store should have been updated") panic("maxValidators is less than the number of records in ValidatorsBonded Store, store should have been updated")
} }
address := iterator.Value() address := GetAddressFromValBondedIndexKey(iterator.Key())
validator, found := k.GetValidator(ctx, address) validator, found := k.GetValidator(ctx, address)
if !found { if !found {
panic(fmt.Sprintf("validator record not found for address: %v\n", address)) panic(fmt.Sprintf("validator record not found for address: %v\n", address))
@ -205,8 +201,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
// always update the main list ordered by owner address before exiting // always update the main list ordered by owner address before exiting
defer func() { defer func() {
bz := k.cdc.MustMarshalBinary(validator) k.SetValidator(ctx, validator)
store.Set(GetValidatorKey(ownerAddr), bz)
}() }()
// retrieve the old validator record // retrieve the old validator record
@ -266,6 +261,13 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
if updatedVal.Owner != nil { // updates to validator occurred to be updated if updatedVal.Owner != nil { // updates to validator occurred to be updated
validator = updatedVal validator = updatedVal
} }
// if decreased in power but still bonded, update Tendermint validator
// (if updatedVal is set, the validator has changed bonding status)
stillBonded := oldFound && oldValidator.Status() == sdk.Bonded && updatedVal.Owner == nil
if stillBonded && oldValidator.PoolShares.Bonded().GT(validator.PoolShares.Bonded()) {
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
store.Set(GetTendermintUpdatesKey(ownerAddr), bz)
}
return validator return validator
} }
@ -388,7 +390,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) {
toKickOut := make(map[string]byte) toKickOut := make(map[string]byte)
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey) iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
for ; iterator.Valid(); iterator.Next() { for ; iterator.Valid(); iterator.Next() {
ownerAddr := iterator.Value() ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key())
toKickOut[string(ownerAddr)] = 0 // set anything toKickOut[string(ownerAddr)] = 0 // set anything
} }
iterator.Close() iterator.Close()
@ -465,8 +467,7 @@ func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) type
k.SetPool(ctx, pool) k.SetPool(ctx, pool)
// save the now unbonded validator record // save the now unbonded validator record
bzVal := k.cdc.MustMarshalBinary(validator) k.SetValidator(ctx, validator)
store.Set(GetValidatorKey(validator.Owner), bzVal)
// add to accumulated changes for tendermint // add to accumulated changes for tendermint
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero()) bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero())
@ -493,9 +494,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
k.SetPool(ctx, pool) k.SetPool(ctx, pool)
// save the now bonded validator record to the three referenced stores // save the now bonded validator record to the three referenced stores
bzVal := k.cdc.MustMarshalBinary(validator) k.SetValidator(ctx, validator)
store.Set(GetValidatorKey(validator.Owner), bzVal) store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{})
store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner)
// add to accumulated changes for tendermint // add to accumulated changes for tendermint
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator()) bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator())

View File

@ -675,3 +675,43 @@ func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) {
require.Equal(t, validators[0].ABCIValidatorZero(), updates[0]) require.Equal(t, validators[0].ABCIValidatorZero(), updates[0])
require.Equal(t, validators[2].ABCIValidator(), updates[1]) require.Equal(t, validators[2].ABCIValidator(), updates[1])
} }
func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
amts := []int64{100, 100}
var validators [2]types.Validator
for i, amt := range amts {
pool := keeper.GetPool(ctx)
validators[i] = types.NewValidator(Addrs[i], PKs[i], types.Description{})
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, amt)
keeper.SetPool(ctx, pool)
}
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
// check initial power
require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[0].GetPower().RoundInt64())
require.Equal(t, sdk.NewRat(100).RoundInt64(), validators[1].GetPower().RoundInt64())
// test multiple value change
// tendermintUpdate set: {c1, c3} -> {c1', c3'}
pool := keeper.GetPool(ctx)
validators[0], pool, _ = validators[0].RemoveDelShares(pool, sdk.NewRat(20))
validators[1], pool, _ = validators[1].RemoveDelShares(pool, sdk.NewRat(30))
keeper.SetPool(ctx, pool)
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
// power has changed
require.Equal(t, sdk.NewRat(80).RoundInt64(), validators[0].GetPower().RoundInt64())
require.Equal(t, sdk.NewRat(70).RoundInt64(), validators[1].GetPower().RoundInt64())
// Tendermint updates should reflect power change
updates := keeper.GetTendermintUpdates(ctx)
require.Equal(t, 2, len(updates))
require.Equal(t, validators[0].ABCIValidator(), updates[0])
require.Equal(t, validators[1].ABCIValidator(), updates[1])
}

View File

@ -7,30 +7,29 @@ import (
"github.com/cosmos/cosmos-sdk/x/stake/types" "github.com/cosmos/cosmos-sdk/x/stake/types"
) )
// keeper type (
type Keeper = keeper.Keeper Keeper = keeper.Keeper
Validator = types.Validator
var NewKeeper = keeper.NewKeeper Description = types.Description
Delegation = types.Delegation
// types UnbondingDelegation = types.UnbondingDelegation
type Validator = types.Validator Redelegation = types.Redelegation
type Description = types.Description Params = types.Params
type Delegation = types.Delegation Pool = types.Pool
type UnbondingDelegation = types.UnbondingDelegation PoolShares = types.PoolShares
type Redelegation = types.Redelegation MsgCreateValidator = types.MsgCreateValidator
type Params = types.Params MsgEditValidator = types.MsgEditValidator
type Pool = types.Pool MsgDelegate = types.MsgDelegate
type PoolShares = types.PoolShares MsgBeginUnbonding = types.MsgBeginUnbonding
type MsgCreateValidator = types.MsgCreateValidator MsgCompleteUnbonding = types.MsgCompleteUnbonding
type MsgEditValidator = types.MsgEditValidator MsgBeginRedelegate = types.MsgBeginRedelegate
type MsgDelegate = types.MsgDelegate MsgCompleteRedelegate = types.MsgCompleteRedelegate
type MsgBeginUnbonding = types.MsgBeginUnbonding GenesisState = types.GenesisState
type MsgCompleteUnbonding = types.MsgCompleteUnbonding )
type MsgBeginRedelegate = types.MsgBeginRedelegate
type MsgCompleteRedelegate = types.MsgCompleteRedelegate
type GenesisState = types.GenesisState
var ( var (
NewKeeper = keeper.NewKeeper
GetValidatorKey = keeper.GetValidatorKey GetValidatorKey = keeper.GetValidatorKey
GetValidatorByPubKeyIndexKey = keeper.GetValidatorByPubKeyIndexKey GetValidatorByPubKeyIndexKey = keeper.GetValidatorByPubKeyIndexKey
GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey
@ -72,7 +71,6 @@ var (
DefaultGenesisState = types.DefaultGenesisState DefaultGenesisState = types.DefaultGenesisState
RegisterWire = types.RegisterWire RegisterWire = types.RegisterWire
// messages
NewMsgCreateValidator = types.NewMsgCreateValidator NewMsgCreateValidator = types.NewMsgCreateValidator
NewMsgEditValidator = types.NewMsgEditValidator NewMsgEditValidator = types.NewMsgEditValidator
NewMsgDelegate = types.NewMsgDelegate NewMsgDelegate = types.NewMsgDelegate
@ -82,7 +80,6 @@ var (
NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate
) )
// errors
const ( const (
DefaultCodespace = types.DefaultCodespace DefaultCodespace = types.DefaultCodespace
CodeInvalidValidator = types.CodeInvalidValidator CodeInvalidValidator = types.CodeInvalidValidator
@ -126,7 +123,6 @@ var (
ErrMissingSignature = types.ErrMissingSignature ErrMissingSignature = types.ErrMissingSignature
) )
// tags
var ( var (
ActionCreateValidator = tags.ActionCreateValidator ActionCreateValidator = tags.ActionCreateValidator
ActionEditValidator = tags.ActionEditValidator ActionEditValidator = tags.ActionEditValidator

View File

@ -2,9 +2,11 @@ package types
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
) )
// Delegation represents the bond with tokens held by an account. It is // Delegation represents the bond with tokens held by an account. It is
@ -17,7 +19,54 @@ type Delegation struct {
Height int64 `json:"height"` // Last height bond updated Height int64 `json:"height"` // Last height bond updated
} }
// two are equal type delegationValue struct {
Shares sdk.Rat
Height int64
}
// return the delegation without fields contained within the key for the store
func MustMarshalDelegation(cdc *wire.Codec, delegation Delegation) []byte {
val := delegationValue{
delegation.Shares,
delegation.Height,
}
return cdc.MustMarshalBinary(val)
}
// return the delegation without fields contained within the key for the store
func MustUnmarshalDelegation(cdc *wire.Codec, key, value []byte) Delegation {
delegation, err := UnmarshalDelegation(cdc, key, value)
if err != nil {
panic(err)
}
return delegation
}
// return the delegation without fields contained within the key for the store
func UnmarshalDelegation(cdc *wire.Codec, key, value []byte) (delegation Delegation, err error) {
var storeValue delegationValue
err = cdc.UnmarshalBinary(value, &storeValue)
if err != nil {
return
}
addrs := key[1:] // remove prefix bytes
if len(addrs) != 2*sdk.AddrLen {
err = errors.New("unexpected key length")
return
}
delAddr := sdk.Address(addrs[:sdk.AddrLen])
valAddr := sdk.Address(addrs[sdk.AddrLen:])
return Delegation{
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
Shares: storeValue.Shares,
Height: storeValue.Height,
}, nil
}
// nolint
func (d Delegation) Equal(d2 Delegation) bool { func (d Delegation) Equal(d2 Delegation) bool {
return bytes.Equal(d.DelegatorAddr, d2.DelegatorAddr) && return bytes.Equal(d.DelegatorAddr, d2.DelegatorAddr) &&
bytes.Equal(d.ValidatorAddr, d2.ValidatorAddr) && bytes.Equal(d.ValidatorAddr, d2.ValidatorAddr) &&
@ -33,16 +82,20 @@ func (d Delegation) GetDelegator() sdk.Address { return d.DelegatorAddr }
func (d Delegation) GetValidator() sdk.Address { return d.ValidatorAddr } func (d Delegation) GetValidator() sdk.Address { return d.ValidatorAddr }
func (d Delegation) GetBondShares() sdk.Rat { return d.Shares } func (d Delegation) GetBondShares() sdk.Rat { return d.Shares }
//Human Friendly pretty printer // HumanReadableString returns a human readable string representation of a
// Delegation. An error is returned if the Delegation's delegator or validator
// addresses cannot be Bech32 encoded.
func (d Delegation) HumanReadableString() (string, error) { func (d Delegation) HumanReadableString() (string, error) {
bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr) bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr)
if err != nil { if err != nil {
return "", err return "", err
} }
bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr) bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr)
if err != nil { if err != nil {
return "", err return "", err
} }
resp := "Delegation \n" resp := "Delegation \n"
resp += fmt.Sprintf("Delegator: %s\n", bechAcc) resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
resp += fmt.Sprintf("Validator: %s\n", bechVal) resp += fmt.Sprintf("Validator: %s\n", bechVal)
@ -50,12 +103,9 @@ func (d Delegation) HumanReadableString() (string, error) {
resp += fmt.Sprintf("Height: %d", d.Height) resp += fmt.Sprintf("Height: %d", d.Height)
return resp, nil return resp, nil
} }
//__________________________________________________________________ // UnbondingDelegation reflects a delegation's passive unbonding queue.
// element stored to represent the passive unbonding queue
type UnbondingDelegation struct { type UnbondingDelegation struct {
DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator
ValidatorAddr sdk.Address `json:"validator_addr"` // validator unbonding from owner addr ValidatorAddr sdk.Address `json:"validator_addr"` // validator unbonding from owner addr
@ -65,6 +115,59 @@ type UnbondingDelegation struct {
Balance sdk.Coin `json:"balance"` // atoms to receive at completion Balance sdk.Coin `json:"balance"` // atoms to receive at completion
} }
type ubdValue struct {
CreationHeight int64
MinTime int64
InitialBalance sdk.Coin
Balance sdk.Coin
}
// return the unbonding delegation without fields contained within the key for the store
func MustMarshalUBD(cdc *wire.Codec, ubd UnbondingDelegation) []byte {
val := ubdValue{
ubd.CreationHeight,
ubd.MinTime,
ubd.InitialBalance,
ubd.Balance,
}
return cdc.MustMarshalBinary(val)
}
// unmarshal a unbonding delegation from a store key and value
func MustUnmarshalUBD(cdc *wire.Codec, key, value []byte) UnbondingDelegation {
ubd, err := UnmarshalUBD(cdc, key, value)
if err != nil {
panic(err)
}
return ubd
}
// unmarshal a unbonding delegation from a store key and value
func UnmarshalUBD(cdc *wire.Codec, key, value []byte) (ubd UnbondingDelegation, err error) {
var storeValue ubdValue
err = cdc.UnmarshalBinary(value, &storeValue)
if err != nil {
return
}
addrs := key[1:] // remove prefix bytes
if len(addrs) != 2*sdk.AddrLen {
err = errors.New("unexpected key length")
return
}
delAddr := sdk.Address(addrs[:sdk.AddrLen])
valAddr := sdk.Address(addrs[sdk.AddrLen:])
return UnbondingDelegation{
DelegatorAddr: delAddr,
ValidatorAddr: valAddr,
CreationHeight: storeValue.CreationHeight,
MinTime: storeValue.MinTime,
InitialBalance: storeValue.InitialBalance,
Balance: storeValue.Balance,
}, nil
}
// nolint // nolint
func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool { func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool {
bz1 := MsgCdc.MustMarshalBinary(&d) bz1 := MsgCdc.MustMarshalBinary(&d)
@ -72,16 +175,20 @@ func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool {
return bytes.Equal(bz1, bz2) return bytes.Equal(bz1, bz2)
} }
//Human Friendly pretty printer // HumanReadableString returns a human readable string representation of an
// UnbondingDelegation. An error is returned if the UnbondingDelegation's
// delegator or validator addresses cannot be Bech32 encoded.
func (d UnbondingDelegation) HumanReadableString() (string, error) { func (d UnbondingDelegation) HumanReadableString() (string, error) {
bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr) bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr)
if err != nil { if err != nil {
return "", err return "", err
} }
bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr) bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr)
if err != nil { if err != nil {
return "", err return "", err
} }
resp := "Unbonding Delegation \n" resp := "Unbonding Delegation \n"
resp += fmt.Sprintf("Delegator: %s\n", bechAcc) resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
resp += fmt.Sprintf("Validator: %s\n", bechVal) resp += fmt.Sprintf("Validator: %s\n", bechVal)
@ -93,9 +200,7 @@ func (d UnbondingDelegation) HumanReadableString() (string, error) {
} }
//__________________________________________________________________ // Redelegation reflects a delegation's passive re-delegation queue.
// element stored to represent the passive redelegation queue
type Redelegation struct { type Redelegation struct {
DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator
ValidatorSrcAddr sdk.Address `json:"validator_src_addr"` // validator redelegation source owner addr ValidatorSrcAddr sdk.Address `json:"validator_src_addr"` // validator redelegation source owner addr
@ -108,6 +213,67 @@ type Redelegation struct {
SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating SharesDst sdk.Rat `json:"shares_dst"` // amount of destination shares redelegating
} }
type redValue struct {
CreationHeight int64
MinTime int64
InitialBalance sdk.Coin
Balance sdk.Coin
SharesSrc sdk.Rat
SharesDst sdk.Rat
}
// return the redelegation without fields contained within the key for the store
func MustMarshalRED(cdc *wire.Codec, red Redelegation) []byte {
val := redValue{
red.CreationHeight,
red.MinTime,
red.InitialBalance,
red.Balance,
red.SharesSrc,
red.SharesDst,
}
return cdc.MustMarshalBinary(val)
}
// unmarshal a redelegation from a store key and value
func MustUnmarshalRED(cdc *wire.Codec, key, value []byte) Redelegation {
red, err := UnmarshalRED(cdc, key, value)
if err != nil {
panic(err)
}
return red
}
// unmarshal a redelegation from a store key and value
func UnmarshalRED(cdc *wire.Codec, key, value []byte) (red Redelegation, err error) {
var storeValue redValue
err = cdc.UnmarshalBinary(value, &storeValue)
if err != nil {
return
}
addrs := key[1:] // remove prefix bytes
if len(addrs) != 3*sdk.AddrLen {
err = errors.New("unexpected key length")
return
}
delAddr := sdk.Address(addrs[:sdk.AddrLen])
valSrcAddr := sdk.Address(addrs[sdk.AddrLen : 2*sdk.AddrLen])
valDstAddr := sdk.Address(addrs[2*sdk.AddrLen:])
return Redelegation{
DelegatorAddr: delAddr,
ValidatorSrcAddr: valSrcAddr,
ValidatorDstAddr: valDstAddr,
CreationHeight: storeValue.CreationHeight,
MinTime: storeValue.MinTime,
InitialBalance: storeValue.InitialBalance,
Balance: storeValue.Balance,
SharesSrc: storeValue.SharesSrc,
SharesDst: storeValue.SharesDst,
}, nil
}
// nolint // nolint
func (d Redelegation) Equal(d2 Redelegation) bool { func (d Redelegation) Equal(d2 Redelegation) bool {
bz1 := MsgCdc.MustMarshalBinary(&d) bz1 := MsgCdc.MustMarshalBinary(&d)
@ -115,20 +281,25 @@ func (d Redelegation) Equal(d2 Redelegation) bool {
return bytes.Equal(bz1, bz2) return bytes.Equal(bz1, bz2)
} }
//Human Friendly pretty printer // HumanReadableString returns a human readable string representation of a
// Redelegation. An error is returned if the UnbondingDelegation's delegator or
// validator addresses cannot be Bech32 encoded.
func (d Redelegation) HumanReadableString() (string, error) { func (d Redelegation) HumanReadableString() (string, error) {
bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr) bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr)
if err != nil { if err != nil {
return "", err return "", err
} }
bechValSrc, err := sdk.Bech32ifyAcc(d.ValidatorSrcAddr) bechValSrc, err := sdk.Bech32ifyAcc(d.ValidatorSrcAddr)
if err != nil { if err != nil {
return "", err return "", err
} }
bechValDst, err := sdk.Bech32ifyAcc(d.ValidatorDstAddr) bechValDst, err := sdk.Bech32ifyAcc(d.ValidatorDstAddr)
if err != nil { if err != nil {
return "", err return "", err
} }
resp := "Redelegation \n" resp := "Redelegation \n"
resp += fmt.Sprintf("Delegator: %s\n", bechAcc) resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
resp += fmt.Sprintf("Source Validator: %s\n", bechValSrc) resp += fmt.Sprintf("Source Validator: %s\n", bechValSrc)

View File

@ -0,0 +1,116 @@
package types
import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"
)
func TestDelegationEqual(t *testing.T) {
d1 := Delegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
Shares: sdk.NewRat(100),
}
d2 := Delegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
Shares: sdk.NewRat(100),
}
ok := d1.Equal(d2)
require.True(t, ok)
d2.ValidatorAddr = addr3
d2.Shares = sdk.NewRat(200)
ok = d1.Equal(d2)
require.False(t, ok)
}
func TestDelegationHumanReadableString(t *testing.T) {
d := Delegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
Shares: sdk.NewRat(100),
}
// NOTE: Being that the validator's keypair is random, we cannot test the
// actual contents of the string.
valStr, err := d.HumanReadableString()
require.Nil(t, err)
require.NotEmpty(t, valStr)
}
func TestUnbondingDelegationEqual(t *testing.T) {
ud1 := UnbondingDelegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
}
ud2 := UnbondingDelegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
}
ok := ud1.Equal(ud2)
require.True(t, ok)
ud2.ValidatorAddr = addr3
ud2.MinTime = 20 * 20 * 2
ok = ud1.Equal(ud2)
require.False(t, ok)
}
func TestUnbondingDelegationHumanReadableString(t *testing.T) {
ud := UnbondingDelegation{
DelegatorAddr: addr1,
ValidatorAddr: addr2,
}
// NOTE: Being that the validator's keypair is random, we cannot test the
// actual contents of the string.
valStr, err := ud.HumanReadableString()
require.Nil(t, err)
require.NotEmpty(t, valStr)
}
func TestRedelegationEqual(t *testing.T) {
r1 := Redelegation{
DelegatorAddr: addr1,
ValidatorSrcAddr: addr2,
ValidatorDstAddr: addr3,
}
r2 := Redelegation{
DelegatorAddr: addr1,
ValidatorSrcAddr: addr2,
ValidatorDstAddr: addr3,
}
ok := r1.Equal(r2)
require.True(t, ok)
r2.SharesDst = sdk.NewRat(10)
r2.SharesSrc = sdk.NewRat(20)
r2.MinTime = 20 * 20 * 2
ok = r1.Equal(r2)
require.False(t, ok)
}
func TestRedelegationHumanReadableString(t *testing.T) {
r := Redelegation{
DelegatorAddr: addr1,
ValidatorSrcAddr: addr2,
ValidatorDstAddr: addr3,
SharesDst: sdk.NewRat(10),
SharesSrc: sdk.NewRat(20),
}
// NOTE: Being that the validator's keypair is random, we cannot test the
// actual contents of the string.
valStr, err := r.HumanReadableString()
require.Nil(t, err)
require.NotEmpty(t, valStr)
}

View File

@ -25,97 +25,118 @@ const (
func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error { func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil") return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil")
} }
func ErrNoValidatorFound(codespace sdk.CodespaceType) sdk.Error { func ErrNoValidatorFound(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address") return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address")
} }
func ErrValidatorAlreadyExists(codespace sdk.CodespaceType) sdk.Error { func ErrValidatorAlreadyExists(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist, cannot re-create validator") return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist, cannot re-create validator")
} }
func ErrValidatorRevoked(codespace sdk.CodespaceType) sdk.Error { func ErrValidatorRevoked(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "validator for this address is currently revoked") return sdk.NewError(codespace, CodeInvalidValidator, "validator for this address is currently revoked")
} }
func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error { func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "error removing validator") return sdk.NewError(codespace, CodeInvalidValidator, "error removing validator")
} }
func ErrDescriptionLength(codespace sdk.CodespaceType, descriptor string, got, max int) sdk.Error { func ErrDescriptionLength(codespace sdk.CodespaceType, descriptor string, got, max int) sdk.Error {
msg := fmt.Sprintf("bad description length for %v, got length %v, max is %v", descriptor, got, max) msg := fmt.Sprintf("bad description length for %v, got length %v, max is %v", descriptor, got, max)
return sdk.NewError(codespace, CodeInvalidValidator, msg) return sdk.NewError(codespace, CodeInvalidValidator, msg)
} }
func ErrCommissionNegative(codespace sdk.CodespaceType) sdk.Error { func ErrCommissionNegative(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "commission must be positive") return sdk.NewError(codespace, CodeInvalidValidator, "commission must be positive")
} }
func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error { func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%") return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%")
} }
// delegation
func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil") return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil")
} }
func ErrBadDenom(codespace sdk.CodespaceType) sdk.Error { func ErrBadDenom(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "invalid coin denomination") return sdk.NewError(codespace, CodeInvalidDelegation, "invalid coin denomination")
} }
func ErrBadDelegationAmount(codespace sdk.CodespaceType) sdk.Error { func ErrBadDelegationAmount(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "amount must be > 0") return sdk.NewError(codespace, CodeInvalidDelegation, "amount must be > 0")
} }
func ErrNoDelegation(codespace sdk.CodespaceType) sdk.Error { func ErrNoDelegation(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "no delegation for this (address, validator) pair") return sdk.NewError(codespace, CodeInvalidDelegation, "no delegation for this (address, validator) pair")
} }
func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error { func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not exist for that address") return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not exist for that address")
} }
func ErrNoDelegatorForAddress(codespace sdk.CodespaceType) sdk.Error { func ErrNoDelegatorForAddress(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not contain this delegation") return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not contain this delegation")
} }
func ErrInsufficientShares(codespace sdk.CodespaceType) sdk.Error { func ErrInsufficientShares(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "insufficient delegation shares") return sdk.NewError(codespace, CodeInvalidDelegation, "insufficient delegation shares")
} }
func ErrDelegationValidatorEmpty(codespace sdk.CodespaceType) sdk.Error { func ErrDelegationValidatorEmpty(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "cannot delegate to an empty validator") return sdk.NewError(codespace, CodeInvalidDelegation, "cannot delegate to an empty validator")
} }
func ErrNotEnoughDelegationShares(codespace sdk.CodespaceType, shares string) sdk.Error { func ErrNotEnoughDelegationShares(codespace sdk.CodespaceType, shares string) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, fmt.Sprintf("not enough shares only have %v", shares)) return sdk.NewError(codespace, CodeInvalidDelegation, fmt.Sprintf("not enough shares only have %v", shares))
} }
func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error { func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0") return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0")
} }
func ErrBadSharesPrecision(codespace sdk.CodespaceType) sdk.Error { func ErrBadSharesPrecision(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, return sdk.NewError(codespace, CodeInvalidDelegation,
fmt.Sprintf("shares denominator must be < %s, try reducing the number of decimal points", fmt.Sprintf("shares denominator must be < %s, try reducing the number of decimal points",
maximumBondingRationalDenominator.String()), maximumBondingRationalDenominator.String()),
) )
} }
func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error { func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1") return sdk.NewError(codespace, CodeInvalidDelegation, "shares percent must be >0 and <=1")
} }
// redelegation
func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min int64) sdk.Error { func ErrNotMature(codespace sdk.CodespaceType, operation, descriptor string, got, min int64) sdk.Error {
msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v", msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v",
operation, descriptor, got, min) operation, descriptor, got, min)
return sdk.NewError(codespace, CodeUnauthorized, msg) return sdk.NewError(codespace, CodeUnauthorized, msg)
} }
func ErrNoUnbondingDelegation(codespace sdk.CodespaceType) sdk.Error { func ErrNoUnbondingDelegation(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "no unbonding delegation found") return sdk.NewError(codespace, CodeInvalidDelegation, "no unbonding delegation found")
} }
func ErrNoRedelegation(codespace sdk.CodespaceType) sdk.Error { func ErrNoRedelegation(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "no redelegation found") return sdk.NewError(codespace, CodeInvalidDelegation, "no redelegation found")
} }
func ErrBadRedelegationDst(codespace sdk.CodespaceType) sdk.Error { func ErrBadRedelegationDst(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, "redelegation validator not found") return sdk.NewError(codespace, CodeInvalidDelegation, "redelegation validator not found")
} }
func ErrTransitiveRedelegation(codespace sdk.CodespaceType) sdk.Error { func ErrTransitiveRedelegation(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDelegation, return sdk.NewError(codespace, CodeInvalidDelegation,
"redelegation to this validator already in progress, first redelegation to this validator must complete before next redelegation") "redelegation to this validator already in progress, first redelegation to this validator must complete before next redelegation")
} }
// messages
func ErrBothShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { func ErrBothShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidInput, "both shares amount and shares percent provided") return sdk.NewError(codespace, CodeInvalidInput, "both shares amount and shares percent provided")
} }
func ErrNeitherShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error { func ErrNeitherShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidInput, "neither shares amount nor shares percent provided") return sdk.NewError(codespace, CodeInvalidInput, "neither shares amount nor shares percent provided")
} }
func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error { func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "missing signature") return sdk.NewError(codespace, CodeInvalidValidator, "missing signature")
} }

View File

@ -63,7 +63,7 @@ func (msg MsgCreateValidator) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// quick validity check // quick validity check
@ -114,7 +114,7 @@ func (msg MsgEditValidator) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// quick validity check // quick validity check
@ -166,7 +166,7 @@ func (msg MsgDelegate) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// quick validity check // quick validity check
@ -226,7 +226,7 @@ func (msg MsgBeginRedelegate) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// quick validity check // quick validity check
@ -286,7 +286,7 @@ func (msg MsgCompleteRedelegate) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// quick validity check // quick validity check
@ -338,7 +338,7 @@ func (msg MsgBeginUnbonding) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// quick validity check // quick validity check
@ -387,7 +387,7 @@ func (msg MsgCompleteUnbonding) GetSignBytes() []byte {
if err != nil { if err != nil {
panic(err) panic(err)
} }
return b return sdk.MustSortJSON(b)
} }
// quick validity check // quick validity check

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