ibc-transfer: sims updates (#7123)

* ibc-transfer: sims updates

* params and genesis

* sim tests

* update module.go

* remove dontcover

* Update x/ibc-transfer/simulation/decoder.go

Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com>

Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com>
This commit is contained in:
Federico Kunze 2020-08-21 10:52:46 +02:00 committed by GitHub
parent a6defabb3d
commit 0234ad324e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 233 additions and 18 deletions

View File

@ -5,6 +5,7 @@ import (
"math/big" "math/big"
"math/rand" "math/rand"
"time" "time"
"unsafe"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
@ -27,17 +28,15 @@ func RandStringOfLength(r *rand.Rand, n int) string {
if remain == 0 { if remain == 0 {
cache, remain = r.Int63(), letterIdxMax cache, remain = r.Int63(), letterIdxMax
} }
if idx := int(cache & letterIdxMask); idx < len(letterBytes) { if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx] b[i] = letterBytes[idx]
i-- i--
} }
cache >>= letterIdxBits cache >>= letterIdxBits
remain-- remain--
} }
return string(b) return *(*string)(unsafe.Pointer(&b))
} }
// RandPositiveInt get a rand positive sdk.Int // RandPositiveInt get a rand positive sdk.Int

View File

@ -9,13 +9,14 @@ import (
"github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/bank/types"
) )
type SupplyUnmarshaller interface { // SupplyUnmarshaler defines the expected encoding store functions.
type SupplyUnmarshaler interface {
UnmarshalSupply([]byte) (exported.SupplyI, error) UnmarshalSupply([]byte) (exported.SupplyI, error)
} }
// NewDecodeStore returns a function closure that unmarshals the KVPair's values // NewDecodeStore returns a function closure that unmarshals the KVPair's values
// to the corresponding types. // to the corresponding types.
func NewDecodeStore(cdc SupplyUnmarshaller) func(kvA, kvB kv.Pair) string { func NewDecodeStore(cdc SupplyUnmarshaler) func(kvA, kvB kv.Pair) string {
return func(kvA, kvB kv.Pair) string { return func(kvA, kvB kv.Pair) string {
switch { switch {
case bytes.Equal(kvA.Key[:1], types.SupplyKey): case bytes.Equal(kvA.Key[:1], types.SupplyKey):

View File

@ -0,0 +1,35 @@
package keeper
import (
"github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"
)
// UnmarshalDenomTrace attempts to decode and return an DenomTrace object from
// raw encoded bytes.
func (k Keeper) UnmarshalDenomTrace(bz []byte) (types.DenomTrace, error) {
var denomTrace types.DenomTrace
if err := k.cdc.UnmarshalBinaryBare(bz, &denomTrace); err != nil {
return types.DenomTrace{}, err
}
return denomTrace, nil
}
// MustUnmarshalDenomTrace attempts to decode and return an DenomTrace object from
// raw encoded bytes. It panics on error.
func (k Keeper) MustUnmarshalDenomTrace(bz []byte) types.DenomTrace {
var denomTrace types.DenomTrace
k.cdc.MustUnmarshalBinaryBare(bz, &denomTrace)
return denomTrace
}
// MarshalDenomTrace attempts to encode an DenomTrace object and returns the
// raw encoded bytes.
func (k Keeper) MarshalDenomTrace(denomTrace types.DenomTrace) ([]byte, error) {
return k.cdc.MarshalBinaryBare(&denomTrace)
}
// MustMarshalDenomTrace attempts to encode an DenomTrace object and returns the
// raw encoded bytes. It panics on error.
func (k Keeper) MustMarshalDenomTrace(denomTrace types.DenomTrace) []byte {
return k.cdc.MustMarshalBinaryBare(&denomTrace)
}

View File

@ -53,8 +53,8 @@ func (q Keeper) DenomTraces(c context.Context, req *types.QueryDenomTracesReques
store := prefix.NewStore(ctx.KVStore(q.storeKey), types.DenomTraceKey) store := prefix.NewStore(ctx.KVStore(q.storeKey), types.DenomTraceKey)
pageRes, err := query.Paginate(store, req.Pagination, func(_, value []byte) error { pageRes, err := query.Paginate(store, req.Pagination, func(_, value []byte) error {
var result types.DenomTrace result, err := q.UnmarshalDenomTrace(value)
if err := q.cdc.UnmarshalBinaryBare(value, &result); err != nil { if err != nil {
return err return err
} }

View File

@ -127,8 +127,7 @@ func (k Keeper) GetDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes)
return types.DenomTrace{}, false return types.DenomTrace{}, false
} }
var denomTrace types.DenomTrace denomTrace := k.MustUnmarshalDenomTrace(bz)
k.cdc.MustUnmarshalBinaryBare(bz, &denomTrace)
return denomTrace, true return denomTrace, true
} }
@ -141,7 +140,7 @@ func (k Keeper) HasDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes)
// SetDenomTrace sets a new {trace hash -> denom trace} pair to the store. // SetDenomTrace sets a new {trace hash -> denom trace} pair to the store.
func (k Keeper) SetDenomTrace(ctx sdk.Context, denomTrace types.DenomTrace) { func (k Keeper) SetDenomTrace(ctx sdk.Context, denomTrace types.DenomTrace) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey) store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey)
bz := k.cdc.MustMarshalBinaryBare(&denomTrace) bz := k.MustMarshalDenomTrace(denomTrace)
store.Set(denomTrace.Hash(), bz) store.Set(denomTrace.Hash(), bz)
} }
@ -165,9 +164,7 @@ func (k Keeper) IterateDenomTraces(ctx sdk.Context, cb func(denomTrace types.Den
defer iterator.Close() defer iterator.Close()
for ; iterator.Valid(); iterator.Next() { for ; iterator.Valid(); iterator.Next() {
var denomTrace types.DenomTrace denomTrace := k.MustUnmarshalDenomTrace(iterator.Value())
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &denomTrace)
if cb(denomTrace) { if cb(denomTrace) {
break break
} }

View File

@ -159,13 +159,14 @@ func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedP
return nil return nil
} }
// RandomizedParams returns nil. // RandomizedParams creates randomized ibc-transfer param changes for the simulator.
func (AppModule) RandomizedParams(_ *rand.Rand) []simtypes.ParamChange { func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
return nil return simulation.ParamChanges(r)
} }
// RegisterStoreDecoder registers a decoder for transfer module's types // RegisterStoreDecoder registers a decoder for transfer module's types
func (am AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) { func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[types.StoreKey] = simulation.NewDecodeStore(am.keeper)
} }
// WeightedOperations returns the all the transfer module operations with their respective weights. // WeightedOperations returns the all the transfer module operations with their respective weights.

View File

@ -0,0 +1,33 @@
package simulation
import (
"bytes"
"fmt"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"
)
// TransferUnmarshaler defines the expected encoding store functions.
type TransferUnmarshaler interface {
MustUnmarshalDenomTrace([]byte) types.DenomTrace
}
// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
// Value to the corresponding DenomTrace type.
func NewDecodeStore(cdc TransferUnmarshaler) func(kvA, kvB kv.Pair) string {
return func(kvA, kvB kv.Pair) string {
switch {
case bytes.Equal(kvA.Key[:1], types.PortKey):
return fmt.Sprintf("Port A: %s\nPort B: %s", string(kvA.Value), string(kvB.Value))
case bytes.Equal(kvA.Key[:1], types.DenomTraceKey):
denomTraceA := cdc.MustUnmarshalDenomTrace(kvA.Value)
denomTraceB := cdc.MustUnmarshalDenomTrace(kvB.Value)
return fmt.Sprintf("DenomTrace A: %s\nDenomTrace B: %s", denomTraceA.IBCDenom(), denomTraceB.IBCDenom())
default:
panic(fmt.Sprintf("invalid %s key prefix %X", types.ModuleName, kvA.Key[:1]))
}
}
}

View File

@ -0,0 +1,59 @@
package simulation_test
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/cosmos/cosmos-sdk/x/ibc-transfer/simulation"
"github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"
)
func TestDecodeStore(t *testing.T) {
app := simapp.Setup(false)
dec := simulation.NewDecodeStore(app.TransferKeeper)
trace := types.DenomTrace{
BaseDenom: "uatom",
Path: "transfer/channelToA",
}
kvPairs := kv.Pairs{
Pairs: []kv.Pair{
{
Key: types.PortKey,
Value: []byte(types.PortID),
},
{
Key: types.DenomTraceKey,
Value: app.TransferKeeper.MustMarshalDenomTrace(trace),
},
{
Key: []byte{0x99},
Value: []byte{0x99},
},
},
}
tests := []struct {
name string
expectedLog string
}{
{"PortID", fmt.Sprintf("Port A: %s\nPort B: %s", types.PortID, types.PortID)},
{"DenomTrace", fmt.Sprintf("DenomTrace A: %s\nDenomTrace B: %s", trace.IBCDenom(), trace.IBCDenom())},
{"other", ""},
}
for i, tt := range tests {
i, tt := i, tt
t.Run(tt.name, func(t *testing.T) {
if i == len(tests)-1 {
require.Panics(t, func() { dec(kvPairs.Pairs[i], kvPairs.Pairs[i]) }, tt.name)
} else {
require.Equal(t, tt.expectedLog, dec(kvPairs.Pairs[i], kvPairs.Pairs[i]), tt.name)
}
})
}
}

View File

@ -14,6 +14,11 @@ import (
// Simulation parameter constants // Simulation parameter constants
const port = "port_id" const port = "port_id"
// RadomEnabled randomized send or receive enabled param with 75% prob of being true.
func RadomEnabled(r *rand.Rand) bool {
return r.Int63n(101) <= 75
}
// RandomizedGenState generates a random GenesisState for transfer. // RandomizedGenState generates a random GenesisState for transfer.
func RandomizedGenState(simState *module.SimulationState) { func RandomizedGenState(simState *module.SimulationState) {
var portID string var portID string
@ -22,8 +27,22 @@ func RandomizedGenState(simState *module.SimulationState) {
func(r *rand.Rand) { portID = strings.ToLower(simtypes.RandStringOfLength(r, 20)) }, func(r *rand.Rand) { portID = strings.ToLower(simtypes.RandStringOfLength(r, 20)) },
) )
var sendEnabled bool
simState.AppParams.GetOrGenerate(
simState.Cdc, string(types.KeySendEnabled), &sendEnabled, simState.Rand,
func(r *rand.Rand) { sendEnabled = RadomEnabled(r) },
)
var receiveEnabled bool
simState.AppParams.GetOrGenerate(
simState.Cdc, string(types.KeyReceiveEnabled), &receiveEnabled, simState.Rand,
func(r *rand.Rand) { receiveEnabled = RadomEnabled(r) },
)
transferGenesis := types.GenesisState{ transferGenesis := types.GenesisState{
PortId: portID, PortId: portID,
DenomTraces: types.Traces{},
Params: types.NewParams(sendEnabled, receiveEnabled),
} }
fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, &transferGenesis)) fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, &transferGenesis))

View File

@ -37,6 +37,9 @@ func TestRandomizedGenState(t *testing.T) {
simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &ibcTransferGenesis) simState.Cdc.MustUnmarshalJSON(simState.GenState[types.ModuleName], &ibcTransferGenesis)
require.Equal(t, "euzxpfgkqegqiqwixnku", ibcTransferGenesis.PortId) require.Equal(t, "euzxpfgkqegqiqwixnku", ibcTransferGenesis.PortId)
require.True(t, ibcTransferGenesis.Params.SendEnabled)
require.True(t, ibcTransferGenesis.Params.ReceiveEnabled)
require.Len(t, ibcTransferGenesis.DenomTraces, 0)
} }

View File

@ -0,0 +1,32 @@
package simulation
import (
"fmt"
"math/rand"
gogotypes "github.com/gogo/protobuf/types"
"github.com/cosmos/cosmos-sdk/x/simulation"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/ibc-transfer/types"
)
// ParamChanges defines the parameters that can be modified by param change proposals
// on the simulation
func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
return []simtypes.ParamChange{
simulation.NewSimParamChange(types.ModuleName, string(types.KeySendEnabled),
func(r *rand.Rand) string {
sendEnabled := RadomEnabled(r)
return fmt.Sprintf("%s", types.ModuleCdc.MustMarshalJSON(&gogotypes.BoolValue{Value: sendEnabled}))
},
),
simulation.NewSimParamChange(types.ModuleName, string(types.KeyReceiveEnabled),
func(r *rand.Rand) string {
receiveEnabled := RadomEnabled(r)
return fmt.Sprintf("%s", types.ModuleCdc.MustMarshalJSON(&gogotypes.BoolValue{Value: receiveEnabled}))
},
),
}
}

View File

@ -0,0 +1,36 @@
package simulation_test
import (
"math/rand"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/x/ibc-transfer/simulation"
)
func TestParamChanges(t *testing.T) {
s := rand.NewSource(1)
r := rand.New(s)
expected := []struct {
composedKey string
key string
simValue string
subspace string
}{
{"transfer/SendEnabled", "SendEnabled", "false", "transfer"},
{"transfer/ReceiveEnabled", "ReceiveEnabled", "true", "transfer"},
}
paramChanges := simulation.ParamChanges(r)
require.Len(t, paramChanges, 2)
for i, p := range paramChanges {
require.Equal(t, expected[i].composedKey, p.ComposedKey())
require.Equal(t, expected[i].key, p.Key())
require.Equal(t, expected[i].simValue, p.SimValue()(r), p.Key())
require.Equal(t, expected[i].subspace, p.Subspace())
}
}