Skip to content

Commit

Permalink
Enable some IBC calls and better test framework (#8)
Browse files Browse the repository at this point in the history
* Enable IBC calls and better test framework

* Review feedback
  • Loading branch information
alpe authored Jan 20, 2021
1 parent 572400e commit 4a63c7a
Show file tree
Hide file tree
Showing 18 changed files with 416 additions and 366 deletions.
3 changes: 2 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ type WasmApp struct {
// NewWasmApp returns a reference to an initialized WasmApp.
func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
skipUpgradeHeights map[int64]bool, homePath string, invCheckPeriod uint, enabledProposals []wasm.ProposalType,
appOpts servertypes.AppOptions, baseAppOptions ...func(*baseapp.BaseApp)) *WasmApp {
appOpts servertypes.AppOptions, wasmOpts []wasm.Option, baseAppOptions ...func(*baseapp.BaseApp)) *WasmApp {

encodingConfig := MakeEncodingConfig()
appCodec, legacyAmino := encodingConfig.Marshaler, encodingConfig.Amino
Expand Down Expand Up @@ -375,6 +375,7 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
supportedFeatures,
nil,
nil,
wasmOpts...,
)

// The gov proposal types can be individually enabled
Expand Down
8 changes: 5 additions & 3 deletions app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
)

var emptyWasmOpts []wasm.Option = nil

func TestWasmdExport(t *testing.T) {
db := db.NewMemDB()
gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyAppOptions{})
gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyBaseAppOptions{}, emptyWasmOpts)

genesisState := NewDefaultGenesisState()
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
Expand All @@ -32,15 +34,15 @@ func TestWasmdExport(t *testing.T) {
gapp.Commit()

// Making a new app object with the db, so that initchain hasn't been called
newGapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyAppOptions{})
newGapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyBaseAppOptions{}, emptyWasmOpts)
_, err = newGapp.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}

// ensure that blocked addresses are properly set in bank keeper
func TestBlockedAddrs(t *testing.T) {
db := db.NewMemDB()
gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyAppOptions{})
gapp := NewWasmApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, wasm.EnableAllProposals, EmptyBaseAppOptions{}, emptyWasmOpts)

for acc := range maccPerms {
require.Equal(t, !allowedReceivingModAcc[acc], gapp.bankKeeper.BlockedAddr(gapp.accountKeeper.GetModuleAddress(acc)))
Expand Down
14 changes: 7 additions & 7 deletions app/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ var DefaultConsensusParams = &abci.ConsensusParams{
},
}

func setup(withGenesis bool, invCheckPeriod uint) (*WasmApp, GenesisState) {
func setup(withGenesis bool, invCheckPeriod uint, opts ...wasm.Option) (*WasmApp, GenesisState) {
db := dbm.NewMemDB()
app := NewWasmApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, invCheckPeriod, wasm.EnableAllProposals, EmptyAppOptions{})
app := NewWasmApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, invCheckPeriod, wasm.EnableAllProposals, EmptyBaseAppOptions{}, opts)
if withGenesis {
return app, NewDefaultGenesisState()
}
Expand Down Expand Up @@ -86,8 +86,8 @@ func Setup(isCheckTx bool) *WasmApp {
// that also act as delegators. For simplicity, each validator is bonded with a delegation
// of one consensus engine unit (10^6) in the default token of the WasmApp from first genesis
// account. A Nop logger is set in WasmApp.
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *WasmApp {
app, genesisState := setup(true, 5)
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, opts []wasm.Option, balances ...banktypes.Balance) *WasmApp {
app, genesisState := setup(true, 5, opts...)
// set genesis accounts
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
genesisState[authtypes.ModuleName] = app.appCodec.MustMarshalJSON(authGenesis)
Expand Down Expand Up @@ -435,10 +435,10 @@ func NewPubKeyFromHex(pk string) (res cryptotypes.PubKey) {
return &ed25519.PubKey{Key: pkBytes}
}

// EmptyAppOptions is a stub implementing AppOptions
type EmptyAppOptions struct{}
// EmptyBaseAppOptions is a stub implementing AppOptions
type EmptyBaseAppOptions struct{}

// Get implements AppOptions
func (ao EmptyAppOptions) Get(o string) interface{} {
func (ao EmptyBaseAppOptions) Get(o string) interface{} {
return nil
}
8 changes: 5 additions & 3 deletions cmd/wasmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,13 @@ func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer, appOpts serverty
if err != nil {
panic(err)
}

var emptyWasmOpts []wasm.Option
return app.NewWasmApp(logger, db, traceStore, true, skipUpgradeHeights,
cast.ToString(appOpts.Get(flags.FlagHome)),
cast.ToUint(appOpts.Get(server.FlagInvCheckPeriod)),
app.GetEnabledProposals(),
appOpts,
emptyWasmOpts,
baseapp.SetPruning(pruningOpts),
baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))),
baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))),
Expand All @@ -227,14 +228,15 @@ func createWasmAppAndExport(
if !ok || homePath == "" {
return servertypes.ExportedApp{}, errors.New("application home not set")
}
var emptyWasmOpts []wasm.Option
if height != -1 {
wasmApp = app.NewWasmApp(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), app.GetEnabledProposals(), appOpts)
wasmApp = app.NewWasmApp(logger, db, traceStore, false, map[int64]bool{}, homePath, uint(1), app.GetEnabledProposals(), appOpts, emptyWasmOpts)

if err := wasmApp.LoadHeight(height); err != nil {
return servertypes.ExportedApp{}, err
}
} else {
wasmApp = app.NewWasmApp(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), app.GetEnabledProposals(), appOpts)
wasmApp = app.NewWasmApp(logger, db, traceStore, true, map[int64]bool{}, homePath, uint(1), app.GetEnabledProposals(), appOpts, emptyWasmOpts)
}

return wasmApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs)
Expand Down
2 changes: 2 additions & 0 deletions x/wasm/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ var (
NewWasmProposalHandler = keeper.NewWasmProposalHandler
NewQuerier = keeper.NewQuerier
ContractFromPortID = keeper.ContractFromPortID
WithWasmEngine = keeper.WithWasmEngine

// variable aliases
ModuleCdc = types.ModuleCdc
Expand Down Expand Up @@ -136,4 +137,5 @@ type (
QueryHandler = keeper.QueryHandler
CustomQuerier = keeper.CustomQuerier
QueryPlugins = keeper.QueryPlugins
Option = keeper.Option
)
5 changes: 3 additions & 2 deletions x/wasm/ibctesting/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
wasmd "github.com/CosmWasm/wasmd/app"
"github.com/CosmWasm/wasmd/x/wasm/internal/keeper"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
"io/ioutil"
"os"
Expand Down Expand Up @@ -114,7 +115,7 @@ type TestChain struct {
//
// Time management is handled by the Coordinator in order to ensure synchrony between chains.
// Each update of any chain increments the block header time for all chains by 5 seconds.
func NewTestChain(t *testing.T, chainID string) *TestChain {
func NewTestChain(t *testing.T, chainID string, opt ...keeper.Option) *TestChain {
// generate validator private/public key
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey()
Expand All @@ -140,7 +141,7 @@ func NewTestChain(t *testing.T, chainID string) *TestChain {
}
t.Cleanup(func() { os.RemoveAll(tempDir) })

app := wasmd.SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, balance)
app := wasmd.SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, opt, balance)

// create current header and call begin block
header := tmproto.Header{
Expand Down
13 changes: 10 additions & 3 deletions x/wasm/ibctesting/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ibctesting
import (
"fmt"
"github.com/CosmWasm/wasmd/app"
"github.com/CosmWasm/wasmd/x/wasm/internal/keeper"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
"strconv"
"testing"
Expand Down Expand Up @@ -32,12 +33,18 @@ type Coordinator struct {
}

// NewCoordinator initializes Coordinator with N TestChain's
func NewCoordinator(t *testing.T, n int) *Coordinator {
func NewCoordinator(t *testing.T, n int, opts ...[]keeper.Option) *Coordinator {
chains := make(map[string]*TestChain)

if len(opts) != 0 && len(opts) != n {
t.Fatalf("opts not matching number of instances: %d", len(opts))
}
for i := 0; i < n; i++ {
chainID := GetChainID(i)
chains[chainID] = NewTestChain(t, chainID)
var iOpts []keeper.Option
if len(opts) != 0 {
iOpts = opts[i]
}
chains[chainID] = NewTestChain(t, chainID, iOpts...)
}
return &Coordinator{
t: t,
Expand Down
11 changes: 8 additions & 3 deletions x/wasm/ibctesting/wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ import (
"io/ioutil"
)

func (c *TestChain) NewRandomContractInstance() sdk.AccAddress {
wasmCode, err := ioutil.ReadFile("./internal/keeper/testdata/hackatom.wasm.gzip")
// SeedNewContractInstance stores some wasm code and instantiates a new contract on this chain.
// This method can be called to prepare the store with some valid CodeInfo and ContractInfo. The returned
// Address is the contract address for this instance. Test should make use of this data and/or use NewIBCContractMockWasmer
// for using a contract mock in Go.
func (c *TestChain) SeedNewContractInstance() sdk.AccAddress {
anyWasmCode, err := ioutil.ReadFile("./internal/keeper/testdata/hackatom.wasm.gzip")
require.NoError(c.t, err)

storeMsg := &types.MsgStoreCode{
Sender: c.SenderAccount.GetAddress().String(),
WASMByteCode: wasmCode,
WASMByteCode: anyWasmCode,
}
r, err := c.SendMsgs(storeMsg)
require.NoError(c.t, err)
Expand Down Expand Up @@ -56,6 +60,7 @@ func (c *TestChain) parseSDKResultData(r *sdk.Result) sdk.TxMsgData {
return protoResult
}

// ContractInfo is a helper function to returns the ContractInfo for the given contract address
func (c *TestChain) ContractInfo(contractAddr sdk.AccAddress) *types.ContractInfo {
return wasmd.NewTestSupport(c.t, c.App).WasmKeeper().GetContractInfo(c.GetContext(), contractAddr)
}
103 changes: 0 additions & 103 deletions x/wasm/internal/keeper/ibc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import (
"strings"

"github.com/CosmWasm/wasmd/x/wasm/internal/types"
wasmvm "github.com/CosmWasm/wasmvm"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
Expand Down Expand Up @@ -66,103 +63,3 @@ func (k Keeper) AuthenticateCapability(ctx sdk.Context, cap *capabilitytypes.Cap
func (k Keeper) ClaimCapability(ctx sdk.Context, cap *capabilitytypes.Capability, name string) error {
return k.capabilityKeeper.ClaimCapability(ctx, cap, name)
}

// IBCContractCallbacks defines the methods for go-cosmwasm to interact with the wasm contract.
// A mock contract would implement the interface to fully simulate a wasm contract's behaviour.
type IBCContractCallbacks interface {
// Package livecycle

// IBCChannelOpen is available on IBC-enabled contracts and is a hook to call into
// during the handshake pahse
IBCChannelOpen(
codeID wasmvm.CodeID,
env wasmvmtypes.Env,
channel wasmvmtypes.IBCChannel,
store wasmvm.KVStore,
goapi wasmvm.GoAPI,
querier wasmvm.Querier,
gasMeter wasmvm.GasMeter,
gasLimit uint64,
) (uint64, error)

// IBCChannelConnect is available on IBC-enabled contracts and is a hook to call into
// during the handshake pahse
IBCChannelConnect(
codeID wasmvm.CodeID,
env wasmvmtypes.Env,
channel wasmvmtypes.IBCChannel,
store wasmvm.KVStore,
goapi wasmvm.GoAPI,
querier wasmvm.Querier,
gasMeter wasmvm.GasMeter,
gasLimit uint64,
) (*wasmvmtypes.IBCBasicResponse, uint64, error)

// IBCChannelClose is available on IBC-enabled contracts and is a hook to call into
// at the end of the channel lifetime
IBCChannelClose(
codeID wasmvm.CodeID,
env wasmvmtypes.Env,
channel wasmvmtypes.IBCChannel,
store wasmvm.KVStore,
goapi wasmvm.GoAPI,
querier wasmvm.Querier,
gasMeter wasmvm.GasMeter,
gasLimit uint64,
) (*wasmvmtypes.IBCBasicResponse, uint64, error)

// IBCPacketReceive is available on IBC-enabled contracts and is called when an incoming
// packet is received on a channel belonging to this contract
IBCPacketReceive(
codeID wasmvm.CodeID,
env wasmvmtypes.Env,
packet wasmvmtypes.IBCPacket,
store wasmvm.KVStore,
goapi wasmvm.GoAPI,
querier wasmvm.Querier,
gasMeter wasmvm.GasMeter,
gasLimit uint64,
) (*wasmvmtypes.IBCReceiveResponse, uint64, error)

// IBCPacketAck is available on IBC-enabled contracts and is called when an
// the response for an outgoing packet (previously sent by this contract)
// is received
IBCPacketAck(
codeID wasmvm.CodeID,
env wasmvmtypes.Env,
ack wasmvmtypes.IBCAcknowledgement,
store wasmvm.KVStore,
goapi wasmvm.GoAPI,
querier wasmvm.Querier,
gasMeter wasmvm.GasMeter,
gasLimit uint64,
) (*wasmvmtypes.IBCBasicResponse, uint64, error)

// IBCPacketTimeout is available on IBC-enabled contracts and is called when an
// outgoing packet (previously sent by this contract) will provably never be executed.
// Usually handled like ack returning an error
IBCPacketTimeout(
codeID wasmvm.CodeID,
env wasmvmtypes.Env,
packet wasmvmtypes.IBCPacket,
store wasmvm.KVStore,
goapi wasmvm.GoAPI,
querier wasmvm.Querier,
gasMeter wasmvm.GasMeter,
gasLimit uint64,
) (*wasmvmtypes.IBCBasicResponse, uint64, error)

Execute(
code []byte,
env wasmvmtypes.Env,
info wasmvmtypes.MessageInfo,
executeMsg []byte,
store prefix.Store,
api wasmvm.GoAPI,
querier wasmvmtypes.Querier,
gasMeter wasmvm.GasMeter,
gasLimit uint64,
) (*wasmvmtypes.HandleResponse, uint64, error)
}

var MockContracts = make(map[string]IBCContractCallbacks, 0)
Loading

0 comments on commit 4a63c7a

Please sign in to comment.