Merge remote-tracking branch 'origin/develop' into rigel/a-validator-on-a-cliff
This commit is contained in:
commit
2bf0b842fa
|
@ -0,0 +1,7 @@
|
|||
# CODEOWNERS: https://help.github.com/articles/about-codeowners/
|
||||
|
||||
# Primary repo maintainers
|
||||
* @ebuchman @rigelrozanski @cwgoes
|
||||
|
||||
# Precious documentation
|
||||
/docs/ @zramsay @jolesbi
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -5,6 +5,7 @@
|
|||
*TBD*
|
||||
|
||||
BREAKING CHANGES
|
||||
* msg.GetSignBytes() returns sorted JSON (by key)
|
||||
* Update Tendermint to v0.22.0
|
||||
* Default ports changed from 466xx to 266xx
|
||||
* 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
|
||||
* Add REST endpoint to unrevoke a validator previously revoked for downtime
|
||||
* 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
|
||||
* [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
|
||||
* [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
|
||||
- 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
|
||||
* [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
|
||||
* 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] 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)
|
||||
* [types] added common tag constants
|
||||
* [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
|
||||
|
||||
BUG FIXES
|
||||
* [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
|
||||
* [lcd] tests now don't depend on raw json text
|
||||
* [stake] error strings lower case
|
||||
|
@ -96,6 +112,8 @@ BUG FIXES
|
|||
* \#1353 - CLI: Show pool shares fractions in human-readable format
|
||||
* \#1258 - printing big.rat's can no longer overflow int64
|
||||
* \#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
|
||||
|
||||
|
|
|
@ -137,6 +137,7 @@
|
|||
".",
|
||||
"hcl/ast",
|
||||
"hcl/parser",
|
||||
"hcl/printer",
|
||||
"hcl/scanner",
|
||||
"hcl/strconv",
|
||||
"hcl/token",
|
||||
|
@ -240,7 +241,7 @@
|
|||
"nfs",
|
||||
"xfs"
|
||||
]
|
||||
revision = "40f013a808ec4fa79def444a1a56de4d1727efcb"
|
||||
revision = "ae68e2d4c00fed4943b5f6698d504a5fe083da8a"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
|
@ -433,13 +434,13 @@
|
|||
"netutil",
|
||||
"trace"
|
||||
]
|
||||
revision = "87b3feba568e144938625fc5d80ec92566c1a8fe"
|
||||
revision = "ed29d75add3d7c4bf7ca65aac0c6df3d1420216f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "7138fd3d9dc8335c567ca206f4333fb75eb05d56"
|
||||
revision = "151529c776cdc58ddbe7963ba9af779f3577b419"
|
||||
|
||||
[[projects]]
|
||||
name = "golang.org/x/text"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package baseapp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
@ -19,7 +18,6 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
func 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 {
|
||||
return cmn.RandInt64()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -224,25 +224,58 @@ func (ctx CoreContext) ensureSignBuild(name string, msgs []sdk.Msg, cdc *wire.Co
|
|||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return ctx.BroadcastTx(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 ctx.Async {
|
||||
res, err := ctx.BroadcastTxAsync(txBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ctx.JSON {
|
||||
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 nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
return ctx.BroadcastTxAsync(txBytes)
|
||||
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
|
||||
|
|
|
@ -22,6 +22,9 @@ type CoreContext struct {
|
|||
Decoder auth.AccountDecoder
|
||||
AccountStore string
|
||||
UseLedger bool
|
||||
Async bool
|
||||
JSON bool
|
||||
PrintResponse bool
|
||||
}
|
||||
|
||||
// WithChainID - return a copy of the context with an updated chainID
|
||||
|
|
|
@ -27,13 +27,20 @@ func NewCoreContextFromViper() CoreContext {
|
|||
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{
|
||||
ChainID: chainID,
|
||||
Height: viper.GetInt64(client.FlagHeight),
|
||||
Gas: viper.GetInt64(client.FlagGas),
|
||||
Fee: viper.GetString(client.FlagFee),
|
||||
TrustNode: viper.GetBool(client.FlagTrustNode),
|
||||
FromAddressName: viper.GetString(client.FlagName),
|
||||
FromAddressName: keyName,
|
||||
NodeURI: nodeURI,
|
||||
AccountNumber: viper.GetInt64(client.FlagAccountNumber),
|
||||
Sequence: viper.GetInt64(client.FlagSequence),
|
||||
|
@ -42,6 +49,9 @@ func NewCoreContextFromViper() CoreContext {
|
|||
Decoder: nil,
|
||||
AccountStore: "acc",
|
||||
UseLedger: viper.GetBool(client.FlagUseLedger),
|
||||
Async: viper.GetBool(client.FlagAsync),
|
||||
JSON: viper.GetBool(client.FlagJson),
|
||||
PrintResponse: viper.GetBool(client.FlagPrintResponse),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,11 +10,15 @@ const (
|
|||
FlagHeight = "height"
|
||||
FlagGas = "gas"
|
||||
FlagTrustNode = "trust-node"
|
||||
FlagFrom = "from"
|
||||
FlagName = "name"
|
||||
FlagAccountNumber = "account-number"
|
||||
FlagSequence = "sequence"
|
||||
FlagMemo = "memo"
|
||||
FlagFee = "fee"
|
||||
FlagAsync = "async"
|
||||
FlagJson = "json"
|
||||
FlagPrintResponse = "print-response"
|
||||
)
|
||||
|
||||
// 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
|
||||
func PostCommands(cmds ...*cobra.Command) []*cobra.Command {
|
||||
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(FlagSequence, 0, "Sequence number to sign the tx")
|
||||
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().Bool(FlagUseLedger, false, "Use a connected Ledger device")
|
||||
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
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -162,12 +161,6 @@ type NewKeyBody struct {
|
|||
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
|
||||
func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var kb keys.Keybase
|
||||
|
@ -216,22 +209,24 @@ func AddNewKeyRequestHandler(w http.ResponseWriter, r *http.Request) {
|
|||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
bech32Account, err := sdk.Bech32ifyAcc(sdk.Address(info.GetPubKey().Address().Bytes()))
|
||||
|
||||
keyOutput, err := Bech32KeyOutput(info)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
bz, err := json.Marshal(NewKeyResponse{
|
||||
Address: bech32Account,
|
||||
Mnemonic: mnemonic,
|
||||
})
|
||||
|
||||
keyOutput.Seed = mnemonic
|
||||
|
||||
output, err := json.MarshalIndent(keyOutput, "", " ")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
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
|
||||
|
|
|
@ -25,14 +25,19 @@ func deleteKeyCommand() *cobra.Command {
|
|||
func runDeleteCmd(cmd *cobra.Command, args []string) error {
|
||||
name := args[0]
|
||||
|
||||
buf := client.BufferStdin()
|
||||
oldpass, err := client.GetPassword(
|
||||
"DANGER - enter password to permanently delete key:", buf)
|
||||
kb, err := GetKeyBase()
|
||||
if err != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ func TestKeys(t *testing.T) {
|
|||
res, body = Request(t, port, "POST", "/keys", jsonStr)
|
||||
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, body)
|
||||
var resp keys.NewKeyResponse
|
||||
var resp keys.KeyOutput
|
||||
err = wire.Cdc.UnmarshalJSON([]byte(body), &resp)
|
||||
require.Nil(t, err, body)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package clitest
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -21,37 +22,44 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
)
|
||||
|
||||
func TestGaiaCLISend(t *testing.T) {
|
||||
var (
|
||||
pass = "1234567890"
|
||||
gaiadHome = ""
|
||||
gaiacliHome = ""
|
||||
)
|
||||
|
||||
tests.ExecuteT(t, "gaiad unsafe_reset_all")
|
||||
pass := "1234567890"
|
||||
executeWrite(t, "gaiacli keys delete foo", pass)
|
||||
executeWrite(t, "gaiacli keys delete bar", pass)
|
||||
chainID := executeInit(t, "gaiad init -o --name=foo")
|
||||
executeWrite(t, "gaiacli keys add bar", pass)
|
||||
func init() {
|
||||
gaiadHome, gaiacliHome = getTestingHomeDirs()
|
||||
}
|
||||
|
||||
func TestGaiaCLISend(t *testing.T) {
|
||||
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
|
||||
servAddr, port, err := server.FreeTCPAddr()
|
||||
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
|
||||
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)
|
||||
tests.WaitForTMStart(port)
|
||||
tests.WaitForNextHeightTM(port)
|
||||
|
||||
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
||||
fooCech, err := sdk.Bech32ifyAcc(fooAddr)
|
||||
require.NoError(t, err)
|
||||
barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
|
||||
barCech, err := sdk.Bech32ifyAcc(barAddr)
|
||||
require.NoError(t, err)
|
||||
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
||||
fooCech := sdk.MustBech32ifyAcc(fooAddr)
|
||||
barAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
|
||||
barCech := sdk.MustBech32ifyAcc(barAddr)
|
||||
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
|
||||
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)
|
||||
|
||||
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())
|
||||
|
||||
// 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)
|
||||
|
||||
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())
|
||||
|
||||
// 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)
|
||||
|
||||
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) {
|
||||
|
||||
tests.ExecuteT(t, "gaiad unsafe_reset_all")
|
||||
pass := "1234567890"
|
||||
executeWrite(t, "gaiacli keys delete foo", pass)
|
||||
executeWrite(t, "gaiacli keys delete bar", pass)
|
||||
chainID := executeInit(t, "gaiad init -o --name=foo")
|
||||
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
|
||||
servAddr, port, err := server.FreeTCPAddr()
|
||||
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
|
||||
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)
|
||||
tests.WaitForTMStart(port)
|
||||
tests.WaitForNextHeightTM(port)
|
||||
|
||||
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
||||
fooCech, err := sdk.Bech32ifyAcc(fooAddr)
|
||||
require.NoError(t, err)
|
||||
barAddr, barPubKey := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
|
||||
barCech, err := sdk.Bech32ifyAcc(barAddr)
|
||||
require.NoError(t, err)
|
||||
barCeshPubKey, err := sdk.Bech32ifyValPub(barPubKey)
|
||||
require.NoError(t, err)
|
||||
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
||||
fooCech := sdk.MustBech32ifyAcc(fooAddr)
|
||||
barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome))
|
||||
barCech := sdk.MustBech32ifyAcc(barAddr)
|
||||
barCeshPubKey := sdk.MustBech32ifyValPub(barPubKey)
|
||||
|
||||
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)
|
||||
|
||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barCech, flags))
|
||||
|
@ -117,7 +121,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
|
||||
// create validator
|
||||
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(" --pubkey=%v", barCeshPubKey)
|
||||
cvStr += fmt.Sprintf(" --amount=%v", "2steak")
|
||||
|
@ -135,7 +139,7 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
|
||||
// unbond a single share
|
||||
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-delegator=%v", barCech)
|
||||
unbondStr += fmt.Sprintf(" --shares-amount=%v", "1")
|
||||
|
@ -153,33 +157,31 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||
|
||||
tests.ExecuteT(t, "gaiad unsafe_reset_all")
|
||||
pass := "1234567890"
|
||||
executeWrite(t, "gaiacli keys delete foo", pass)
|
||||
executeWrite(t, "gaiacli keys delete bar", pass)
|
||||
chainID := executeInit(t, "gaiad init -o --name=foo")
|
||||
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
|
||||
servAddr, port, err := server.FreeTCPAddr()
|
||||
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
|
||||
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)
|
||||
tests.WaitForTMStart(port)
|
||||
tests.WaitForNextHeightTM(port)
|
||||
|
||||
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
||||
fooCech, err := sdk.Bech32ifyAcc(fooAddr)
|
||||
require.NoError(t, err)
|
||||
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
||||
fooCech := sdk.MustBech32ifyAcc(fooAddr)
|
||||
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooCech, flags))
|
||||
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)
|
||||
|
||||
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, 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)
|
||||
|
||||
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, 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)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// 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
|
||||
|
||||
|
|
|
@ -197,6 +197,7 @@ func MakeCodec() *wire.Codec {
|
|||
auth.RegisterWire(cdc)
|
||||
sdk.RegisterWire(cdc)
|
||||
wire.RegisterCrypto(cdc)
|
||||
cdc.Seal()
|
||||
return cdc
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ gaiacli stake create-validator \
|
|||
--address-validator=<account_cosmosaccaddr>
|
||||
--moniker="choose a moniker" \
|
||||
--chain-id=gaia-6002 \
|
||||
--name=<key_name>
|
||||
--from=<key_name>
|
||||
```
|
||||
|
||||
### Edit Validator Description
|
||||
|
@ -237,7 +237,7 @@ gaiacli stake edit-validator
|
|||
--keybase-sig="6A0D65E29A4CBC8E"
|
||||
--details="To infinity and beyond!"
|
||||
--chain-id=gaia-6002 \
|
||||
--name=<key_name>
|
||||
--from=<key_name>
|
||||
```
|
||||
|
||||
### 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`.
|
||||
|
||||
```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.
|
||||
|
@ -320,8 +320,8 @@ On the testnet, we delegate `steak` instead of `atom`. Here's how you can bond t
|
|||
gaiacli stake delegate \
|
||||
--amount=10steak \
|
||||
--address-delegator=<account_cosmosaccaddr> \
|
||||
--address-validator=$(gaiad tendermint show_validator) \
|
||||
--name=<key_name> \
|
||||
--address-validator=<validator_cosmosaccaddr> \
|
||||
--from=<key_name> \
|
||||
--chain-id=gaia-6002
|
||||
```
|
||||
|
||||
|
@ -336,9 +336,9 @@ If for any reason the validator misbehaves, or you want to unbond a certain amou
|
|||
```bash
|
||||
gaiacli stake unbond \
|
||||
--address-delegator=<account_cosmosaccaddr> \
|
||||
--address-validator=$(gaiad tendermint show_validator) \
|
||||
--address-validator=<validator_cosmosaccaddr> \
|
||||
--shares=MAX \
|
||||
--name=<key_name> \
|
||||
--from=<key_name> \
|
||||
--chain-id=gaia-6002
|
||||
```
|
||||
|
||||
|
@ -349,7 +349,7 @@ gaiacli account <account_cosmosaccaddr>
|
|||
|
||||
gaiacli stake delegation \
|
||||
--address-delegator=<account_cosmosaccaddr> \
|
||||
--address-validator=$(gaiad tendermint show_validator) \
|
||||
--address-validator=<validator_cosmosaccaddr> \
|
||||
--chain-id=gaia-6002
|
||||
```
|
||||
|
||||
|
@ -361,7 +361,7 @@ gaiacli stake delegation \
|
|||
gaiacli send \
|
||||
--amount=10faucetToken \
|
||||
--chain-id=gaia-6002 \
|
||||
--name=<key_name> \
|
||||
--from=<key_name> \
|
||||
--to=<destination_cosmosaccaddr>
|
||||
```
|
||||
|
||||
|
|
|
@ -188,6 +188,9 @@ func (kb dbKeybase) List() ([]Info, error) {
|
|||
// Get returns the public information about one key.
|
||||
func (kb dbKeybase) Get(name string) (Info, error) {
|
||||
bs := kb.db.Get(infoKey(name))
|
||||
if len(bs) == 0 {
|
||||
return nil, fmt.Errorf("Key %s not found", name)
|
||||
}
|
||||
return readInfo(bs)
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
@ -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``:
|
||||
|
||||
::
|
||||
|
||||
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:
|
||||
|
||||
|
@ -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
|
||||
|
||||
See the bond decrease with ``gaiacli stake delegation`` like above.
|
||||
|
|
|
@ -63,7 +63,7 @@ Then, we try to transfer some `steak` to another account:
|
|||
```
|
||||
gaiacli account <FOO-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`
|
||||
|
@ -84,7 +84,7 @@ Finally, to relinquish all your power, unbond some coins. You should see
|
|||
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!
|
||||
|
|
|
@ -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!
|
|
@ -189,7 +189,7 @@ docs](https://godoc.org/github.com/cosmos/cosmos-sdk/types#Context) for more det
|
|||
### 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:
|
||||
|
||||
```go
|
||||
|
@ -409,7 +409,7 @@ func txDecoder(txBytes []byte) (sdk.Tx, sdk.Error) {
|
|||
Finally, we stitch it all together using the `BaseApp`.
|
||||
|
||||
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.
|
||||
It serves as the mediator between the two key components of an SDK app: the store
|
||||
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
|
||||
consensus. We'll talk more about ABCI and how this all works a bit later, but
|
||||
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
|
||||
for running and using a live blockchain application.
|
||||
|
||||
|
|
|
@ -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
|
||||
depiction of the ABCI and how its used, see
|
||||
[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
|
||||
|
||||
|
|
|
@ -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)
|
||||
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.
|
||||
|
||||
TODO: compile and run the binary
|
||||
|
|
|
@ -85,7 +85,7 @@ func (msg MsgSend) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
return sdk.MustSortJSON(bz)
|
||||
}
|
||||
|
||||
// Implements Msg. Return the signer.
|
||||
|
|
|
@ -100,7 +100,7 @@ func (msg MsgIssue) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
return sdk.MustSortJSON(bz)
|
||||
}
|
||||
|
||||
// Implements Msg. Return the signer.
|
||||
|
|
|
@ -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
|
||||
committed malicious behaviour. The relevant information is forwarded to the
|
||||
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:
|
||||
|
||||
|
|
|
@ -123,12 +123,12 @@ Where `90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD` is alice's address we got from
|
|||
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
|
||||
```
|
||||
|
||||
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
|
||||
- `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`
|
||||
|
@ -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:
|
||||
|
||||
```
|
||||
basecli send --name=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E
|
||||
basecli send --from=bob --amount=5000mycoin --to=2E8E13EEB8E3F0411ACCBC9BE0384732C24FBD5E
|
||||
--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:
|
||||
|
||||
```
|
||||
basecli send --name=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD
|
||||
basecli send --from=bob --amount=3000mycoin --to=90B0B9BE0914ECEE0B6DB74E67B07A00056B9BBD
|
||||
--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
|
||||
of the public key, but other formats are acceptable as well, as defined
|
||||
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
|
||||
`IAVL tree <https://github.com/tendermint/iavl>`__.
|
||||
|
||||
|
|
|
@ -103,6 +103,8 @@ func MakeCodec() *wire.Codec {
|
|||
cdc.RegisterInterface((*auth.Account)(nil), nil)
|
||||
cdc.RegisterConcrete(&types.AppAccount{}, "basecoin/Account", nil)
|
||||
|
||||
cdc.Seal()
|
||||
|
||||
return cdc
|
||||
}
|
||||
|
||||
|
|
|
@ -113,6 +113,9 @@ func MakeCodec() *wire.Codec {
|
|||
// Register AppAccount
|
||||
cdc.RegisterInterface((*auth.Account)(nil), nil)
|
||||
cdc.RegisterConcrete(&types.AppAccount{}, "democoin/Account", nil)
|
||||
|
||||
cdc.Seal()
|
||||
|
||||
return cdc
|
||||
}
|
||||
|
||||
|
|
|
@ -4,14 +4,12 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/types"
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/x/cool"
|
||||
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"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
|
|
|
@ -29,20 +29,24 @@ func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
key := "cool"
|
||||
value := json.RawMessage(`{
|
||||
"trend": "ice-cold"
|
||||
}`)
|
||||
appState, err = server.AppendJSON(cdc, appState, key, value)
|
||||
|
||||
appState, err = server.InsertKeyJSON(cdc, appState, key, value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
key = "pow"
|
||||
value = json.RawMessage(`{
|
||||
"difficulty": 1,
|
||||
"count": 0
|
||||
}`)
|
||||
appState, err = server.AppendJSON(cdc, appState, key, value)
|
||||
|
||||
appState, err = server.InsertKeyJSON(cdc, appState, key, value)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -3,15 +3,13 @@ package cool
|
|||
import (
|
||||
"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"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/mock"
|
||||
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 (
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
|
@ -37,12 +35,11 @@ func QuizTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
name := viper.GetString(client.FlagName)
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -70,12 +67,11 @@ func SetTrendTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
msg := cool.NewMsgSetTrend(from, args[0])
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ func (msg MsgSetTrend) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
|
@ -102,5 +102,5 @@ func (msg MsgQuiz) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
|
|
@ -48,6 +48,8 @@ func makeCodec() *wire.Codec {
|
|||
cdc.RegisterInterface((*Payload)(nil), nil)
|
||||
cdc.RegisterConcrete(seqOracle{}, "test/oracle/seqOracle", nil)
|
||||
|
||||
cdc.Seal()
|
||||
|
||||
return cdc
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ func (msg Msg) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
return sdk.MustSortJSON(bz)
|
||||
}
|
||||
|
||||
// GetSigners implements sdk.Msg
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"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/mock"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -49,12 +48,11 @@ func MineCmd(cdc *wire.Codec) *cobra.Command {
|
|||
name := ctx.FromAddressName
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -76,5 +76,5 @@ func (msg MsgMine) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ func TestMsgMineGetSignBytes(t *testing.T) {
|
|||
addr := sdk.Address([]byte("sender"))
|
||||
msg := MsgMine{addr, 1, 1, 1, []byte("abc")}
|
||||
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) {
|
||||
|
|
|
@ -87,11 +87,10 @@ func UnbondTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
func sendMsg(cdc *wire.Codec, msg sdk.Msg) error {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ func (msg MsgBond) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
return sdk.MustSortJSON(bz)
|
||||
}
|
||||
|
||||
//_______________________________________________________________
|
||||
|
|
|
@ -27,7 +27,7 @@ func (tx kvstoreTx) GetMemo() string {
|
|||
}
|
||||
|
||||
func (tx kvstoreTx) GetSignBytes() []byte {
|
||||
return tx.bytes
|
||||
return sdk.MustSortJSON(tx.bytes)
|
||||
}
|
||||
|
||||
// Should the app be calling this? Or only handlers?
|
||||
|
|
|
@ -332,32 +332,20 @@ func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
|
|||
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 {
|
||||
genDoc := tmtypes.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
Validators: validators,
|
||||
ChainID: chainID,
|
||||
Validators: validators,
|
||||
AppStateJSON: appState,
|
||||
}
|
||||
|
||||
if err := genDoc.ValidateAndComplete(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := genDoc.SaveAs(genesisFile); err != nil {
|
||||
return err
|
||||
}
|
||||
return addAppStateToGenesis(cdc, genesisFile, appState)
|
||||
}
|
||||
|
||||
// Add one line to the genesis file
|
||||
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)
|
||||
return genDoc.SaveAs(genesisFile)
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
|
|
|
@ -123,15 +123,21 @@ func AddCommands(
|
|||
|
||||
//___________________________________________________________________________________
|
||||
|
||||
// append a new json field to existing json message
|
||||
func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) {
|
||||
// InsertKeyJSON inserts a new JSON field/key with a given value to an existing
|
||||
// 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
|
||||
err = cdc.UnmarshalJSON(baseJSON, &jsonMap)
|
||||
if err != nil {
|
||||
|
||||
if err := cdc.UnmarshalJSON(baseJSON, &jsonMap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
jsonMap[key] = value
|
||||
bz, err := wire.MarshalJSONIndent(cdc, jsonMap)
|
||||
|
||||
return json.RawMessage(bz), err
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAppendJSON(t *testing.T) {
|
||||
func TestInsertKeyJSON(t *testing.T) {
|
||||
cdc := wire.NewCodec()
|
||||
|
||||
foo := map[string]string{"foo": "foofoo"}
|
||||
|
@ -24,7 +24,7 @@ func TestAppendJSON(t *testing.T) {
|
|||
barRaw := json.RawMessage(bz)
|
||||
|
||||
// make the append
|
||||
appBz, err := AppendJSON(cdc, fooRaw, "barOuter", barRaw)
|
||||
appBz, err := InsertKeyJSON(cdc, fooRaw, "barOuter", barRaw)
|
||||
require.NoError(t, err)
|
||||
|
||||
// test the append
|
||||
|
|
|
@ -36,7 +36,7 @@ echo; echo "Empty account:" $TO
|
|||
./build/basecli account $TO
|
||||
|
||||
# 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
|
||||
HASH=`echo $TX | cut -d' ' -f6`
|
||||
echo "tx hash:" $HASH
|
||||
|
|
|
@ -13,8 +13,12 @@ import (
|
|||
//Address is a go crypto-style Address
|
||||
type Address = cmn.HexBytes
|
||||
|
||||
// Bech32 prefixes
|
||||
// nolint
|
||||
const (
|
||||
// expected address length
|
||||
AddrLen = 20
|
||||
|
||||
// Bech32 prefixes
|
||||
Bech32PrefixAccAddr = "cosmosaccaddr"
|
||||
Bech32PrefixAccPub = "cosmosaccpub"
|
||||
Bech32PrefixValAddr = "cosmosvaladdr"
|
||||
|
|
|
@ -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
|
||||
func NewRatFromDecimal(decimalStr string, prec int) (f Rat, err Error) {
|
||||
// first extract any negative symbol
|
||||
if len(decimalStr) == 0 {
|
||||
return f, ErrUnknownRequest("decimal string is empty")
|
||||
}
|
||||
|
||||
neg := false
|
||||
if string(decimalStr[0]) == "-" {
|
||||
neg = true
|
||||
|
|
|
@ -27,6 +27,7 @@ func TestNewFromDecimal(t *testing.T) {
|
|||
expErr bool
|
||||
exp Rat
|
||||
}{
|
||||
{"", true, Rat{}},
|
||||
{"0", false, NewRat(0)},
|
||||
{"1", false, NewRat(1)},
|
||||
{"1.1", false, NewRat(11, 10)},
|
||||
|
|
|
@ -60,7 +60,7 @@ func (msg *TestMsg) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
return MustSortJSON(bz)
|
||||
}
|
||||
func (msg *TestMsg) ValidateBasic() Error { return nil }
|
||||
func (msg *TestMsg) GetSigners() []Address {
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -44,6 +44,5 @@ var Cdc *Codec
|
|||
func init() {
|
||||
cdc := NewCodec()
|
||||
RegisterCrypto(cdc)
|
||||
Cdc = cdc
|
||||
//Cdc = cdc.Seal() // TODO uncomment once amino upgraded to 0.9.10
|
||||
Cdc = cdc.Seal()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -54,7 +55,7 @@ func GetAccountCmd(storeName string, cdc *wire.Codec, decoder auth.AccountDecode
|
|||
|
||||
// Check if account was found
|
||||
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?")
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -141,7 +141,7 @@ func StdSignBytes(chainID string, accnum int64, sequence int64, fee StdFee, msgs
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bz
|
||||
return sdk.MustSortJSON(bz)
|
||||
}
|
||||
|
||||
// StdSignMsg is a convenience structure for passing along
|
||||
|
|
|
@ -5,9 +5,11 @@ import (
|
|||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"math/rand"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"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"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
@ -81,17 +83,19 @@ func getMockApp(t *testing.T) *mock.App {
|
|||
return mapp
|
||||
}
|
||||
|
||||
// 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()
|
||||
func TestBankWithRandomMessages(t *testing.T) {
|
||||
mapp := getMockApp(t)
|
||||
setup := func(r *rand.Rand, keys []crypto.PrivKey) {
|
||||
return
|
||||
}
|
||||
|
||||
RegisterWire(mapp.Cdc)
|
||||
coinKeeper := NewKeeper(mapp.AccountMapper)
|
||||
mapp.Router().AddRoute("bank", NewHandler(coinKeeper))
|
||||
|
||||
err := mapp.CompleteSetup([]*sdk.KVStoreKey{})
|
||||
return mapp, err
|
||||
mapp.RandomizedTesting(
|
||||
t,
|
||||
[]mock.TestAndRunTx{TestAndRunSingleInputMsgSend},
|
||||
[]mock.RandSetup{setup},
|
||||
[]mock.Invariant{ModuleInvariants},
|
||||
100, 30, 30,
|
||||
)
|
||||
}
|
||||
|
||||
func TestMsgSendWithAccounts(t *testing.T) {
|
||||
|
|
|
@ -5,11 +5,24 @@ import (
|
|||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"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"
|
||||
)
|
||||
|
||||
// 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) {
|
||||
benchmarkApp, _ := getBenchmarkMockApp()
|
||||
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"errors"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/client"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
flagTo = "to"
|
||||
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 {
|
||||
cmd := &cobra.Command{
|
||||
Use: "send",
|
||||
|
@ -33,35 +32,48 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
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)
|
||||
|
||||
to, err := sdk.GetAccAddressBech32(toStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// parse coins
|
||||
// parse coins trying to be sent
|
||||
amount := viper.GetString(flagAmount)
|
||||
coins, err := sdk.ParseCoins(amount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
msg := client.BuildMsg(from, to, coins)
|
||||
|
||||
if viper.GetBool(flagAsync) {
|
||||
res, err := ctx.EnsureSignBuildBroadcastAsync(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("Async tx sent. tx hash: ", res.Hash.String())
|
||||
return nil
|
||||
}
|
||||
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
||||
// 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
|
||||
msg := client.BuildMsg(from, to, coins)
|
||||
|
||||
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
|
||||
|
||||
},
|
||||
|
@ -69,7 +81,6 @@ func SendTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
cmd.Flags().String(flagTo, "", "Address to send coins")
|
||||
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
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ func (msg MsgSend) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
|
@ -133,7 +133,7 @@ func (msg MsgIssue) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
|
@ -162,7 +162,7 @@ func (in Input) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bin
|
||||
return sdk.MustSortJSON(bin)
|
||||
}
|
||||
|
||||
// ValidateBasic - validate transaction input
|
||||
|
@ -209,7 +209,7 @@ func (out Output) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bin
|
||||
return sdk.MustSortJSON(bin)
|
||||
}
|
||||
|
||||
// ValidateBasic - validate transaction output
|
||||
|
|
|
@ -187,7 +187,7 @@ func TestMsgSendGetSignBytes(t *testing.T) {
|
|||
}
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -257,7 +257,7 @@ func TestMsgIssueGetSignBytes(t *testing.T) {
|
|||
}
|
||||
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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -29,7 +29,7 @@ const (
|
|||
// submit a proposal tx
|
||||
func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "submitproposal",
|
||||
Use: "submit-proposal",
|
||||
Short: "Submit a proposal along with an initial deposit",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
title := viper.GetString(flagTitle)
|
||||
|
@ -63,13 +63,13 @@ func GetCmdSubmitProposal(cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block:%d. Hash:%s.Response:%+v \n", res.Height, res.Hash.String(), res.DeliverTx)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -113,11 +113,10 @@ func GetCmdDeposit(cdc *wire.Codec) *cobra.Command {
|
|||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -164,11 +163,10 @@ func GetCmdVote(cdc *wire.Codec) *cobra.Command {
|
|||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ func (msg MsgSubmitProposal) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
|
@ -149,7 +149,7 @@ func (msg MsgDeposit) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
|
@ -213,7 +213,7 @@ func (msg MsgVote) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// Implements Msg.
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -12,13 +12,13 @@ import (
|
|||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
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/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
)
|
||||
|
||||
// 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()
|
||||
|
||||
stake.RegisterWire(mapp.Cdc)
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"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/mock"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
|
|
@ -109,7 +109,7 @@ key2 DC26002735D3AA9573707CFA6D77C12349E49868
|
|||
## Transfer coins (addr1:chain1 -> addr2:chain2)
|
||||
|
||||
```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':
|
||||
Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0
|
||||
> basecli account $ADDR1 --node $NODE1
|
||||
|
@ -133,7 +133,7 @@ Committed at block 1022. Hash: E16019DCC4AA08CA70AFCFBC96028ABCC51B6AD0
|
|||
## Relay IBC packets
|
||||
|
||||
```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':
|
||||
I[04-03|16:18:59.984] Detected IBC packet number=0
|
||||
I[04-03|16:19:00.869] Relayed IBC packet number=0
|
||||
|
|
|
@ -2,7 +2,6 @@ package cli
|
|||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
@ -43,12 +42,10 @@ func IBCTransferCmd(cdc *wire.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
// get password
|
||||
res, err := ctx.EnsureSignBuildBroadcast(ctx.FromAddressName, []sdk.Msg{msg}, cdc)
|
||||
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
|
||||
},
|
||||
}
|
||||
|
|
|
@ -53,6 +53,8 @@ func makeCodec() *wire.Codec {
|
|||
cdc.RegisterConcrete(&auth.BaseAccount{}, "test/ibc/Account", nil)
|
||||
wire.RegisterCrypto(cdc)
|
||||
|
||||
cdc.Seal()
|
||||
|
||||
return cdc
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ func (p IBCPacket) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// validator the ibc packey
|
||||
|
@ -131,5 +131,5 @@ func (msg IBCReceiveMsg) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
|
|
@ -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]++
|
||||
}
|
||||
}
|
|
@ -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],
|
||||
)
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,11 +5,10 @@ import (
|
|||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/mock"
|
||||
"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/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"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()))
|
||||
unrevokeMsg := MsgUnrevoke{ValidatorAddr: validator.PubKey.Address()}
|
||||
|
||||
// no signing info yet
|
||||
checkValidatorSigningInfo(t, mapp, keeper, addr1, false)
|
||||
|
||||
// unrevoke should fail with validator not revoked
|
||||
res := mock.SignCheck(mapp.BaseApp, []sdk.Msg{unrevokeMsg}, []int64{0}, []int64{1}, priv1)
|
||||
// unrevoke should fail with unknown validator
|
||||
res := mock.CheckGenTx(t, mapp.BaseApp, []sdk.Msg{unrevokeMsg}, []int64{0}, []int64{1}, false, priv1)
|
||||
require.Equal(t, sdk.ToABCICode(DefaultCodespace, CodeValidatorNotRevoked), res.Code)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
|
@ -29,12 +27,10 @@ func GetCmdUnrevoke(cdc *wire.Codec) *cobra.Command {
|
|||
msg := slashing.NewMsgUnrevoke(validatorAddr)
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -15,7 +15,8 @@ func TestCannotUnrevokeUnlessRevoked(t *testing.T) {
|
|||
slh := NewHandler(keeper)
|
||||
amtInt := int64(100)
|
||||
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())
|
||||
stake.EndBlocker(ctx, sk)
|
||||
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins.Sub(amt)}})
|
||||
|
|
|
@ -38,7 +38,7 @@ func (msg MsgUnrevoke) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
|
|
|
@ -23,16 +23,16 @@ import (
|
|||
// TODO remove dependencies on staking (should only refer to validator set type from sdk)
|
||||
|
||||
var (
|
||||
addrs = []sdk.Address{
|
||||
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160"),
|
||||
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161"),
|
||||
testAddr("A58856F0FD53BF058B4909A21AEC019107BA6162"),
|
||||
}
|
||||
pks = []crypto.PubKey{
|
||||
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"),
|
||||
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"),
|
||||
newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"),
|
||||
}
|
||||
addrs = []sdk.Address{
|
||||
pks[0].Address(),
|
||||
pks[1].Address(),
|
||||
pks[2].Address(),
|
||||
}
|
||||
initCoins sdk.Int = sdk.NewInt(200)
|
||||
)
|
||||
|
||||
|
|
|
@ -5,11 +5,9 @@ import (
|
|||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
)
|
||||
|
@ -22,81 +20,86 @@ var (
|
|||
addr3 = crypto.GenPrivKeyEd25519().PubKey().Address()
|
||||
priv4 = crypto.GenPrivKeyEd25519()
|
||||
addr4 = priv4.PubKey().Address()
|
||||
coins = sdk.Coins{{"foocoin", sdk.NewInt(10)}}
|
||||
fee = auth.StdFee{
|
||||
sdk.Coins{{"foocoin", sdk.NewInt(0)}},
|
||||
100000,
|
||||
}
|
||||
coins = sdk.NewCoin("foocoin", 10)
|
||||
fee = auth.StdFee{sdk.Coins{sdk.NewCoin("foocoin", 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) {
|
||||
mapp := mock.NewApp()
|
||||
mApp := mock.NewApp()
|
||||
|
||||
RegisterWire(mApp.Cdc)
|
||||
|
||||
RegisterWire(mapp.Cdc)
|
||||
keyStake := sdk.NewKVStoreKey("stake")
|
||||
coinKeeper := bank.NewKeeper(mapp.AccountMapper)
|
||||
keeper := NewKeeper(mapp.Cdc, keyStake, coinKeeper, mapp.RegisterCodespace(DefaultCodespace))
|
||||
mapp.Router().AddRoute("stake", NewHandler(keeper))
|
||||
coinKeeper := bank.NewKeeper(mApp.AccountMapper)
|
||||
keeper := NewKeeper(mApp.Cdc, keyStake, coinKeeper, mApp.RegisterCodespace(DefaultCodespace))
|
||||
|
||||
mapp.SetEndBlocker(getEndBlocker(keeper))
|
||||
mapp.SetInitChainer(getInitChainer(mapp, keeper))
|
||||
mApp.Router().AddRoute("stake", NewHandler(keeper))
|
||||
mApp.SetEndBlocker(getEndBlocker(keeper))
|
||||
mApp.SetInitChainer(getInitChainer(mApp, keeper))
|
||||
|
||||
require.NoError(t, mapp.CompleteSetup([]*sdk.KVStoreKey{keyStake}))
|
||||
return mapp, keeper
|
||||
require.NoError(t, mApp.CompleteSetup([]*sdk.KVStoreKey{keyStake}))
|
||||
return mApp, keeper
|
||||
}
|
||||
|
||||
// stake endblocker
|
||||
// getEndBlocker returns a stake endblocker.
|
||||
func getEndBlocker(keeper Keeper) sdk.EndBlocker {
|
||||
return func(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||
validatorUpdates := EndBlocker(ctx, keeper)
|
||||
|
||||
return abci.ResponseEndBlock{
|
||||
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 {
|
||||
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
mapp.InitChainer(ctx, req)
|
||||
|
||||
stakeGenesis := DefaultGenesisState()
|
||||
stakeGenesis.Pool.LooseTokens = 100000
|
||||
|
||||
InitGenesis(ctx, keeper, stakeGenesis)
|
||||
|
||||
return abci.ResponseInitChain{}
|
||||
}
|
||||
}
|
||||
|
||||
//__________________________________________________________________________________________
|
||||
|
||||
func checkValidator(t *testing.T, mapp *mock.App, keeper Keeper,
|
||||
addr sdk.Address, expFound bool) Validator {
|
||||
|
||||
func checkValidator(
|
||||
t *testing.T, mapp *mock.App, keeper Keeper,
|
||||
addr sdk.Address, expFound bool,
|
||||
) Validator {
|
||||
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
|
||||
validator, found := keeper.GetValidator(ctxCheck, addr1)
|
||||
|
||||
require.Equal(t, expFound, found)
|
||||
return validator
|
||||
}
|
||||
|
||||
func checkDelegation(t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr,
|
||||
validatorAddr sdk.Address, expFound bool, expShares sdk.Rat) {
|
||||
|
||||
func checkDelegation(
|
||||
t *testing.T, mapp *mock.App, keeper Keeper, delegatorAddr,
|
||||
validatorAddr sdk.Address, expFound bool, expShares sdk.Rat,
|
||||
) {
|
||||
ctxCheck := mapp.BaseApp.NewContext(true, abci.Header{})
|
||||
delegation, found := keeper.GetDelegation(ctxCheck, delegatorAddr, validatorAddr)
|
||||
if expFound {
|
||||
require.True(t, found)
|
||||
assert.True(sdk.RatEq(t, expShares, delegation.Shares))
|
||||
require.True(sdk.RatEq(t, expShares, delegation.Shares))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
require.False(t, found)
|
||||
}
|
||||
|
||||
func TestStakeMsgs(t *testing.T) {
|
||||
mapp, keeper := getMockApp(t)
|
||||
mApp, keeper := getMockApp(t)
|
||||
|
||||
genCoin := sdk.Coin{"steak", sdk.NewInt(42)}
|
||||
bondCoin := sdk.Coin{"steak", sdk.NewInt(10)}
|
||||
genCoin := sdk.NewCoin("steak", 42)
|
||||
bondCoin := sdk.NewCoin("steak", 10)
|
||||
|
||||
acc1 := &auth.BaseAccount{
|
||||
Address: addr1,
|
||||
|
@ -108,56 +111,51 @@ func TestStakeMsgs(t *testing.T) {
|
|||
}
|
||||
accs := []auth.Account{acc1, acc2}
|
||||
|
||||
mock.SetGenesis(mapp, accs)
|
||||
mock.CheckBalance(t, mapp, addr1, sdk.Coins{genCoin})
|
||||
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin})
|
||||
|
||||
////////////////////
|
||||
// Create Validator
|
||||
mock.SetGenesis(mApp, accs)
|
||||
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin})
|
||||
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
|
||||
|
||||
// create validator
|
||||
description := NewDescription("foo_moniker", "", "", "")
|
||||
createValidatorMsg := NewMsgCreateValidator(
|
||||
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, sdk.Bonded, validator.Status())
|
||||
require.True(sdk.RatEq(t, sdk.NewRat(10), validator.PoolShares.Bonded()))
|
||||
|
||||
// check the bond that should have been created as well
|
||||
checkDelegation(t, mapp, keeper, addr1, addr1, true, sdk.NewRat(10))
|
||||
|
||||
////////////////////
|
||||
// Edit Validator
|
||||
checkDelegation(t, mApp, keeper, addr1, addr1, true, sdk.NewRat(10))
|
||||
|
||||
// edit the validator
|
||||
description = NewDescription("bar_moniker", "", "", "")
|
||||
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)
|
||||
|
||||
////////////////////
|
||||
// Delegate
|
||||
|
||||
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin})
|
||||
// delegate
|
||||
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
|
||||
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))
|
||||
|
||||
////////////////////
|
||||
// Begin Unbonding
|
||||
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))
|
||||
|
||||
// begin unbonding
|
||||
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
|
||||
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
|
||||
mock.CheckBalance(t, mapp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
|
||||
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if len(res) == 0 {
|
||||
return fmt.Errorf("No validator found with address %s", args[0])
|
||||
}
|
||||
validator := new(stake.Validator)
|
||||
cdc.MustUnmarshalBinary(res, validator)
|
||||
validator := types.MustUnmarshalValidator(cdc, addr, res)
|
||||
|
||||
switch viper.Get(cli.OutputFlag) {
|
||||
case "text":
|
||||
|
@ -74,9 +76,9 @@ func GetCmdQueryValidators(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
// parse out the validators
|
||||
var validators []stake.Validator
|
||||
for _, KV := range resKVs {
|
||||
var validator stake.Validator
|
||||
cdc.MustUnmarshalBinary(KV.Value, &validator)
|
||||
for _, kv := range resKVs {
|
||||
addr := kv.Key[1:]
|
||||
validator := types.MustUnmarshalValidator(cdc, addr, kv.Value)
|
||||
validators = append(validators, validator)
|
||||
}
|
||||
|
||||
|
@ -117,12 +119,12 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
delAddr, err := sdk.GetValAddressHex(viper.GetString(FlagAddressDelegator))
|
||||
delAddr, err := sdk.GetAccAddressBech32(viper.GetString(FlagAddressDelegator))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := stake.GetDelegationKey(delAddr, valAddr, cdc)
|
||||
key := stake.GetDelegationKey(delAddr, valAddr)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.QueryStore(key, storeName)
|
||||
if err != nil {
|
||||
|
@ -130,7 +132,7 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
// parse out the delegation
|
||||
delegation := new(stake.Delegation)
|
||||
delegation := types.MustUnmarshalDelegation(cdc, key, res)
|
||||
|
||||
switch viper.Get(cli.OutputFlag) {
|
||||
case "text":
|
||||
|
@ -140,7 +142,6 @@ func GetCmdQueryDelegation(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
}
|
||||
fmt.Println(resp)
|
||||
case "json":
|
||||
cdc.MustUnmarshalBinary(res, delegation)
|
||||
output, err := wire.MarshalJSONIndent(cdc, delegation)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -169,7 +170,7 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := stake.GetDelegationsKey(delegatorAddr, cdc)
|
||||
key := stake.GetDelegationsKey(delegatorAddr)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
|
||||
if err != nil {
|
||||
|
@ -178,9 +179,8 @@ func GetCmdQueryDelegations(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
|
||||
// parse out the validators
|
||||
var delegations []stake.Delegation
|
||||
for _, KV := range resKVs {
|
||||
var delegation stake.Delegation
|
||||
cdc.MustUnmarshalBinary(KV.Value, &delegation)
|
||||
for _, kv := range resKVs {
|
||||
delegation := types.MustUnmarshalDelegation(cdc, kv.Key, kv.Value)
|
||||
delegations = append(delegations, delegation)
|
||||
}
|
||||
|
||||
|
@ -214,7 +214,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
|
|||
return err
|
||||
}
|
||||
|
||||
key := stake.GetUBDKey(delAddr, valAddr, cdc)
|
||||
key := stake.GetUBDKey(delAddr, valAddr)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.QueryStore(key, storeName)
|
||||
if err != nil {
|
||||
|
@ -222,7 +222,7 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
|
|||
}
|
||||
|
||||
// parse out the unbonding delegation
|
||||
ubd := new(stake.UnbondingDelegation)
|
||||
ubd := types.MustUnmarshalUBD(cdc, key, res)
|
||||
|
||||
switch viper.Get(cli.OutputFlag) {
|
||||
case "text":
|
||||
|
@ -232,7 +232,6 @@ func GetCmdQueryUnbondingDelegation(storeName string, cdc *wire.Codec) *cobra.Co
|
|||
}
|
||||
fmt.Println(resp)
|
||||
case "json":
|
||||
cdc.MustUnmarshalBinary(res, ubd)
|
||||
output, err := wire.MarshalJSONIndent(cdc, ubd)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -261,7 +260,7 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := stake.GetUBDsKey(delegatorAddr, cdc)
|
||||
key := stake.GetUBDsKey(delegatorAddr)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
|
||||
if err != nil {
|
||||
|
@ -270,9 +269,8 @@ func GetCmdQueryUnbondingDelegations(storeName string, cdc *wire.Codec) *cobra.C
|
|||
|
||||
// parse out the validators
|
||||
var ubds []stake.UnbondingDelegation
|
||||
for _, KV := range resKVs {
|
||||
var ubd stake.UnbondingDelegation
|
||||
cdc.MustUnmarshalBinary(KV.Value, &ubd)
|
||||
for _, kv := range resKVs {
|
||||
ubd := types.MustUnmarshalUBD(cdc, kv.Key, kv.Value)
|
||||
ubds = append(ubds, ubd)
|
||||
}
|
||||
|
||||
|
@ -309,7 +307,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
return err
|
||||
}
|
||||
|
||||
key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr, cdc)
|
||||
key := stake.GetREDKey(delAddr, valSrcAddr, valDstAddr)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.QueryStore(key, storeName)
|
||||
if err != nil {
|
||||
|
@ -317,7 +315,7 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
}
|
||||
|
||||
// parse out the unbonding delegation
|
||||
red := new(stake.Redelegation)
|
||||
red := types.MustUnmarshalRED(cdc, key, res)
|
||||
|
||||
switch viper.Get(cli.OutputFlag) {
|
||||
case "text":
|
||||
|
@ -327,7 +325,6 @@ func GetCmdQueryRedelegation(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
}
|
||||
fmt.Println(resp)
|
||||
case "json":
|
||||
cdc.MustUnmarshalBinary(res, red)
|
||||
output, err := wire.MarshalJSONIndent(cdc, red)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -356,7 +353,7 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := stake.GetREDsKey(delegatorAddr, cdc)
|
||||
key := stake.GetREDsKey(delegatorAddr)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
resKVs, err := ctx.QuerySubspace(cdc, key, storeName)
|
||||
if err != nil {
|
||||
|
@ -365,9 +362,8 @@ func GetCmdQueryRedelegations(storeName string, cdc *wire.Codec) *cobra.Command
|
|||
|
||||
// parse out the validators
|
||||
var reds []stake.Redelegation
|
||||
for _, KV := range resKVs {
|
||||
var red stake.Redelegation
|
||||
cdc.MustUnmarshalBinary(KV.Value, &red)
|
||||
for _, kv := range resKVs {
|
||||
red := types.MustUnmarshalRED(cdc, kv.Key, kv.Value)
|
||||
reds = append(reds, red)
|
||||
}
|
||||
|
||||
|
|
|
@ -53,12 +53,10 @@ func GetCmdCreateValidator(cdc *wire.Codec) *cobra.Command {
|
|||
msg := stake.NewMsgCreateValidator(validatorAddr, pk, amount, description)
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -92,12 +90,11 @@ func GetCmdEditValidator(cdc *wire.Codec) *cobra.Command {
|
|||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -132,12 +129,11 @@ func GetCmdDelegate(cdc *wire.Codec) *cobra.Command {
|
|||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -197,12 +193,11 @@ func GetCmdBeginRedelegate(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -240,7 +235,7 @@ func getShares(storeName string, cdc *wire.Codec, sharesAmountStr, sharesPercent
|
|||
}
|
||||
|
||||
// make a query to get the existing delegation shares
|
||||
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
|
||||
key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
resQuery, err := ctx.QueryStore(key, storeName)
|
||||
if err != nil {
|
||||
|
@ -282,12 +277,11 @@ func GetCmdCompleteRedelegate(cdc *wire.Codec) *cobra.Command {
|
|||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -340,12 +334,11 @@ func GetCmdBeginUnbonding(storeName string, cdc *wire.Codec) *cobra.Command {
|
|||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -377,12 +370,11 @@ func GetCmdCompleteUnbonding(cdc *wire.Codec) *cobra.Command {
|
|||
// build and sign the transaction, then broadcast to Tendermint
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Committed at block %d. Hash: %s\n", res.Height, res.Hash.String())
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
const storeName = "stake"
|
||||
|
@ -60,7 +62,7 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
|
|||
return
|
||||
}
|
||||
|
||||
key := stake.GetDelegationKey(delegatorAddr, validatorAddr, cdc)
|
||||
key := stake.GetDelegationKey(delegatorAddr, validatorAddr)
|
||||
|
||||
res, err := ctx.QueryStore(key, storeName)
|
||||
if err != nil {
|
||||
|
@ -75,11 +77,10 @@ func delegationHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
|
|||
return
|
||||
}
|
||||
|
||||
var delegation stake.Delegation
|
||||
err = cdc.UnmarshalBinary(res, &delegation)
|
||||
delegation, err := types.UnmarshalDelegation(cdc, key, res)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(fmt.Sprintf("couldn't decode delegation. Error: %s", err.Error())))
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -117,7 +118,7 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
key := stake.GetUBDKey(delegatorAddr, validatorAddr, cdc)
|
||||
key := stake.GetUBDKey(delegatorAddr, validatorAddr)
|
||||
|
||||
res, err := ctx.QueryStore(key, storeName)
|
||||
if err != nil {
|
||||
|
@ -132,11 +133,10 @@ func ubdHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
var ubd stake.UnbondingDelegation
|
||||
err = cdc.UnmarshalBinary(res, &ubd)
|
||||
ubd, err := types.UnmarshalUBD(cdc, key, res)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr, cdc)
|
||||
key := stake.GetREDKey(delegatorAddr, validatorSrcAddr, validatorDstAddr)
|
||||
|
||||
res, err := ctx.QueryStore(key, storeName)
|
||||
if err != nil {
|
||||
|
@ -197,11 +197,10 @@ func redHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
|
||||
var red stake.Redelegation
|
||||
err = cdc.UnmarshalBinary(res, &red)
|
||||
red, err := types.UnmarshalRED(cdc, key, res)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -291,15 +290,19 @@ func validatorsHandlerFn(ctx context.CoreContext, cdc *wire.Codec) http.HandlerF
|
|||
// parse out the validators
|
||||
validators := make([]StakeValidatorOutput, len(kvs))
|
||||
for i, kv := range kvs {
|
||||
var validator stake.Validator
|
||||
var bech32Validator StakeValidatorOutput
|
||||
err = cdc.UnmarshalBinary(kv.Value, &validator)
|
||||
if err == nil {
|
||||
bech32Validator, err = bech32StakeValidatorOutput(validator)
|
||||
}
|
||||
|
||||
addr := kv.Key[1:]
|
||||
validator, err := types.UnmarshalValidator(cdc, addr, kv.Value)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
validators[i] = bech32Validator
|
||||
|
|
|
@ -1,50 +1,58 @@
|
|||
package stake
|
||||
|
||||
import (
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/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) {
|
||||
keeper.SetPool(ctx, data.Pool)
|
||||
keeper.SetNewParams(ctx, data.Params)
|
||||
keeper.InitIntraTxCounter(ctx)
|
||||
for _, validator := range data.Validators {
|
||||
|
||||
// set validator
|
||||
for _, validator := range data.Validators {
|
||||
keeper.SetValidator(ctx, validator)
|
||||
|
||||
// manually set indexes for the first time
|
||||
// Manually set indexes for the first time
|
||||
keeper.SetValidatorByPubKeyIndex(ctx, validator)
|
||||
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
|
||||
|
||||
if validator.Status() == sdk.Bonded {
|
||||
keeper.SetValidatorBondedIndex(ctx, validator)
|
||||
}
|
||||
}
|
||||
|
||||
for _, bond := range data.Bonds {
|
||||
keeper.SetDelegation(ctx, bond)
|
||||
}
|
||||
|
||||
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 {
|
||||
pool := keeper.GetPool(ctx)
|
||||
params := keeper.GetParams(ctx)
|
||||
validators := keeper.GetAllValidators(ctx)
|
||||
bonds := keeper.GetAllDelegations(ctx)
|
||||
|
||||
return types.GenesisState{
|
||||
pool,
|
||||
params,
|
||||
validators,
|
||||
bonds,
|
||||
Pool: pool,
|
||||
Params: params,
|
||||
Validators: validators,
|
||||
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) {
|
||||
keeper.IterateValidatorsBonded(ctx, func(_ int64, validator sdk.Validator) (stop bool) {
|
||||
vals = append(vals, tmtypes.GenesisValidator{
|
||||
|
@ -52,7 +60,9 @@ func WriteValidators(ctx sdk.Context, keeper Keeper) (vals []tmtypes.GenesisVali
|
|||
Power: validator.GetPower().RoundInt64(),
|
||||
Name: validator.GetMoniker(),
|
||||
})
|
||||
|
||||
return false
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -12,12 +12,13 @@ func (k Keeper) GetDelegation(ctx sdk.Context,
|
|||
delegatorAddr, validatorAddr sdk.Address) (delegation types.Delegation, found bool) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
delegatorBytes := store.Get(GetDelegationKey(delegatorAddr, validatorAddr, k.cdc))
|
||||
if delegatorBytes == nil {
|
||||
key := GetDelegationKey(delegatorAddr, validatorAddr)
|
||||
value := store.Get(key)
|
||||
if value == nil {
|
||||
return delegation, false
|
||||
}
|
||||
|
||||
k.cdc.MustUnmarshalBinary(delegatorBytes, &delegation)
|
||||
delegation = types.MustUnmarshalDelegation(k.cdc, key, value)
|
||||
return delegation, true
|
||||
}
|
||||
|
||||
|
@ -31,9 +32,7 @@ func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegati
|
|||
if !iterator.Valid() {
|
||||
break
|
||||
}
|
||||
bondBytes := iterator.Value()
|
||||
var delegation types.Delegation
|
||||
k.cdc.MustUnmarshalBinary(bondBytes, &delegation)
|
||||
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
|
||||
delegations = append(delegations, delegation)
|
||||
iterator.Next()
|
||||
}
|
||||
|
@ -46,7 +45,7 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address,
|
|||
maxRetrieve int16) (delegations []types.Delegation) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
delegatorPrefixKey := GetDelegationsKey(delegator, k.cdc)
|
||||
delegatorPrefixKey := GetDelegationsKey(delegator)
|
||||
iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest
|
||||
|
||||
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) {
|
||||
break
|
||||
}
|
||||
bondBytes := iterator.Value()
|
||||
var delegation types.Delegation
|
||||
k.cdc.MustUnmarshalBinary(bondBytes, &delegation)
|
||||
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
|
||||
delegations[i] = delegation
|
||||
iterator.Next()
|
||||
}
|
||||
|
@ -68,14 +65,14 @@ func (k Keeper) GetDelegations(ctx sdk.Context, delegator sdk.Address,
|
|||
// set the delegation
|
||||
func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := k.cdc.MustMarshalBinary(delegation)
|
||||
store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr, k.cdc), b)
|
||||
b := types.MustMarshalDelegation(k.cdc, delegation)
|
||||
store.Set(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr), b)
|
||||
}
|
||||
|
||||
// remove the delegation
|
||||
func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) {
|
||||
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) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
ubdKey := GetUBDKey(DelegatorAddr, ValidatorAddr, k.cdc)
|
||||
bz := store.Get(ubdKey)
|
||||
if bz == nil {
|
||||
key := GetUBDKey(DelegatorAddr, ValidatorAddr)
|
||||
value := store.Get(key)
|
||||
if value == nil {
|
||||
return ubd, false
|
||||
}
|
||||
|
||||
k.cdc.MustUnmarshalBinary(bz, &ubd)
|
||||
ubd = types.MustUnmarshalUBD(k.cdc, key, value)
|
||||
return ubd, true
|
||||
}
|
||||
|
||||
// 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)
|
||||
iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr, k.cdc))
|
||||
i := 0
|
||||
for ; ; i++ {
|
||||
iterator := sdk.KVStorePrefixIterator(store, GetUBDsByValIndexKey(valAddr))
|
||||
for {
|
||||
if !iterator.Valid() {
|
||||
break
|
||||
}
|
||||
unbondingKey := iterator.Value()
|
||||
unbondingBytes := store.Get(unbondingKey)
|
||||
var unbondingDelegation types.UnbondingDelegation
|
||||
k.cdc.MustUnmarshalBinary(unbondingBytes, &unbondingDelegation)
|
||||
unbondingDelegations = append(unbondingDelegations, unbondingDelegation)
|
||||
key := GetUBDKeyFromValIndexKey(iterator.Key())
|
||||
value := store.Get(key)
|
||||
ubd := types.MustUnmarshalUBD(k.cdc, key, value)
|
||||
ubds = append(ubds, ubd)
|
||||
iterator.Next()
|
||||
}
|
||||
iterator.Close()
|
||||
return unbondingDelegations
|
||||
return ubds
|
||||
}
|
||||
|
||||
// set the unbonding delegation and associated index
|
||||
func (k Keeper) SetUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinary(ubd)
|
||||
ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc)
|
||||
store.Set(ubdKey, bz)
|
||||
store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc), ubdKey)
|
||||
bz := types.MustMarshalUBD(k.cdc, ubd)
|
||||
key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr)
|
||||
store.Set(key, bz)
|
||||
store.Set(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr), []byte{}) // index, store empty bytes
|
||||
}
|
||||
|
||||
// remove the unbonding delegation object and associated index
|
||||
func (k Keeper) RemoveUnbondingDelegation(ctx sdk.Context, ubd types.UnbondingDelegation) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
ubdKey := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc)
|
||||
store.Delete(ubdKey)
|
||||
store.Delete(GetUBDByValIndexKey(ubd.DelegatorAddr, ubd.ValidatorAddr, k.cdc))
|
||||
key := GetUBDKey(ubd.DelegatorAddr, ubd.ValidatorAddr)
|
||||
store.Delete(key)
|
||||
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) {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
redKey := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr, k.cdc)
|
||||
bz := store.Get(redKey)
|
||||
if bz == nil {
|
||||
key := GetREDKey(DelegatorAddr, ValidatorSrcAddr, ValidatorDstAddr)
|
||||
value := store.Get(key)
|
||||
if value == nil {
|
||||
return red, false
|
||||
}
|
||||
|
||||
k.cdc.MustUnmarshalBinary(bz, &red)
|
||||
red = types.MustUnmarshalRED(k.cdc, key, value)
|
||||
return red, true
|
||||
}
|
||||
|
||||
// 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)
|
||||
iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr, k.cdc))
|
||||
i := 0
|
||||
for ; ; i++ {
|
||||
iterator := sdk.KVStorePrefixIterator(store, GetREDsFromValSrcIndexKey(valAddr))
|
||||
for {
|
||||
if !iterator.Valid() {
|
||||
break
|
||||
}
|
||||
redelegationKey := iterator.Value()
|
||||
redelegationBytes := store.Get(redelegationKey)
|
||||
var redelegation types.Redelegation
|
||||
k.cdc.MustUnmarshalBinary(redelegationBytes, &redelegation)
|
||||
redelegations = append(redelegations, redelegation)
|
||||
key := GetREDKeyFromValSrcIndexKey(iterator.Key())
|
||||
value := store.Get(key)
|
||||
red := types.MustUnmarshalRED(k.cdc, key, value)
|
||||
reds = append(reds, red)
|
||||
iterator.Next()
|
||||
}
|
||||
iterator.Close()
|
||||
return redelegations
|
||||
return reds
|
||||
}
|
||||
|
||||
// has a redelegation
|
||||
|
@ -174,7 +167,7 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context,
|
|||
DelegatorAddr, ValidatorDstAddr sdk.Address) bool {
|
||||
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr, k.cdc)
|
||||
prefix := GetREDsByDelToValDstIndexKey(DelegatorAddr, ValidatorDstAddr)
|
||||
iterator := sdk.KVStorePrefixIterator(store, prefix) //smallest to largest
|
||||
|
||||
found := false
|
||||
|
@ -189,20 +182,20 @@ func (k Keeper) HasReceivingRedelegation(ctx sdk.Context,
|
|||
// set a redelegation and associated index
|
||||
func (k Keeper) SetRedelegation(ctx sdk.Context, red types.Redelegation) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := k.cdc.MustMarshalBinary(red)
|
||||
redKey := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc)
|
||||
store.Set(redKey, bz)
|
||||
store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey)
|
||||
store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc), redKey)
|
||||
bz := types.MustMarshalRED(k.cdc, red)
|
||||
key := GetREDKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr)
|
||||
store.Set(key, bz)
|
||||
store.Set(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{})
|
||||
store.Set(GetREDByValDstIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr), []byte{})
|
||||
}
|
||||
|
||||
// remove a redelegation object and associated index
|
||||
func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) {
|
||||
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(GetREDByValSrcIndexKey(red.DelegatorAddr, red.ValidatorSrcAddr, red.ValidatorDstAddr, k.cdc))
|
||||
store.Delete(GetREDByValDstIndexKey(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))
|
||||
}
|
||||
|
||||
//_____________________________________________________________________________________
|
||||
|
|
|
@ -179,6 +179,36 @@ func TestUnbondDelegation(t *testing.T) {
|
|||
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
|
||||
func TestRedelegation(t *testing.T) {
|
||||
ctx, _, keeper := CreateTestInput(t, false, 0)
|
||||
|
@ -201,7 +231,10 @@ func TestRedelegation(t *testing.T) {
|
|||
keeper.SetRedelegation(ctx, rd)
|
||||
resBond, found := keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||
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
|
||||
has = keeper.HasReceivingRedelegation(ctx, addrDels[0], addrVals[1])
|
||||
|
@ -211,10 +244,15 @@ func TestRedelegation(t *testing.T) {
|
|||
rd.SharesSrc = sdk.NewRat(21)
|
||||
rd.SharesDst = sdk.NewRat(21)
|
||||
keeper.SetRedelegation(ctx, rd)
|
||||
|
||||
resBond, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||
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))
|
||||
|
||||
// delete a record
|
||||
keeper.RemoveRedelegation(ctx, rd)
|
||||
_, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
|
@ -29,41 +28,49 @@ var (
|
|||
UnbondingDelegationKey = []byte{0x0B} // key for an unbonding-delegation
|
||||
UnbondingDelegationByValIndexKey = []byte{0x0C} // prefix for each key for an unbonding-delegation, by validator owner
|
||||
RedelegationKey = []byte{0x0D} // key for a redelegation
|
||||
RedelegationByValSrcIndexKey = []byte{0x0E} // prefix for each key for an redelegation, by validator owner
|
||||
RedelegationByValDstIndexKey = []byte{0x0F} // 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 destination validator owner
|
||||
)
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return append(ValidatorsBondedIndexKey, ownerAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// get the power which is the key for the validator used in the power-store
|
||||
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 validator owner address from ValBondedIndexKey
|
||||
func GetAddressFromValBondedIndexKey(IndexKey []byte) []byte {
|
||||
return IndexKey[1:] // remove prefix bytes
|
||||
}
|
||||
|
||||
// get the power of a validator
|
||||
func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
|
||||
// get the validator by power index. power index is the key used in the power-store,
|
||||
// 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)
|
||||
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)
|
||||
if validator.Revoked {
|
||||
revokedBytes[0] = byte(0x01)
|
||||
|
@ -71,127 +78,162 @@ func GetValidatorPowerRank(validator types.Validator, pool types.Pool) []byte {
|
|||
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 := make([]byte, binary.MaxVarintLen64)
|
||||
binary.BigEndian.PutUint64(heightBytes, ^uint64(validator.BondHeight)) // invert height (older validators first)
|
||||
counterBytes := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(counterBytes, ^uint16(validator.BondIntraTxCounter)) // invert counter (first txns have priority)
|
||||
|
||||
return append(ValidatorsByPowerIndexKey,
|
||||
append(revokedBytes,
|
||||
append(powerBytes,
|
||||
append(heightBytes, counterBytes...)...)...)...)
|
||||
return append(append(append(append(
|
||||
ValidatorsByPowerIndexKey,
|
||||
revokedBytes...),
|
||||
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 {
|
||||
return append(TendermintUpdatesKey, ownerAddr.Bytes()...)
|
||||
}
|
||||
|
||||
//________________________________________________________________________________
|
||||
|
||||
// get the key for delegator bond with validator
|
||||
func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
return append(GetDelegationsKey(delegatorAddr, cdc), validatorAddr.Bytes()...)
|
||||
// get the key for delegator bond with validator.
|
||||
// VALUE: stake/types.Delegation
|
||||
func GetDelegationKey(delegatorAddr, validatorAddr sdk.Address) []byte {
|
||||
return append(GetDelegationsKey(delegatorAddr), validatorAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// get the prefix for a delegator for all validators
|
||||
func GetDelegationsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
res := cdc.MustMarshalBinary(&delegatorAddr)
|
||||
return append(DelegationKey, res...)
|
||||
func GetDelegationsKey(delegatorAddr sdk.Address) []byte {
|
||||
return append(DelegationKey, delegatorAddr.Bytes()...)
|
||||
}
|
||||
|
||||
//________________________________________________________________________________
|
||||
|
||||
// get the key for an unbonding delegation
|
||||
func GetUBDKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
return append(GetUBDsKey(delegatorAddr, cdc), validatorAddr.Bytes()...)
|
||||
// get the key for an unbonding delegation by delegator and validator addr.
|
||||
// VALUE: stake/types.UnbondingDelegation
|
||||
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
|
||||
func GetUBDByValIndexKey(delegatorAddr, validatorAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
return append(GetUBDsByValIndexKey(validatorAddr, cdc), delegatorAddr.Bytes()...)
|
||||
// VALUE: none (key rearrangement used)
|
||||
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
|
||||
func GetUBDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
res := cdc.MustMarshalBinary(&delegatorAddr)
|
||||
return append(UnbondingDelegationKey, res...)
|
||||
func GetUBDsKey(delegatorAddr sdk.Address) []byte {
|
||||
return append(UnbondingDelegationKey, delegatorAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// get the prefix keyspace for the indexs of unbonding delegations for a validator
|
||||
func GetUBDsByValIndexKey(validatorAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
res := cdc.MustMarshalBinary(&validatorAddr)
|
||||
return append(UnbondingDelegationByValIndexKey, res...)
|
||||
// get the prefix keyspace for the indexes of unbonding delegations for a validator
|
||||
func GetUBDsByValIndexKey(validatorAddr sdk.Address) []byte {
|
||||
return append(UnbondingDelegationByValIndexKey, validatorAddr.Bytes()...)
|
||||
}
|
||||
|
||||
//________________________________________________________________________________
|
||||
|
||||
// get the key for a redelegation
|
||||
// VALUE: stake/types.RedelegationKey
|
||||
func GetREDKey(delegatorAddr, validatorSrcAddr,
|
||||
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
validatorDstAddr sdk.Address) []byte {
|
||||
|
||||
return append(
|
||||
GetREDsKey(delegatorAddr, cdc),
|
||||
append(
|
||||
validatorSrcAddr.Bytes(),
|
||||
validatorDstAddr.Bytes()...)...,
|
||||
)
|
||||
return append(append(
|
||||
GetREDsKey(delegatorAddr.Bytes()),
|
||||
validatorSrcAddr.Bytes()...),
|
||||
validatorDstAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// get the index-key for a redelegation, stored by source-validator-index
|
||||
// VALUE: none (key rearrangement used)
|
||||
func GetREDByValSrcIndexKey(delegatorAddr, validatorSrcAddr,
|
||||
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
validatorDstAddr sdk.Address) []byte {
|
||||
|
||||
return append(
|
||||
GetREDsFromValSrcIndexKey(validatorSrcAddr, cdc),
|
||||
append(
|
||||
delegatorAddr.Bytes(),
|
||||
validatorDstAddr.Bytes()...)...,
|
||||
)
|
||||
return append(append(
|
||||
GetREDsFromValSrcIndexKey(validatorSrcAddr),
|
||||
delegatorAddr.Bytes()...),
|
||||
validatorDstAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// get the index-key for a redelegation, stored by destination-validator-index
|
||||
// VALUE: none (key rearrangement used)
|
||||
func GetREDByValDstIndexKey(delegatorAddr, validatorSrcAddr,
|
||||
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
validatorDstAddr sdk.Address) []byte {
|
||||
|
||||
return append(
|
||||
GetREDsToValDstIndexKey(validatorDstAddr, cdc),
|
||||
append(
|
||||
delegatorAddr.Bytes(),
|
||||
validatorSrcAddr.Bytes()...)...,
|
||||
)
|
||||
return append(append(
|
||||
GetREDsToValDstIndexKey(validatorDstAddr),
|
||||
delegatorAddr.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
|
||||
func GetREDsKey(delegatorAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
res := cdc.MustMarshalBinary(&delegatorAddr)
|
||||
return append(RedelegationKey, res...)
|
||||
func GetREDsKey(delegatorAddr sdk.Address) []byte {
|
||||
return append(RedelegationKey, delegatorAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// get the prefix keyspace for all redelegations redelegating away from a source validator
|
||||
func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
res := cdc.MustMarshalBinary(&validatorSrcAddr)
|
||||
return append(RedelegationByValSrcIndexKey, res...)
|
||||
func GetREDsFromValSrcIndexKey(validatorSrcAddr sdk.Address) []byte {
|
||||
return append(RedelegationByValSrcIndexKey, validatorSrcAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// get the prefix keyspace for all redelegations redelegating towards a destination validator
|
||||
func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
res := cdc.MustMarshalBinary(&validatorDstAddr)
|
||||
return append(RedelegationByValDstIndexKey, res...)
|
||||
func GetREDsToValDstIndexKey(validatorDstAddr sdk.Address) []byte {
|
||||
return append(RedelegationByValDstIndexKey, validatorDstAddr.Bytes()...)
|
||||
}
|
||||
|
||||
// get the prefix keyspace for all redelegations redelegating towards a destination validator
|
||||
// from a particular delegator
|
||||
func GetREDsByDelToValDstIndexKey(delegatorAddr sdk.Address,
|
||||
validatorDstAddr sdk.Address, cdc *wire.Codec) []byte {
|
||||
validatorDstAddr sdk.Address) []byte {
|
||||
|
||||
return append(
|
||||
GetREDsToValDstIndexKey(validatorDstAddr, cdc),
|
||||
GetREDsToValDstIndexKey(validatorDstAddr),
|
||||
delegatorAddr.Bytes()...)
|
||||
}
|
||||
|
|
|
@ -16,9 +16,8 @@ func (k Keeper) IterateValidators(ctx sdk.Context, fn func(index int64, validato
|
|||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey)
|
||||
i := int64(0)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
bz := iterator.Value()
|
||||
var validator types.Validator
|
||||
k.cdc.MustUnmarshalBinary(bz, &validator)
|
||||
addr := iterator.Key()[1:]
|
||||
validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
|
||||
stop := fn(i, validator) // XXX is this safe will the validator unexposed fields be able to get written to?
|
||||
if stop {
|
||||
break
|
||||
|
@ -34,7 +33,7 @@ func (k Keeper) IterateValidatorsBonded(ctx sdk.Context, fn func(index int64, va
|
|||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
||||
i := int64(0)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
address := iterator.Value()
|
||||
address := GetAddressFromValBondedIndexKey(iterator.Key())
|
||||
validator, found := k.GetValidator(ctx, address)
|
||||
if !found {
|
||||
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
|
||||
func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.Address, fn func(index int64, delegation sdk.Delegation) (stop bool)) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
key := GetDelegationsKey(delAddr, k.cdc)
|
||||
key := GetDelegationsKey(delAddr)
|
||||
iterator := sdk.KVStorePrefixIterator(store, key)
|
||||
i := int64(0)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
bz := iterator.Value()
|
||||
var delegation types.Delegation
|
||||
k.cdc.MustUnmarshalBinary(bz, &delegation)
|
||||
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
|
||||
stop := fn(i, delegation) // XXX is this safe will the fields be able to get written to?
|
||||
if stop {
|
||||
break
|
||||
|
|
|
@ -14,11 +14,11 @@ import (
|
|||
// get a single validator
|
||||
func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator types.Validator, found bool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := store.Get(GetValidatorKey(addr))
|
||||
if b == nil {
|
||||
value := store.Get(GetValidatorKey(addr))
|
||||
if value == nil {
|
||||
return validator, false
|
||||
}
|
||||
k.cdc.MustUnmarshalBinary(b, &validator)
|
||||
validator = types.MustUnmarshalValidator(k.cdc, addr, value)
|
||||
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
|
||||
func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
// set main store
|
||||
bz := k.cdc.MustMarshalBinary(validator)
|
||||
bz := types.MustMarshalValidator(k.cdc, validator)
|
||||
store.Set(GetValidatorKey(validator.Owner), bz)
|
||||
}
|
||||
|
||||
// validator index
|
||||
func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
// set pointer by pubkey
|
||||
store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner)
|
||||
}
|
||||
|
||||
|
@ -56,7 +54,7 @@ func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Valida
|
|||
// validator index
|
||||
func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner)
|
||||
store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{})
|
||||
}
|
||||
|
||||
// used in testing
|
||||
|
@ -75,9 +73,8 @@ func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator)
|
|||
if !iterator.Valid() {
|
||||
break
|
||||
}
|
||||
bz := iterator.Value()
|
||||
var validator types.Validator
|
||||
k.cdc.MustUnmarshalBinary(bz, &validator)
|
||||
addr := iterator.Key()[1:]
|
||||
validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
|
||||
validators = append(validators, validator)
|
||||
iterator.Next()
|
||||
}
|
||||
|
@ -96,9 +93,8 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators []
|
|||
if !iterator.Valid() || i > int(maxRetrieve-1) {
|
||||
break
|
||||
}
|
||||
bz := iterator.Value()
|
||||
var validator types.Validator
|
||||
k.cdc.MustUnmarshalBinary(bz, &validator)
|
||||
addr := iterator.Key()[1:]
|
||||
validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
|
||||
validators[i] = validator
|
||||
iterator.Next()
|
||||
}
|
||||
|
@ -124,7 +120,7 @@ func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validat
|
|||
if i > int(maxValidators-1) {
|
||||
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)
|
||||
if !found {
|
||||
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
|
||||
defer func() {
|
||||
bz := k.cdc.MustMarshalBinary(validator)
|
||||
store.Set(GetValidatorKey(ownerAddr), bz)
|
||||
k.SetValidator(ctx, validator)
|
||||
}()
|
||||
|
||||
// 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
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -388,7 +390,7 @@ func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) {
|
|||
toKickOut := make(map[string]byte)
|
||||
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
||||
for ; iterator.Valid(); iterator.Next() {
|
||||
ownerAddr := iterator.Value()
|
||||
ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key())
|
||||
toKickOut[string(ownerAddr)] = 0 // set anything
|
||||
}
|
||||
iterator.Close()
|
||||
|
@ -465,8 +467,7 @@ func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) type
|
|||
k.SetPool(ctx, pool)
|
||||
|
||||
// save the now unbonded validator record
|
||||
bzVal := k.cdc.MustMarshalBinary(validator)
|
||||
store.Set(GetValidatorKey(validator.Owner), bzVal)
|
||||
k.SetValidator(ctx, validator)
|
||||
|
||||
// add to accumulated changes for tendermint
|
||||
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)
|
||||
|
||||
// save the now bonded validator record to the three referenced stores
|
||||
bzVal := k.cdc.MustMarshalBinary(validator)
|
||||
store.Set(GetValidatorKey(validator.Owner), bzVal)
|
||||
store.Set(GetValidatorsBondedIndexKey(validator.Owner), validator.Owner)
|
||||
k.SetValidator(ctx, validator)
|
||||
store.Set(GetValidatorsBondedIndexKey(validator.Owner), []byte{})
|
||||
|
||||
// add to accumulated changes for tendermint
|
||||
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
||||
|
|
|
@ -675,3 +675,43 @@ func TestGetTendermintUpdatesNotValidatorCliff(t *testing.T) {
|
|||
require.Equal(t, validators[0].ABCIValidatorZero(), updates[0])
|
||||
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])
|
||||
}
|
||||
|
|
|
@ -7,30 +7,29 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
)
|
||||
|
||||
// keeper
|
||||
type Keeper = keeper.Keeper
|
||||
|
||||
var NewKeeper = keeper.NewKeeper
|
||||
|
||||
// types
|
||||
type Validator = types.Validator
|
||||
type Description = types.Description
|
||||
type Delegation = types.Delegation
|
||||
type UnbondingDelegation = types.UnbondingDelegation
|
||||
type Redelegation = types.Redelegation
|
||||
type Params = types.Params
|
||||
type Pool = types.Pool
|
||||
type PoolShares = types.PoolShares
|
||||
type MsgCreateValidator = types.MsgCreateValidator
|
||||
type MsgEditValidator = types.MsgEditValidator
|
||||
type MsgDelegate = types.MsgDelegate
|
||||
type MsgBeginUnbonding = types.MsgBeginUnbonding
|
||||
type MsgCompleteUnbonding = types.MsgCompleteUnbonding
|
||||
type MsgBeginRedelegate = types.MsgBeginRedelegate
|
||||
type MsgCompleteRedelegate = types.MsgCompleteRedelegate
|
||||
type GenesisState = types.GenesisState
|
||||
type (
|
||||
Keeper = keeper.Keeper
|
||||
Validator = types.Validator
|
||||
Description = types.Description
|
||||
Delegation = types.Delegation
|
||||
UnbondingDelegation = types.UnbondingDelegation
|
||||
Redelegation = types.Redelegation
|
||||
Params = types.Params
|
||||
Pool = types.Pool
|
||||
PoolShares = types.PoolShares
|
||||
MsgCreateValidator = types.MsgCreateValidator
|
||||
MsgEditValidator = types.MsgEditValidator
|
||||
MsgDelegate = types.MsgDelegate
|
||||
MsgBeginUnbonding = types.MsgBeginUnbonding
|
||||
MsgCompleteUnbonding = types.MsgCompleteUnbonding
|
||||
MsgBeginRedelegate = types.MsgBeginRedelegate
|
||||
MsgCompleteRedelegate = types.MsgCompleteRedelegate
|
||||
GenesisState = types.GenesisState
|
||||
)
|
||||
|
||||
var (
|
||||
NewKeeper = keeper.NewKeeper
|
||||
|
||||
GetValidatorKey = keeper.GetValidatorKey
|
||||
GetValidatorByPubKeyIndexKey = keeper.GetValidatorByPubKeyIndexKey
|
||||
GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey
|
||||
|
@ -72,7 +71,6 @@ var (
|
|||
DefaultGenesisState = types.DefaultGenesisState
|
||||
RegisterWire = types.RegisterWire
|
||||
|
||||
// messages
|
||||
NewMsgCreateValidator = types.NewMsgCreateValidator
|
||||
NewMsgEditValidator = types.NewMsgEditValidator
|
||||
NewMsgDelegate = types.NewMsgDelegate
|
||||
|
@ -82,7 +80,6 @@ var (
|
|||
NewMsgCompleteRedelegate = types.NewMsgCompleteRedelegate
|
||||
)
|
||||
|
||||
// errors
|
||||
const (
|
||||
DefaultCodespace = types.DefaultCodespace
|
||||
CodeInvalidValidator = types.CodeInvalidValidator
|
||||
|
@ -126,7 +123,6 @@ var (
|
|||
ErrMissingSignature = types.ErrMissingSignature
|
||||
)
|
||||
|
||||
// tags
|
||||
var (
|
||||
ActionCreateValidator = tags.ActionCreateValidator
|
||||
ActionEditValidator = tags.ActionEditValidator
|
||||
|
|
|
@ -2,9 +2,11 @@ package types
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
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
|
||||
|
@ -17,7 +19,54 @@ type Delegation struct {
|
|||
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 {
|
||||
return bytes.Equal(d.DelegatorAddr, d2.DelegatorAddr) &&
|
||||
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) 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) {
|
||||
bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp := "Delegation \n"
|
||||
resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
|
||||
resp += fmt.Sprintf("Validator: %s\n", bechVal)
|
||||
|
@ -50,12 +103,9 @@ func (d Delegation) HumanReadableString() (string, error) {
|
|||
resp += fmt.Sprintf("Height: %d", d.Height)
|
||||
|
||||
return resp, nil
|
||||
|
||||
}
|
||||
|
||||
//__________________________________________________________________
|
||||
|
||||
// element stored to represent the passive unbonding queue
|
||||
// UnbondingDelegation reflects a delegation's passive unbonding queue.
|
||||
type UnbondingDelegation struct {
|
||||
DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool {
|
||||
bz1 := MsgCdc.MustMarshalBinary(&d)
|
||||
|
@ -72,16 +175,20 @@ func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool {
|
|||
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) {
|
||||
bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bechVal, err := sdk.Bech32ifyAcc(d.ValidatorAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp := "Unbonding Delegation \n"
|
||||
resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
|
||||
resp += fmt.Sprintf("Validator: %s\n", bechVal)
|
||||
|
@ -93,9 +200,7 @@ func (d UnbondingDelegation) HumanReadableString() (string, error) {
|
|||
|
||||
}
|
||||
|
||||
//__________________________________________________________________
|
||||
|
||||
// element stored to represent the passive redelegation queue
|
||||
// Redelegation reflects a delegation's passive re-delegation queue.
|
||||
type Redelegation struct {
|
||||
DelegatorAddr sdk.Address `json:"delegator_addr"` // delegator
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
func (d Redelegation) Equal(d2 Redelegation) bool {
|
||||
bz1 := MsgCdc.MustMarshalBinary(&d)
|
||||
|
@ -115,20 +281,25 @@ func (d Redelegation) Equal(d2 Redelegation) bool {
|
|||
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) {
|
||||
bechAcc, err := sdk.Bech32ifyAcc(d.DelegatorAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bechValSrc, err := sdk.Bech32ifyAcc(d.ValidatorSrcAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bechValDst, err := sdk.Bech32ifyAcc(d.ValidatorDstAddr)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resp := "Redelegation \n"
|
||||
resp += fmt.Sprintf("Delegator: %s\n", bechAcc)
|
||||
resp += fmt.Sprintf("Source Validator: %s\n", bechValSrc)
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -25,97 +25,118 @@ const (
|
|||
func ErrNilValidatorAddr(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidInput, "validator address is nil")
|
||||
}
|
||||
|
||||
func ErrNoValidatorFound(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidValidator, "validator does not exist for that address")
|
||||
}
|
||||
|
||||
func ErrValidatorAlreadyExists(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidValidator, "validator already exist, cannot re-create validator")
|
||||
}
|
||||
|
||||
func ErrValidatorRevoked(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidValidator, "validator for this address is currently revoked")
|
||||
}
|
||||
|
||||
func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidValidator, "error removing validator")
|
||||
}
|
||||
|
||||
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)
|
||||
return sdk.NewError(codespace, CodeInvalidValidator, msg)
|
||||
}
|
||||
|
||||
func ErrCommissionNegative(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidValidator, "commission must be positive")
|
||||
}
|
||||
|
||||
func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%")
|
||||
}
|
||||
|
||||
// delegation
|
||||
func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil")
|
||||
}
|
||||
|
||||
func ErrBadDenom(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "invalid coin denomination")
|
||||
}
|
||||
|
||||
func ErrBadDelegationAmount(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "amount must be > 0")
|
||||
}
|
||||
|
||||
func ErrNoDelegation(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "no delegation for this (address, validator) pair")
|
||||
}
|
||||
|
||||
func ErrBadDelegatorAddr(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not exist for that address")
|
||||
}
|
||||
|
||||
func ErrNoDelegatorForAddress(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "delegator does not contain this delegation")
|
||||
}
|
||||
|
||||
func ErrInsufficientShares(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "insufficient delegation shares")
|
||||
}
|
||||
|
||||
func ErrDelegationValidatorEmpty(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "cannot delegate to an empty validator")
|
||||
}
|
||||
|
||||
func ErrNotEnoughDelegationShares(codespace sdk.CodespaceType, shares string) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, fmt.Sprintf("not enough shares only have %v", shares))
|
||||
}
|
||||
|
||||
func ErrBadSharesAmount(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "shares must be > 0")
|
||||
}
|
||||
|
||||
func ErrBadSharesPrecision(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation,
|
||||
fmt.Sprintf("shares denominator must be < %s, try reducing the number of decimal points",
|
||||
maximumBondingRationalDenominator.String()),
|
||||
)
|
||||
}
|
||||
|
||||
func ErrBadSharesPercent(codespace sdk.CodespaceType) sdk.Error {
|
||||
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 {
|
||||
msg := fmt.Sprintf("%v is not mature requires a min %v of %v, currently it is %v",
|
||||
operation, descriptor, got, min)
|
||||
return sdk.NewError(codespace, CodeUnauthorized, msg)
|
||||
}
|
||||
|
||||
func ErrNoUnbondingDelegation(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "no unbonding delegation found")
|
||||
}
|
||||
|
||||
func ErrNoRedelegation(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "no redelegation found")
|
||||
}
|
||||
|
||||
func ErrBadRedelegationDst(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation, "redelegation validator not found")
|
||||
}
|
||||
|
||||
func ErrTransitiveRedelegation(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDelegation,
|
||||
"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 {
|
||||
return sdk.NewError(codespace, CodeInvalidInput, "both shares amount and shares percent provided")
|
||||
}
|
||||
|
||||
func ErrNeitherShareMsgsGiven(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidInput, "neither shares amount nor shares percent provided")
|
||||
}
|
||||
|
||||
func ErrMissingSignature(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidValidator, "missing signature")
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ func (msg MsgCreateValidator) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
|
@ -114,7 +114,7 @@ func (msg MsgEditValidator) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
|
@ -166,7 +166,7 @@ func (msg MsgDelegate) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
|
@ -226,7 +226,7 @@ func (msg MsgBeginRedelegate) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
|
@ -286,7 +286,7 @@ func (msg MsgCompleteRedelegate) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
|
@ -338,7 +338,7 @@ func (msg MsgBeginUnbonding) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
|
@ -387,7 +387,7 @@ func (msg MsgCompleteUnbonding) GetSignBytes() []byte {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
return sdk.MustSortJSON(b)
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue