Merge pull request #112 from CosmWasm/staking-contract

Integration tests with staking contract
This commit is contained in:
Ethan Frey
2020-05-18 22:14:29 +02:00
committed by GitHub
11 changed files with 634 additions and 36 deletions

2
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/CosmWasm/wasmd
go 1.13
require (
github.com/CosmWasm/go-cosmwasm v0.8.0-alpha2
github.com/CosmWasm/go-cosmwasm v0.8.0-alpha2.0.20200518133220-76a4987de98b
github.com/btcsuite/btcd v0.0.0-20190807005414-4063feeff79a // indirect
github.com/cosmos/cosmos-sdk v0.38.3
github.com/golang/mock v1.4.3 // indirect

4
go.sum
View File

@@ -13,6 +13,10 @@ github.com/CosmWasm/go-cosmwasm v0.7.3-0.20200506091810-b5d72f383001 h1:QvYlAMha
github.com/CosmWasm/go-cosmwasm v0.7.3-0.20200506091810-b5d72f383001/go.mod h1:gAFCwllx97ejI+m9SqJQrmd2SBW7HA0fOjvWWJjM2uc=
github.com/CosmWasm/go-cosmwasm v0.8.0-alpha2 h1:CRITYzG25XuBFfoft+zuRKtJk37/PxNXXKXAje7iv1Q=
github.com/CosmWasm/go-cosmwasm v0.8.0-alpha2/go.mod h1:gAFCwllx97ejI+m9SqJQrmd2SBW7HA0fOjvWWJjM2uc=
github.com/CosmWasm/go-cosmwasm v0.8.0-alpha2.0.20200518132754-acf959da37ac h1:8iIQdsex6lXfwxGf/ju82M0VoYu6apmclJAuAtRUCzc=
github.com/CosmWasm/go-cosmwasm v0.8.0-alpha2.0.20200518132754-acf959da37ac/go.mod h1:gAFCwllx97ejI+m9SqJQrmd2SBW7HA0fOjvWWJjM2uc=
github.com/CosmWasm/go-cosmwasm v0.8.0-alpha2.0.20200518133220-76a4987de98b h1:AKCZCqgZAQnmJdCh4mnk23NoLzoyKQIowckBLnhrLlM=
github.com/CosmWasm/go-cosmwasm v0.8.0-alpha2.0.20200518133220-76a4987de98b/go.mod h1:gAFCwllx97ejI+m9SqJQrmd2SBW7HA0fOjvWWJjM2uc=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=

View File

@@ -25,15 +25,16 @@ func TestNewKeeper(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
_, _, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
require.NotNil(t, keeper)
_, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
require.NotNil(t, keepers.WasmKeeper)
}
func TestCreate(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
@@ -54,7 +55,8 @@ func TestCreateDuplicate(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
@@ -85,7 +87,9 @@ func TestCreateWithSimulation(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
ctx = ctx.WithBlockHeader(abci.Header{Height: 1}).
WithGasMeter(stypes.NewInfiniteGasMeter())
@@ -101,7 +105,8 @@ func TestCreateWithSimulation(t *testing.T) {
require.Equal(t, uint64(1), contractID)
// then try to create it in non-simulation mode (should not fail)
ctx, accKeeper, keeper = CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers = CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper = keepers.AccountKeeper, keepers.WasmKeeper
contractID, err = keeper.Create(ctx, creator, wasmCode, "https://github.com/CosmWasm/wasmd/blob/master/x/wasm/testdata/escrow.wasm", "confio/cosmwasm-opt:0.7.2")
require.NoError(t, err)
require.Equal(t, uint64(1), contractID)
@@ -141,7 +146,8 @@ func TestCreateWithGzippedPayload(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
@@ -164,7 +170,8 @@ func TestInstantiate(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
@@ -208,7 +215,8 @@ func TestInstantiateWithNonExistingCodeID(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
@@ -229,7 +237,8 @@ func TestExecute(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
@@ -306,7 +315,8 @@ func TestExecuteWithNonExistingAddress(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit.Add(deposit...))
@@ -321,7 +331,8 @@ func TestExecuteWithPanic(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
@@ -354,7 +365,8 @@ func TestExecuteWithCpuLoop(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
@@ -395,7 +407,8 @@ func TestExecuteWithStorageLoop(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))

View File

@@ -19,7 +19,8 @@ func TestQueryContractState(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
@@ -147,7 +148,8 @@ func TestListContractByCodeOrdering(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000000))
topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 500))

View File

@@ -2,7 +2,6 @@ package keeper
import (
"encoding/json"
wasmTypes "github.com/CosmWasm/go-cosmwasm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -109,8 +108,16 @@ func NoCustomQuerier(ctx sdk.Context, request json.RawMessage) ([]byte, error) {
func StakingQuerier(keeper staking.Keeper) func(ctx sdk.Context, request *wasmTypes.StakingQuery) ([]byte, error) {
return func(ctx sdk.Context, request *wasmTypes.StakingQuery) ([]byte, error) {
if request.BondedDenom != nil {
denom := keeper.BondDenom(ctx)
res := wasmTypes.BondedDenomResponse{
Denom: denom,
}
return json.Marshal(res)
}
if request.Validators != nil {
validators := keeper.GetBondedValidatorsByPower(ctx)
//validators := keeper.GetAllValidators(ctx)
wasmVals := make([]wasmTypes.Validator, len(validators))
for i, v := range validators {
wasmVals[i] = wasmTypes.Validator{

View File

@@ -55,14 +55,15 @@ func TestMaskReflectContractSend(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, MaskFeatures, maskEncoders(MakeTestCodec()), nil)
ctx, keepers := CreateTestInput(t, false, tempDir, MaskFeatures, maskEncoders(MakeTestCodec()), nil)
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
_, _, bob := keyPubAddr()
// upload mask code
maskCode, err := ioutil.ReadFile("./testdata/mask.wasm")
maskCode, err := ioutil.ReadFile("./testdata/reflect.wasm")
require.NoError(t, err)
maskID, err := keeper.Create(ctx, creator, maskCode, "", "")
require.NoError(t, err)
@@ -138,7 +139,8 @@ func TestMaskReflectCustomMsg(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, MaskFeatures, maskEncoders(MakeTestCodec()), maskPlugins())
ctx, keepers := CreateTestInput(t, false, tempDir, MaskFeatures, maskEncoders(MakeTestCodec()), maskPlugins())
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
@@ -146,7 +148,7 @@ func TestMaskReflectCustomMsg(t *testing.T) {
_, _, fred := keyPubAddr()
// upload code
maskCode, err := ioutil.ReadFile("./testdata/mask.wasm")
maskCode, err := ioutil.ReadFile("./testdata/reflect.wasm")
require.NoError(t, err)
codeID, err := keeper.Create(ctx, creator, maskCode, "", "")
require.NoError(t, err)
@@ -233,13 +235,14 @@ func TestMaskReflectCustomQuery(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir, MaskFeatures, maskEncoders(MakeTestCodec()), maskPlugins())
ctx, keepers := CreateTestInput(t, false, tempDir, MaskFeatures, maskEncoders(MakeTestCodec()), maskPlugins())
accKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
// upload code
maskCode, err := ioutil.ReadFile("./testdata/mask.wasm")
maskCode, err := ioutil.ReadFile("./testdata/reflect.wasm")
require.NoError(t, err)
codeID, err := keeper.Create(ctx, creator, maskCode, "", "")
require.NoError(t, err)

View File

@@ -0,0 +1,502 @@
package keeper
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/assert"
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
)
type StakingInitMsg struct {
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals uint8 `json:"decimals"`
Validator sdk.ValAddress `json:"validator"`
ExitTax sdk.Dec `json:"exit_tax"`
// MinWithdrawl is uint128 encoded as a string (use sdk.Int?)
MinWithdrawl string `json:"min_withdrawl"`
}
// StakingHandleMsg is used to encode handle messages
type StakingHandleMsg struct {
Transfer *transferPayload `json:"transfer,omitempty"`
Bond *struct{} `json:"bond,omitempty"`
Unbond *unbondPayload `json:"unbond,omitempty"`
Claim *struct{} `json:"claim,omitempty"`
Reinvest *struct{} `json:"reinvest,omitempty"`
Change *ownerPayload `json:"change_owner,omitempty"`
}
type transferPayload struct {
Recipient sdk.Address `json:"recipient"`
// uint128 encoded as string
Amount string `json:"amount"`
}
type unbondPayload struct {
// uint128 encoded as string
Amount string `json:"amount"`
}
// StakingQueryMsg is used to encode query messages
type StakingQueryMsg struct {
Balance *addressQuery `json:"balance,omitempty"`
Claims *addressQuery `json:"claims,omitempty"`
TokenInfo *struct{} `json:"token_info,omitempty"`
Investment *struct{} `json:"investment,omitempty"`
}
type addressQuery struct {
Address sdk.AccAddress `json:"address"`
}
type BalanceResponse struct {
Balance string `json:"balance,omitempty"`
}
type ClaimsResponse struct {
Claims string `json:"claims,omitempty"`
}
type TokenInfoResponse struct {
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals uint8 `json:"decimals"`
}
type InvestmentResponse struct {
TokenSupply string `json:"token_supply"`
StakedTokens sdk.Coin `json:"staked_tokens"`
NominalValue sdk.Dec `json:"nominal_value"`
Owner sdk.AccAddress `json:"owner"`
Validator sdk.ValAddress `json:"validator"`
ExitTax sdk.Dec `json:"exit_tax"`
// MinWithdrawl is uint128 encoded as a string (use sdk.Int?)
MinWithdrawl string `json:"min_withdrawl"`
}
func TestInitializeStaking(t *testing.T) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, stakingKeeper, keeper := keepers.AccountKeeper, keepers.StakingKeeper, keepers.WasmKeeper
valAddr := addValidator(ctx, stakingKeeper, accKeeper, sdk.NewInt64Coin("stake", 1234567))
ctx = nextBlock(ctx, stakingKeeper)
v, found := stakingKeeper.GetValidator(ctx, valAddr)
assert.True(t, found)
assert.Equal(t, v.GetDelegatorShares(), sdk.NewDec(1234567))
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000), sdk.NewInt64Coin("stake", 500000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
// upload staking derivates code
stakingCode, err := ioutil.ReadFile("./testdata/staking.wasm")
require.NoError(t, err)
stakingID, err := keeper.Create(ctx, creator, stakingCode, "", "")
require.NoError(t, err)
require.Equal(t, uint64(1), stakingID)
// register to a valid address
initMsg := StakingInitMsg{
Name: "Staking Derivatives",
Symbol: "DRV",
Decimals: 0,
Validator: valAddr,
ExitTax: sdk.MustNewDecFromStr("0.10"),
MinWithdrawl: "100",
}
initBz, err := json.Marshal(&initMsg)
require.NoError(t, err)
stakingAddr, err := keeper.Instantiate(ctx, stakingID, creator, initBz, "staking derivates - DRV", nil)
require.NoError(t, err)
require.NotEmpty(t, stakingAddr)
// nothing spent here
checkAccount(t, ctx, accKeeper, creator, deposit)
// try to register with a validator not on the list and it fails
_, _, bob := keyPubAddr()
badInitMsg := StakingInitMsg{
Name: "Missing Validator",
Symbol: "MISS",
Decimals: 0,
Validator: sdk.ValAddress(bob),
ExitTax: sdk.MustNewDecFromStr("0.10"),
MinWithdrawl: "100",
}
badBz, err := json.Marshal(&badInitMsg)
require.NoError(t, err)
_, err = keeper.Instantiate(ctx, stakingID, creator, badBz, "missing validator", nil)
require.Error(t, err)
// no changes to bonding shares
val, _ := stakingKeeper.GetValidator(ctx, valAddr)
assert.Equal(t, val.GetDelegatorShares(), sdk.NewDec(1234567))
}
type initInfo struct {
valAddr sdk.ValAddress
creator sdk.AccAddress
contractAddr sdk.AccAddress
ctx sdk.Context
accKeeper auth.AccountKeeper
stakingKeeper staking.Keeper
distKeeper distribution.Keeper
wasmKeeper Keeper
cleanup func()
}
func initializeStaking(t *testing.T) initInfo {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
ctx, keepers := CreateTestInput(t, false, tempDir, SupportedFeatures, nil, nil)
accKeeper, stakingKeeper, keeper := keepers.AccountKeeper, keepers.StakingKeeper, keepers.WasmKeeper
valAddr := addValidator(ctx, stakingKeeper, accKeeper, sdk.NewInt64Coin("stake", 1000000))
ctx = nextBlock(ctx, stakingKeeper)
// set some baseline - this seems to be needed
keepers.DistKeeper.SetValidatorHistoricalRewards(ctx, valAddr, 0, distribution.ValidatorHistoricalRewards{
CumulativeRewardRatio: sdk.DecCoins{},
ReferenceCount: 1,
})
v, found := stakingKeeper.GetValidator(ctx, valAddr)
assert.True(t, found)
assert.Equal(t, v.GetDelegatorShares(), sdk.NewDec(1000000))
assert.Equal(t, v.Status, sdk.Bonded)
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000), sdk.NewInt64Coin("stake", 500000))
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
// upload staking derivates code
stakingCode, err := ioutil.ReadFile("./testdata/staking.wasm")
require.NoError(t, err)
stakingID, err := keeper.Create(ctx, creator, stakingCode, "", "")
require.NoError(t, err)
require.Equal(t, uint64(1), stakingID)
// register to a valid address
initMsg := StakingInitMsg{
Name: "Staking Derivatives",
Symbol: "DRV",
Decimals: 0,
Validator: valAddr,
ExitTax: sdk.MustNewDecFromStr("0.10"),
MinWithdrawl: "100",
}
initBz, err := json.Marshal(&initMsg)
require.NoError(t, err)
stakingAddr, err := keeper.Instantiate(ctx, stakingID, creator, initBz, "staking derivates - DRV", nil)
require.NoError(t, err)
require.NotEmpty(t, stakingAddr)
return initInfo{
valAddr: valAddr,
creator: creator,
contractAddr: stakingAddr,
ctx: ctx,
accKeeper: accKeeper,
stakingKeeper: stakingKeeper,
wasmKeeper: keeper,
distKeeper: keepers.DistKeeper,
cleanup: func() { os.RemoveAll(tempDir) },
}
}
func TestBonding(t *testing.T) {
initInfo := initializeStaking(t)
defer initInfo.cleanup()
ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr
keeper, stakingKeeper, accKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper, initInfo.accKeeper
// initial checks of bonding state
val, found := stakingKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
initPower := val.GetDelegatorShares()
// bob has 160k, putting 80k into the contract
full := sdk.NewCoins(sdk.NewInt64Coin("stake", 160000))
funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 80000))
bob := createFakeFundedAccount(ctx, accKeeper, full)
// check contract state before
assertBalance(t, ctx, keeper, contractAddr, bob, "0")
assertClaims(t, ctx, keeper, contractAddr, bob, "0")
assertSupply(t, ctx, keeper, contractAddr, "0", sdk.NewInt64Coin("stake", 0))
bond := StakingHandleMsg{
Bond: &struct{}{},
}
bondBz, err := json.Marshal(bond)
require.NoError(t, err)
_, err = keeper.Execute(ctx, contractAddr, bob, bondBz, funds)
require.NoError(t, err)
// check some account values - the money is on neither account (cuz it is bonded)
checkAccount(t, ctx, accKeeper, contractAddr, sdk.Coins{})
checkAccount(t, ctx, accKeeper, bob, funds)
// make sure the proper number of tokens have been bonded
val, _ = stakingKeeper.GetValidator(ctx, valAddr)
finalPower := val.GetDelegatorShares()
assert.Equal(t, sdk.NewInt(80000), finalPower.Sub(initPower).TruncateInt())
// check the delegation itself
d, found := stakingKeeper.GetDelegation(ctx, contractAddr, valAddr)
require.True(t, found)
assert.Equal(t, d.Shares, sdk.MustNewDecFromStr("80000"))
// check we have the desired balance
assertBalance(t, ctx, keeper, contractAddr, bob, "80000")
assertClaims(t, ctx, keeper, contractAddr, bob, "0")
assertSupply(t, ctx, keeper, contractAddr, "80000", sdk.NewInt64Coin("stake", 80000))
}
func TestUnbonding(t *testing.T) {
initInfo := initializeStaking(t)
defer initInfo.cleanup()
ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr
keeper, stakingKeeper, accKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper, initInfo.accKeeper
// initial checks of bonding state
val, found := stakingKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
initPower := val.GetDelegatorShares()
// bob has 160k, putting 80k into the contract
full := sdk.NewCoins(sdk.NewInt64Coin("stake", 160000))
funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 80000))
bob := createFakeFundedAccount(ctx, accKeeper, full)
bond := StakingHandleMsg{
Bond: &struct{}{},
}
bondBz, err := json.Marshal(bond)
require.NoError(t, err)
_, err = keeper.Execute(ctx, contractAddr, bob, bondBz, funds)
require.NoError(t, err)
// update height a bit
ctx = nextBlock(ctx, stakingKeeper)
// now unbond 30k - note that 3k (10%) goes to the owner as a tax, 27k unbonded and available as claims
unbond := StakingHandleMsg{
Unbond: &unbondPayload{
Amount: "30000",
},
}
unbondBz, err := json.Marshal(unbond)
require.NoError(t, err)
_, err = keeper.Execute(ctx, contractAddr, bob, unbondBz, nil)
require.NoError(t, err)
// check some account values - the money is on neither account (cuz it is bonded)
// Note: why is this immediate? just test setup?
checkAccount(t, ctx, accKeeper, contractAddr, sdk.Coins{})
checkAccount(t, ctx, accKeeper, bob, funds)
// make sure the proper number of tokens have been bonded (80k - 27k = 53k)
val, _ = stakingKeeper.GetValidator(ctx, valAddr)
finalPower := val.GetDelegatorShares()
assert.Equal(t, sdk.NewInt(53000), finalPower.Sub(initPower).TruncateInt(), finalPower.String())
// check the delegation itself
d, found := stakingKeeper.GetDelegation(ctx, contractAddr, valAddr)
require.True(t, found)
assert.Equal(t, d.Shares, sdk.MustNewDecFromStr("53000"))
// check there is unbonding in progress
un, found := stakingKeeper.GetUnbondingDelegation(ctx, contractAddr, valAddr)
require.True(t, found)
require.Equal(t, 1, len(un.Entries))
assert.Equal(t, "27000", un.Entries[0].Balance.String())
// check we have the desired balance
assertBalance(t, ctx, keeper, contractAddr, bob, "50000")
assertBalance(t, ctx, keeper, contractAddr, initInfo.creator, "3000")
assertClaims(t, ctx, keeper, contractAddr, bob, "27000")
assertSupply(t, ctx, keeper, contractAddr, "53000", sdk.NewInt64Coin("stake", 53000))
}
func TestReinvest(t *testing.T) {
initInfo := initializeStaking(t)
defer initInfo.cleanup()
ctx, valAddr, contractAddr := initInfo.ctx, initInfo.valAddr, initInfo.contractAddr
keeper, stakingKeeper, accKeeper := initInfo.wasmKeeper, initInfo.stakingKeeper, initInfo.accKeeper
distKeeper := initInfo.distKeeper
// initial checks of bonding state
val, found := stakingKeeper.GetValidator(ctx, valAddr)
require.True(t, found)
initPower := val.GetDelegatorShares()
assert.Equal(t, val.Tokens, sdk.NewInt(1000000), "%s", val.Tokens)
// full is 2x funds, 1x goes to the contract, other stays on his wallet
full := sdk.NewCoins(sdk.NewInt64Coin("stake", 400000))
funds := sdk.NewCoins(sdk.NewInt64Coin("stake", 200000))
bob := createFakeFundedAccount(ctx, accKeeper, full)
// we will stake 200k to a validator with 1M self-bond
// this means we should get 1/6 of the rewards
bond := StakingHandleMsg{
Bond: &struct{}{},
}
bondBz, err := json.Marshal(bond)
require.NoError(t, err)
_, err = keeper.Execute(ctx, contractAddr, bob, bondBz, funds)
require.NoError(t, err)
// update height a bit to solidify the delegation
ctx = nextBlock(ctx, stakingKeeper)
// we get 1/6, our share should be 40k minus 10% commission = 36k
setValidatorRewards(ctx, stakingKeeper, distKeeper, valAddr, "240000")
// this should withdraw our outstanding 40k of rewards and reinvest them in the same delegation
reinvest := StakingHandleMsg{
Reinvest: &struct{}{},
}
reinvestBz, err := json.Marshal(reinvest)
require.NoError(t, err)
_, err = keeper.Execute(ctx, contractAddr, bob, reinvestBz, nil)
require.NoError(t, err)
// check some account values - the money is on neither account (cuz it is bonded)
// Note: why is this immediate? just test setup?
checkAccount(t, ctx, accKeeper, contractAddr, sdk.Coins{})
checkAccount(t, ctx, accKeeper, bob, funds)
// check the delegation itself
d, found := stakingKeeper.GetDelegation(ctx, contractAddr, valAddr)
require.True(t, found)
// we started with 200k and added 36k
assert.Equal(t, d.Shares, sdk.MustNewDecFromStr("236000"))
// make sure the proper number of tokens have been bonded (80k + 40k = 120k)
val, _ = stakingKeeper.GetValidator(ctx, valAddr)
finalPower := val.GetDelegatorShares()
assert.Equal(t, sdk.NewInt(236000), finalPower.Sub(initPower).TruncateInt(), finalPower.String())
// check there is no unbonding in progress
un, found := stakingKeeper.GetUnbondingDelegation(ctx, contractAddr, valAddr)
assert.False(t, found, "%#v", un)
// check we have the desired balance
assertBalance(t, ctx, keeper, contractAddr, bob, "200000")
assertBalance(t, ctx, keeper, contractAddr, initInfo.creator, "0")
assertClaims(t, ctx, keeper, contractAddr, bob, "0")
assertSupply(t, ctx, keeper, contractAddr, "200000", sdk.NewInt64Coin("stake", 236000))
}
// adds a few validators and returns a list of validators that are registered
func addValidator(ctx sdk.Context, stakingKeeper staking.Keeper, accountKeeper auth.AccountKeeper, value sdk.Coin) sdk.ValAddress {
_, pub, accAddr := keyPubAddr()
addr := sdk.ValAddress(accAddr)
owner := createFakeFundedAccount(ctx, accountKeeper, sdk.Coins{value})
msg := staking.MsgCreateValidator{
Description: types.Description{
Moniker: "Validator power",
},
Commission: types.CommissionRates{
Rate: sdk.MustNewDecFromStr("0.1"),
MaxRate: sdk.MustNewDecFromStr("0.2"),
MaxChangeRate: sdk.MustNewDecFromStr("0.01"),
},
MinSelfDelegation: sdk.OneInt(),
DelegatorAddress: owner,
ValidatorAddress: addr,
PubKey: pub,
Value: value,
}
h := staking.NewHandler(stakingKeeper)
_, err := h(ctx, msg)
if err != nil {
panic(err)
}
return addr
}
// this will commit the current set, update the block height and set historic info
// basically, letting two blocks pass
func nextBlock(ctx sdk.Context, stakingKeeper staking.Keeper) sdk.Context {
staking.EndBlocker(ctx, stakingKeeper)
ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
staking.BeginBlocker(ctx, stakingKeeper)
return ctx
}
func setValidatorRewards(ctx sdk.Context, stakingKeeper staking.Keeper, distKeeper distribution.Keeper, valAddr sdk.ValAddress, reward string) {
// allocate some rewards
vali := stakingKeeper.Validator(ctx, valAddr)
amount, err := sdk.NewDecFromStr(reward)
if err != nil {
panic(err)
}
payout := sdk.DecCoins{{Denom: "stake", Amount: amount}}
distKeeper.AllocateTokensToValidator(ctx, vali, payout)
}
func assertBalance(t *testing.T, ctx sdk.Context, keeper Keeper, contract sdk.AccAddress, addr sdk.AccAddress, expected string) {
query := StakingQueryMsg{
Balance: &addressQuery{
Address: addr,
},
}
queryBz, err := json.Marshal(query)
require.NoError(t, err)
res, err := keeper.QuerySmart(ctx, contract, queryBz)
require.NoError(t, err)
var balance BalanceResponse
err = json.Unmarshal(res, &balance)
require.NoError(t, err)
assert.Equal(t, expected, balance.Balance)
}
func assertClaims(t *testing.T, ctx sdk.Context, keeper Keeper, contract sdk.AccAddress, addr sdk.AccAddress, expected string) {
query := StakingQueryMsg{
Claims: &addressQuery{
Address: addr,
},
}
queryBz, err := json.Marshal(query)
require.NoError(t, err)
res, err := keeper.QuerySmart(ctx, contract, queryBz)
require.NoError(t, err)
var claims ClaimsResponse
err = json.Unmarshal(res, &claims)
require.NoError(t, err)
assert.Equal(t, expected, claims.Claims)
}
func assertSupply(t *testing.T, ctx sdk.Context, keeper Keeper, contract sdk.AccAddress, expectedIssued string, expectedBonded sdk.Coin) {
query := StakingQueryMsg{Investment: &struct{}{}}
queryBz, err := json.Marshal(query)
require.NoError(t, err)
res, err := keeper.QuerySmart(ctx, contract, queryBz)
require.NoError(t, err)
var invest InvestmentResponse
err = json.Unmarshal(res, &invest)
require.NoError(t, err)
assert.Equal(t, expectedIssued, invest.TokenSupply)
assert.Equal(t, expectedBonded, invest.StakedTokens)
}

View File

@@ -2,11 +2,15 @@ package keeper
import (
"fmt"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/supply"
"github.com/cosmos/cosmos-sdk/x/distribution"
"testing"
"time"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store"
@@ -15,11 +19,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/supply"
wasmTypes "github.com/CosmWasm/wasmd/x/wasm/internal/types"
)
@@ -35,6 +36,9 @@ func MakeTestCodec() *codec.Codec {
// cdc.RegisterConcrete(&auth.BaseAccount{}, "test/wasm/BaseAccount", nil)
auth.AppModuleBasic{}.RegisterCodec(cdc)
bank.AppModuleBasic{}.RegisterCodec(cdc)
supply.AppModuleBasic{}.RegisterCodec(cdc)
staking.AppModuleBasic{}.RegisterCodec(cdc)
distribution.AppModuleBasic{}.RegisterCodec(cdc)
wasmTypes.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
@@ -42,12 +46,29 @@ func MakeTestCodec() *codec.Codec {
return cdc
}
var TestingStakeParams = staking.Params{
UnbondingTime: 100,
MaxValidators: 10,
MaxEntries: 10,
HistoricalEntries: 10,
BondDenom: "stake",
}
type TestKeepers struct {
AccountKeeper auth.AccountKeeper
StakingKeeper staking.Keeper
WasmKeeper Keeper
DistKeeper distribution.Keeper
SupplyKeeper supply.Keeper
}
// encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default)
func CreateTestInput(t *testing.T, isCheckTx bool, tempDir string, supportedFeatures string, encoders *MessageEncoders, queriers *QueryPlugins) (sdk.Context, auth.AccountKeeper, Keeper) {
keyContract := sdk.NewKVStoreKey(types.StoreKey)
func CreateTestInput(t *testing.T, isCheckTx bool, tempDir string, supportedFeatures string, encoders *MessageEncoders, queriers *QueryPlugins) (sdk.Context, TestKeepers) {
keyContract := sdk.NewKVStoreKey(wasmTypes.StoreKey)
keyAcc := sdk.NewKVStoreKey(auth.StoreKey)
keyStaking := sdk.NewKVStoreKey(staking.StoreKey)
keySupply := sdk.NewKVStoreKey(supply.StoreKey)
keyDistro := sdk.NewKVStoreKey(distribution.StoreKey)
keyParams := sdk.NewKVStoreKey(params.StoreKey)
tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey)
@@ -56,6 +77,9 @@ func CreateTestInput(t *testing.T, isCheckTx bool, tempDir string, supportedFeat
ms.MountStoreWithDB(keyContract, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keyStaking, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(keyDistro, sdk.StoreTypeIAVL, db)
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeTransient, db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
@@ -82,7 +106,10 @@ func CreateTestInput(t *testing.T, isCheckTx bool, tempDir string, supportedFeat
)
bankKeeper.SetSendEnabled(ctx, true)
// this is also used to initialize module accounts (so nil is meaningful here)
maccPerms := map[string][]string{
auth.FeeCollectorName: nil,
distribution.ModuleName: nil,
//mint.ModuleName: {supply.Minter},
staking.BondedPoolName: {supply.Burner, supply.Staking},
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
@@ -91,12 +118,44 @@ func CreateTestInput(t *testing.T, isCheckTx bool, tempDir string, supportedFeat
supplyKeeper := supply.NewKeeper(cdc, keySupply, accountKeeper, bankKeeper, maccPerms)
stakingKeeper := staking.NewKeeper(cdc, keyStaking, supplyKeeper, pk.Subspace(staking.DefaultParamspace))
stakingKeeper.SetParams(ctx, TestingStakeParams)
distKeeper := distribution.NewKeeper(cdc, keyDistro, pk.Subspace(distribution.DefaultParamspace), stakingKeeper, supplyKeeper, auth.FeeCollectorName, nil)
distKeeper.SetParams(ctx, distribution.DefaultParams())
stakingKeeper.SetHooks(distKeeper.Hooks())
// set genesis items required for distribution
distKeeper.SetFeePool(ctx, distribution.InitialFeePool())
// total supply to track this
totalSupply := sdk.NewCoins(sdk.NewInt64Coin("stake", 100000000))
supplyKeeper.SetSupply(ctx, supply.NewSupply(totalSupply))
// set up initial accounts
for name, perms := range maccPerms {
mod := supply.NewEmptyModuleAccount(name, perms...)
if name == staking.NotBondedPoolName {
err = mod.SetCoins(totalSupply)
require.NoError(t, err)
} else if name == distribution.ModuleName {
// some big pot to pay out
err = mod.SetCoins(sdk.NewCoins(sdk.NewInt64Coin("stake", 500000)))
require.NoError(t, err)
}
supplyKeeper.SetModuleAccount(ctx, mod)
}
stakeAddr := supply.NewModuleAddress(staking.BondedPoolName)
moduleAcct := accountKeeper.GetAccount(ctx, stakeAddr)
require.NotNil(t, moduleAcct)
router := baseapp.NewRouter()
bh := bank.NewHandler(bankKeeper)
router.AddRoute(bank.RouterKey, bh)
sh := staking.NewHandler(stakingKeeper)
router.AddRoute(staking.RouterKey, sh)
dh := distribution.NewHandler(distKeeper)
router.AddRoute(distribution.RouterKey, dh)
// Load default wasm config
wasmConfig := wasmTypes.DefaultWasmConfig()
@@ -105,7 +164,14 @@ func CreateTestInput(t *testing.T, isCheckTx bool, tempDir string, supportedFeat
// add wasm handler so we can loop-back (contracts calling contracts)
router.AddRoute(wasmTypes.RouterKey, TestHandler(keeper))
return ctx, accountKeeper, keeper
keepers := TestKeepers{
AccountKeeper: accountKeeper,
SupplyKeeper: supplyKeeper,
StakingKeeper: stakingKeeper,
DistKeeper: distKeeper,
WasmKeeper: keeper,
}
return ctx, keepers
}
// TestHandler returns a wasm handler for tests (to avoid circular imports)

Binary file not shown.

View File

@@ -34,7 +34,8 @@ func setupTest(t *testing.T) (testData, func()) {
tempDir, err := ioutil.TempDir("", "wasm")
require.NoError(t, err)
ctx, acctKeeper, keeper := CreateTestInput(t, false, tempDir, "staking", nil, nil)
ctx, keepers := CreateTestInput(t, false, tempDir, "staking", nil, nil)
acctKeeper, keeper := keepers.AccountKeeper, keepers.WasmKeeper
data := testData{
module: NewAppModule(keeper),
ctx: ctx,
@@ -63,7 +64,7 @@ func mustLoad(path string) []byte {
var (
key1, pub1, addr1 = keyPubAddr()
testContract = mustLoad("./internal/keeper/testdata/contract.wasm")
maskContract = mustLoad("./internal/keeper/testdata/mask.wasm")
maskContract = mustLoad("./internal/keeper/testdata/reflect.wasm")
oldContract = mustLoad("./testdata/escrow_0.7.wasm")
)