Support self calling contract on instantiation (#300)
* Support self calling contract on instantiation * Review feedback * Review feedback
This commit is contained in:
@@ -422,7 +422,7 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
|
||||
distr.NewAppModule(appCodec, app.distrKeeper, app.accountKeeper, app.bankKeeper, app.stakingKeeper),
|
||||
staking.NewAppModule(appCodec, app.stakingKeeper, app.accountKeeper, app.bankKeeper),
|
||||
upgrade.NewAppModule(app.upgradeKeeper),
|
||||
wasm.NewAppModule(app.wasmKeeper),
|
||||
wasm.NewAppModule(&app.wasmKeeper),
|
||||
evidence.NewAppModule(app.evidenceKeeper),
|
||||
ibc.NewAppModule(app.ibcKeeper),
|
||||
params.NewAppModule(app.paramsKeeper),
|
||||
@@ -472,7 +472,7 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
|
||||
distr.NewAppModule(appCodec, app.distrKeeper, app.accountKeeper, app.bankKeeper, app.stakingKeeper),
|
||||
slashing.NewAppModule(appCodec, app.slashingKeeper, app.accountKeeper, app.bankKeeper, app.stakingKeeper),
|
||||
params.NewAppModule(app.paramsKeeper),
|
||||
wasm.NewAppModule(app.wasmKeeper),
|
||||
wasm.NewAppModule(&app.wasmKeeper),
|
||||
evidence.NewAppModule(app.evidenceKeeper),
|
||||
ibc.NewAppModule(app.ibcKeeper),
|
||||
transferModule,
|
||||
|
||||
@@ -118,14 +118,14 @@ func TestInitGenesis(t *testing.T) {
|
||||
})
|
||||
|
||||
// export into genstate
|
||||
genState := ExportGenesis(data.ctx, data.keeper)
|
||||
genState := ExportGenesis(data.ctx, &data.keeper)
|
||||
|
||||
// create new app to import genstate into
|
||||
newData := setupTest(t)
|
||||
q2 := newData.module.LegacyQuerierHandler(nil)
|
||||
|
||||
// initialize new app with genstate
|
||||
InitGenesis(newData.ctx, newData.keeper, *genState)
|
||||
InitGenesis(newData.ctx, &newData.keeper, *genState)
|
||||
|
||||
// run same checks again on newdata, to make sure it was reinitialized correctly
|
||||
assertCodeList(t, q2, newData.ctx, 1)
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
// NewHandler returns a handler for "bank" type messages.
|
||||
func NewHandler(k Keeper) sdk.Handler {
|
||||
func NewHandler(k *Keeper) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
||||
ctx = ctx.WithEventManager(sdk.NewEventManager())
|
||||
|
||||
@@ -47,7 +47,7 @@ func filteredMessageEvents(manager *sdk.EventManager) []abci.Event {
|
||||
return res
|
||||
}
|
||||
|
||||
func handleStoreCode(ctx sdk.Context, k Keeper, msg *MsgStoreCode) (*sdk.Result, error) {
|
||||
func handleStoreCode(ctx sdk.Context, k *Keeper, msg *MsgStoreCode) (*sdk.Result, error) {
|
||||
err := msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -73,7 +73,7 @@ func handleStoreCode(ctx sdk.Context, k Keeper, msg *MsgStoreCode) (*sdk.Result,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func handleInstantiate(ctx sdk.Context, k Keeper, msg *MsgInstantiateContract) (*sdk.Result, error) {
|
||||
func handleInstantiate(ctx sdk.Context, k *Keeper, msg *MsgInstantiateContract) (*sdk.Result, error) {
|
||||
contractAddr, err := k.Instantiate(ctx, msg.CodeID, msg.Sender, msg.Admin, msg.InitMsg, msg.Label, msg.InitFunds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -95,7 +95,7 @@ func handleInstantiate(ctx sdk.Context, k Keeper, msg *MsgInstantiateContract) (
|
||||
}, nil
|
||||
}
|
||||
|
||||
func handleExecute(ctx sdk.Context, k Keeper, msg *MsgExecuteContract) (*sdk.Result, error) {
|
||||
func handleExecute(ctx sdk.Context, k *Keeper, msg *MsgExecuteContract) (*sdk.Result, error) {
|
||||
res, err := k.Execute(ctx, msg.Contract, msg.Sender, msg.Msg, msg.SentFunds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -115,7 +115,7 @@ func handleExecute(ctx sdk.Context, k Keeper, msg *MsgExecuteContract) (*sdk.Res
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func handleMigration(ctx sdk.Context, k Keeper, msg *MsgMigrateContract) (*sdk.Result, error) {
|
||||
func handleMigration(ctx sdk.Context, k *Keeper, msg *MsgMigrateContract) (*sdk.Result, error) {
|
||||
res, err := k.Migrate(ctx, msg.Contract, msg.Sender, msg.CodeID, msg.MigrateMsg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -133,7 +133,7 @@ func handleMigration(ctx sdk.Context, k Keeper, msg *MsgMigrateContract) (*sdk.R
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func handleUpdateContractAdmin(ctx sdk.Context, k Keeper, msg *MsgUpdateAdmin) (*sdk.Result, error) {
|
||||
func handleUpdateContractAdmin(ctx sdk.Context, k *Keeper, msg *MsgUpdateAdmin) (*sdk.Result, error) {
|
||||
if err := k.UpdateContractAdmin(ctx, msg.Contract, msg.Sender, msg.NewAdmin); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -149,7 +149,7 @@ func handleUpdateContractAdmin(ctx sdk.Context, k Keeper, msg *MsgUpdateAdmin) (
|
||||
}, nil
|
||||
}
|
||||
|
||||
func handleClearContractAdmin(ctx sdk.Context, k Keeper, msg *MsgClearAdmin) (*sdk.Result, error) {
|
||||
func handleClearContractAdmin(ctx sdk.Context, k *Keeper, msg *MsgClearAdmin) (*sdk.Result, error) {
|
||||
if err := k.ClearContractAdmin(ctx, msg.Contract, msg.Sender); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
// InitGenesis sets supply information for genesis.
|
||||
//
|
||||
// CONTRACT: all types of accounts must have been already initialized/created
|
||||
func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error {
|
||||
func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState) error {
|
||||
var maxCodeID uint64
|
||||
for i, code := range data.Codes {
|
||||
err := keeper.importCode(ctx, code.CodeID, code.CodeInfo, code.CodeBytes)
|
||||
@@ -52,7 +52,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) error
|
||||
}
|
||||
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper.
|
||||
func ExportGenesis(ctx sdk.Context, keeper Keeper) *types.GenesisState {
|
||||
func ExportGenesis(ctx sdk.Context, keeper *Keeper) *types.GenesisState {
|
||||
var genState types.GenesisState
|
||||
|
||||
genState.Params = keeper.GetParams(ctx)
|
||||
|
||||
@@ -473,7 +473,7 @@ func TestImportContractWithCodeHistoryReset(t *testing.T) {
|
||||
assert.Equal(t, expHistory, keeper.GetContractHistory(ctx, contractAddr).CodeHistoryEntries)
|
||||
}
|
||||
|
||||
func setupKeeper(t *testing.T) (Keeper, sdk.Context, []sdk.StoreKey, func()) {
|
||||
func setupKeeper(t *testing.T) (*Keeper, sdk.Context, []sdk.StoreKey, func()) {
|
||||
t.Helper()
|
||||
tempDir, err := ioutil.TempDir("", "wasm")
|
||||
require.NoError(t, err)
|
||||
@@ -504,5 +504,5 @@ func setupKeeper(t *testing.T) (Keeper, sdk.Context, []sdk.StoreKey, func()) {
|
||||
srcKeeper := NewKeeper(encodingConfig.Marshaler, keyWasm, pk.Subspace(wasmTypes.DefaultParamspace), authkeeper.AccountKeeper{}, nil, stakingkeeper.Keeper{}, distributionkeeper.Keeper{}, nil, tempDir, wasmConfig, "", nil, nil)
|
||||
srcKeeper.setParams(ctx, wasmTypes.DefaultParams())
|
||||
|
||||
return srcKeeper, ctx, []sdk.StoreKey{keyWasm, keyParams}, cleanup
|
||||
return &srcKeeper, ctx, []sdk.StoreKey{keyWasm, keyParams}, cleanup
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ type Keeper struct {
|
||||
accountKeeper authkeeper.AccountKeeper
|
||||
bankKeeper bankkeeper.Keeper
|
||||
|
||||
wasmer wasm.Wasmer
|
||||
wasmer types.WasmerEngine
|
||||
queryPlugins QueryPlugins
|
||||
messenger MessageHandler
|
||||
// queryGasLimit is the max wasm gas that can be spent on executing a query with a contract
|
||||
@@ -86,7 +86,7 @@ func NewKeeper(
|
||||
keeper := Keeper{
|
||||
storeKey: storeKey,
|
||||
cdc: cdc,
|
||||
wasmer: *wasmer,
|
||||
wasmer: wasmer,
|
||||
accountKeeper: accountKeeper,
|
||||
bankKeeper: bankKeeper,
|
||||
messenger: NewMessageHandler(router, customEncoders),
|
||||
@@ -254,16 +254,18 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A
|
||||
events := types.ParseEvents(res.Attributes, contractAddress)
|
||||
ctx.EventManager().EmitEvents(events)
|
||||
|
||||
// persist instance first
|
||||
createdAt := types.NewAbsoluteTxPosition(ctx)
|
||||
instance := types.NewContractInfo(codeID, creator, admin, label, createdAt)
|
||||
store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshalBinaryBare(&instance))
|
||||
k.appendToContractHistory(ctx, contractAddress, instance.InitialHistory(initMsg))
|
||||
|
||||
// then dispatch so that contract could be called back
|
||||
err = k.dispatchMessages(ctx, contractAddress, res.Messages)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// persist instance
|
||||
createdAt := types.NewAbsoluteTxPosition(ctx)
|
||||
instance := types.NewContractInfo(codeID, creator, admin, label, createdAt)
|
||||
store.Set(types.GetContractAddressKey(contractAddress), k.cdc.MustMarshalBinaryBare(&instance))
|
||||
k.appendToContractHistory(ctx, contractAddress, instance.InitialHistory(initMsg))
|
||||
return contractAddress, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -432,6 +432,21 @@ func TestInstantiateWithNonExistingCodeID(t *testing.T) {
|
||||
require.Nil(t, addr)
|
||||
}
|
||||
|
||||
func TestInstantiateWithCallbackToContract(t *testing.T) {
|
||||
ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil)
|
||||
var (
|
||||
executeCalled bool
|
||||
err error
|
||||
)
|
||||
wasmerMock := selfCallingInstMockWasmer(&executeCalled)
|
||||
|
||||
keepers.WasmKeeper.wasmer = wasmerMock
|
||||
example := StoreHackatomExampleContract(t, ctx, keepers)
|
||||
_, err = keepers.WasmKeeper.Instantiate(ctx, example.CodeID, example.CreatorAddr, nil, nil, "test", nil)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, executeCalled)
|
||||
}
|
||||
|
||||
func TestExecute(t *testing.T) {
|
||||
ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil)
|
||||
accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper
|
||||
|
||||
@@ -27,7 +27,7 @@ const (
|
||||
)
|
||||
|
||||
// NewLegacyQuerier creates a new querier
|
||||
func NewLegacyQuerier(keeper Keeper) sdk.Querier {
|
||||
func NewLegacyQuerier(keeper *Keeper) sdk.Querier {
|
||||
return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) {
|
||||
var (
|
||||
rsp interface{}
|
||||
@@ -39,13 +39,13 @@ func NewLegacyQuerier(keeper Keeper) sdk.Querier {
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, err.Error())
|
||||
}
|
||||
rsp, err = queryContractInfo(ctx, addr, keeper)
|
||||
rsp, err = queryContractInfo(ctx, addr, *keeper)
|
||||
case QueryListContractByCode:
|
||||
codeID, err := strconv.ParseUint(path[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrapf(types.ErrInvalid, "code id: %s", err.Error())
|
||||
}
|
||||
rsp, err = queryContractListByCode(ctx, codeID, keeper)
|
||||
rsp, err = queryContractListByCode(ctx, codeID, *keeper)
|
||||
case QueryGetContractState:
|
||||
if len(path) < 3 {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown data query endpoint")
|
||||
@@ -58,13 +58,13 @@ func NewLegacyQuerier(keeper Keeper) sdk.Querier {
|
||||
}
|
||||
rsp, err = queryCode(ctx, codeID, keeper)
|
||||
case QueryListCode:
|
||||
rsp, err = queryCodeList(ctx, keeper)
|
||||
rsp, err = queryCodeList(ctx, *keeper)
|
||||
case QueryContractHistory:
|
||||
contractAddr, err := sdk.AccAddressFromBech32(path[1])
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, err.Error())
|
||||
}
|
||||
rsp, err = queryContractHistory(ctx, contractAddr, keeper)
|
||||
rsp, err = queryContractHistory(ctx, contractAddr, *keeper)
|
||||
default:
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown data query endpoint")
|
||||
}
|
||||
@@ -82,7 +82,7 @@ func NewLegacyQuerier(keeper Keeper) sdk.Querier {
|
||||
}
|
||||
}
|
||||
|
||||
func queryContractState(ctx sdk.Context, bech, queryMethod string, data []byte, keeper Keeper) (json.RawMessage, error) {
|
||||
func queryContractState(ctx sdk.Context, bech, queryMethod string, data []byte, keeper *Keeper) (json.RawMessage, error) {
|
||||
contractAddr, err := sdk.AccAddressFromBech32(bech)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, bech)
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
)
|
||||
|
||||
type grpcQuerier struct {
|
||||
keeper Keeper
|
||||
keeper *Keeper
|
||||
}
|
||||
|
||||
// todo: this needs proper tests and doc
|
||||
func NewQuerier(keeper Keeper) grpcQuerier {
|
||||
func NewQuerier(keeper *Keeper) grpcQuerier {
|
||||
return grpcQuerier{keeper: keeper}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ func (q grpcQuerier) ContractInfo(c context.Context, req *types.QueryContractInf
|
||||
if err := sdk.VerifyAddressFormat(req.Address); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsp, err := queryContractInfo(sdk.UnwrapSDKContext(c), req.Address, q.keeper)
|
||||
rsp, err := queryContractInfo(sdk.UnwrapSDKContext(c), req.Address, *q.keeper)
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
@@ -40,7 +40,7 @@ func (q grpcQuerier) ContractHistory(c context.Context, req *types.QueryContract
|
||||
if err := sdk.VerifyAddressFormat(req.Address); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rsp, err := queryContractHistory(sdk.UnwrapSDKContext(c), req.Address, q.keeper)
|
||||
rsp, err := queryContractHistory(sdk.UnwrapSDKContext(c), req.Address, *q.keeper)
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
@@ -56,7 +56,7 @@ func (q grpcQuerier) ContractsByCode(c context.Context, req *types.QueryContract
|
||||
if req.CodeId == 0 {
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalid, "code id")
|
||||
}
|
||||
rsp, err := queryContractListByCode(sdk.UnwrapSDKContext(c), req.CodeId, q.keeper)
|
||||
rsp, err := queryContractListByCode(sdk.UnwrapSDKContext(c), req.CodeId, *q.keeper)
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
@@ -134,7 +134,7 @@ func (q grpcQuerier) Code(c context.Context, req *types.QueryCodeRequest) (*type
|
||||
}
|
||||
|
||||
func (q grpcQuerier) Codes(c context.Context, _ *empty.Empty) (*types.QueryCodesResponse, error) {
|
||||
rsp, err := queryCodeList(sdk.UnwrapSDKContext(c), q.keeper)
|
||||
rsp, err := queryCodeList(sdk.UnwrapSDKContext(c), *q.keeper)
|
||||
switch {
|
||||
case err != nil:
|
||||
return nil, err
|
||||
@@ -182,7 +182,7 @@ func queryContractListByCode(ctx sdk.Context, codeID uint64, keeper Keeper) ([]t
|
||||
return contracts, nil
|
||||
}
|
||||
|
||||
func queryCode(ctx sdk.Context, codeID uint64, keeper Keeper) (*types.QueryCodeResponse, error) {
|
||||
func queryCode(ctx sdk.Context, codeID uint64, keeper *Keeper) (*types.QueryCodeResponse, error) {
|
||||
if codeID == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ type recurseResponse struct {
|
||||
// number os wasm queries called from a contract
|
||||
var totalWasmQueryCounter int
|
||||
|
||||
func initRecurseContract(t *testing.T) (contract sdk.AccAddress, creator sdk.AccAddress, ctx sdk.Context, keeper Keeper) {
|
||||
func initRecurseContract(t *testing.T) (contract sdk.AccAddress, creator sdk.AccAddress, ctx sdk.Context, keeper *Keeper) {
|
||||
// we do one basic setup before all test cases (which are read-only and don't change state)
|
||||
var realWasmQuerier func(ctx sdk.Context, request *wasmTypes.WasmQuery) ([]byte, error)
|
||||
countingQuerier := &QueryPlugins{
|
||||
@@ -48,7 +48,7 @@ func initRecurseContract(t *testing.T) (contract sdk.AccAddress, creator sdk.Acc
|
||||
|
||||
ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, countingQuerier)
|
||||
keeper = keepers.WasmKeeper
|
||||
realWasmQuerier = WasmQuerier(&keeper)
|
||||
realWasmQuerier = WasmQuerier(keeper)
|
||||
|
||||
exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers)
|
||||
return exampleContract.Contract, exampleContract.CreatorAddr, ctx, keeper
|
||||
|
||||
@@ -213,7 +213,7 @@ func initializeStaking(t *testing.T) initInfo {
|
||||
ctx: ctx,
|
||||
accKeeper: accKeeper,
|
||||
stakingKeeper: stakingKeeper,
|
||||
wasmKeeper: keeper,
|
||||
wasmKeeper: *keeper,
|
||||
distKeeper: k.DistKeeper,
|
||||
bankKeeper: bankKeeper,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -9,11 +10,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
wasmTypes "github.com/CosmWasm/wasmd/x/wasm/internal/types"
|
||||
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/internal/types"
|
||||
"github.com/CosmWasm/go-cosmwasm"
|
||||
wasmTypes "github.com/CosmWasm/go-cosmwasm/types"
|
||||
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
params2 "github.com/cosmos/cosmos-sdk/simapp/params"
|
||||
"github.com/cosmos/cosmos-sdk/std"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
@@ -87,7 +89,7 @@ func MakeTestCodec() codec.Marshaler {
|
||||
}
|
||||
func MakeEncodingConfig() params2.EncodingConfig {
|
||||
amino := codec.NewLegacyAmino()
|
||||
interfaceRegistry := types.NewInterfaceRegistry()
|
||||
interfaceRegistry := codectypes.NewInterfaceRegistry()
|
||||
marshaler := codec.NewProtoCodec(interfaceRegistry)
|
||||
txCfg := tx.NewTxConfig(marshaler, tx.DefaultSignModes)
|
||||
|
||||
@@ -115,10 +117,10 @@ var TestingStakeParams = stakingtypes.Params{
|
||||
type TestKeepers struct {
|
||||
AccountKeeper authkeeper.AccountKeeper
|
||||
StakingKeeper stakingkeeper.Keeper
|
||||
WasmKeeper Keeper
|
||||
DistKeeper distributionkeeper.Keeper
|
||||
BankKeeper bankkeeper.Keeper
|
||||
GovKeeper govkeeper.Keeper
|
||||
WasmKeeper *Keeper
|
||||
}
|
||||
|
||||
// encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default)
|
||||
@@ -127,7 +129,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { os.RemoveAll(tempDir) })
|
||||
|
||||
keyWasm := sdk.NewKVStoreKey(wasmTypes.StoreKey)
|
||||
keyWasm := sdk.NewKVStoreKey(types.StoreKey)
|
||||
keyAcc := sdk.NewKVStoreKey(authtypes.StoreKey)
|
||||
keyBank := sdk.NewKVStoreKey(banktypes.StoreKey)
|
||||
keyStaking := sdk.NewKVStoreKey(stakingtypes.StoreKey)
|
||||
@@ -229,12 +231,12 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc
|
||||
router.AddRoute(sdk.NewRoute(distributiontypes.RouterKey, dh))
|
||||
|
||||
// Load default wasm config
|
||||
wasmConfig := wasmTypes.DefaultWasmConfig()
|
||||
wasmConfig := types.DefaultWasmConfig()
|
||||
|
||||
keeper := NewKeeper(
|
||||
appCodec,
|
||||
keyWasm,
|
||||
paramsKeeper.Subspace(wasmtypes.DefaultParamspace),
|
||||
paramsKeeper.Subspace(types.DefaultParamspace),
|
||||
authKeeper,
|
||||
bankKeeper,
|
||||
stakingKeeper,
|
||||
@@ -246,15 +248,15 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc
|
||||
encoders,
|
||||
queriers,
|
||||
)
|
||||
keeper.setParams(ctx, wasmtypes.DefaultParams())
|
||||
keeper.setParams(ctx, types.DefaultParams())
|
||||
// add wasm handler so we can loop-back (contracts calling contracts)
|
||||
router.AddRoute(sdk.NewRoute(wasmTypes.RouterKey, TestHandler(keeper)))
|
||||
router.AddRoute(sdk.NewRoute(types.RouterKey, TestHandler(&keeper)))
|
||||
|
||||
govRouter := govtypes.NewRouter().
|
||||
AddRoute(govtypes.RouterKey, govtypes.ProposalHandler).
|
||||
AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(paramsKeeper)).
|
||||
AddRoute(distributiontypes.RouterKey, distribution.NewCommunityPoolSpendProposalHandler(distKeeper)).
|
||||
AddRoute(wasmtypes.RouterKey, NewWasmProposalHandler(keeper, wasmtypes.EnableAllProposals))
|
||||
AddRoute(types.RouterKey, NewWasmProposalHandler(keeper, types.EnableAllProposals))
|
||||
|
||||
govKeeper := govkeeper.NewKeeper(
|
||||
appCodec, keyGov, paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()), authKeeper, bankKeeper, stakingKeeper, govRouter,
|
||||
@@ -269,7 +271,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc
|
||||
AccountKeeper: authKeeper,
|
||||
StakingKeeper: stakingKeeper,
|
||||
DistKeeper: distKeeper,
|
||||
WasmKeeper: keeper,
|
||||
WasmKeeper: &keeper,
|
||||
BankKeeper: bankKeeper,
|
||||
GovKeeper: govKeeper,
|
||||
}
|
||||
@@ -277,15 +279,15 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc
|
||||
}
|
||||
|
||||
// TestHandler returns a wasm handler for tests (to avoid circular imports)
|
||||
func TestHandler(k Keeper) sdk.Handler {
|
||||
func TestHandler(k *Keeper) sdk.Handler {
|
||||
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
|
||||
ctx = ctx.WithEventManager(sdk.NewEventManager())
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case *wasmtypes.MsgInstantiateContract:
|
||||
case *types.MsgInstantiateContract:
|
||||
return handleInstantiate(ctx, k, msg)
|
||||
|
||||
case *wasmtypes.MsgExecuteContract:
|
||||
case *types.MsgExecuteContract:
|
||||
return handleExecute(ctx, k, msg)
|
||||
|
||||
default:
|
||||
@@ -295,7 +297,7 @@ func TestHandler(k Keeper) sdk.Handler {
|
||||
}
|
||||
}
|
||||
|
||||
func handleInstantiate(ctx sdk.Context, k Keeper, msg *wasmtypes.MsgInstantiateContract) (*sdk.Result, error) {
|
||||
func handleInstantiate(ctx sdk.Context, k *Keeper, msg *types.MsgInstantiateContract) (*sdk.Result, error) {
|
||||
contractAddr, err := k.Instantiate(ctx, msg.CodeID, msg.Sender, msg.Admin, msg.InitMsg, msg.Label, msg.InitFunds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -307,7 +309,7 @@ func handleInstantiate(ctx sdk.Context, k Keeper, msg *wasmtypes.MsgInstantiateC
|
||||
}, nil
|
||||
}
|
||||
|
||||
func handleExecute(ctx sdk.Context, k Keeper, msg *wasmtypes.MsgExecuteContract) (*sdk.Result, error) {
|
||||
func handleExecute(ctx sdk.Context, k *Keeper, msg *types.MsgExecuteContract) (*sdk.Result, error) {
|
||||
res, err := k.Execute(ctx, msg.Contract, msg.Sender, msg.Msg, msg.SentFunds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -323,46 +325,13 @@ func AnyAccAddress(_ *testing.T) sdk.AccAddress {
|
||||
}
|
||||
|
||||
type HackatomExampleContract struct {
|
||||
InitialAmount sdk.Coins
|
||||
Contract sdk.AccAddress
|
||||
Creator crypto.PrivKey
|
||||
CreatorAddr sdk.AccAddress
|
||||
Verifier crypto.PrivKey
|
||||
VerifierAddr sdk.AccAddress
|
||||
Beneficiary crypto.PrivKey
|
||||
BeneficiaryAddr sdk.AccAddress
|
||||
CodeID uint64
|
||||
InitialAmount sdk.Coins
|
||||
Creator crypto.PrivKey
|
||||
CreatorAddr sdk.AccAddress
|
||||
CodeID uint64
|
||||
}
|
||||
|
||||
// InstantiateHackatomExampleContract load and instantiate the "./testdata/hackatom.wasm" contract
|
||||
func InstantiateHackatomExampleContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) HackatomExampleContract {
|
||||
anyAmount, creator, creatorAddr, codeID := StoreHackatomExampleContract(t, ctx, keepers)
|
||||
|
||||
verifier, _, verifierAddr := keyPubAddr()
|
||||
fundAccounts(t, ctx, keepers.AccountKeeper, keepers.BankKeeper, verifierAddr, anyAmount)
|
||||
|
||||
beneficiary, _, beneficiaryAddr := keyPubAddr()
|
||||
initMsgBz := HackatomExampleInitMsg{
|
||||
Verifier: verifierAddr,
|
||||
Beneficiary: beneficiaryAddr,
|
||||
}.GetBytes(t)
|
||||
initialAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 100))
|
||||
contractAddr, err := keepers.WasmKeeper.Instantiate(ctx, codeID, creatorAddr, nil, initMsgBz, "demo contract to query", initialAmount)
|
||||
require.NoError(t, err)
|
||||
return HackatomExampleContract{
|
||||
InitialAmount: initialAmount,
|
||||
Contract: contractAddr,
|
||||
Creator: creator,
|
||||
CreatorAddr: creatorAddr,
|
||||
Verifier: verifier,
|
||||
VerifierAddr: verifierAddr,
|
||||
Beneficiary: beneficiary,
|
||||
BeneficiaryAddr: beneficiaryAddr,
|
||||
CodeID: codeID,
|
||||
}
|
||||
}
|
||||
|
||||
func StoreHackatomExampleContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) (sdk.Coins, crypto.PrivKey, sdk.AccAddress, uint64) {
|
||||
func StoreHackatomExampleContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) HackatomExampleContract {
|
||||
anyAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000))
|
||||
creator, _, creatorAddr := keyPubAddr()
|
||||
fundAccounts(t, ctx, keepers.AccountKeeper, keepers.BankKeeper, creatorAddr, anyAmount)
|
||||
@@ -372,7 +341,41 @@ func StoreHackatomExampleContract(t *testing.T, ctx sdk.Context, keepers TestKee
|
||||
|
||||
codeID, err := keepers.WasmKeeper.Create(ctx, creatorAddr, wasmCode, "", "", nil)
|
||||
require.NoError(t, err)
|
||||
return anyAmount, creator, creatorAddr, codeID
|
||||
return HackatomExampleContract{anyAmount, creator, creatorAddr, codeID}
|
||||
}
|
||||
|
||||
type HackatomExampleInstance struct {
|
||||
HackatomExampleContract
|
||||
Contract sdk.AccAddress
|
||||
Verifier crypto.PrivKey
|
||||
VerifierAddr sdk.AccAddress
|
||||
Beneficiary crypto.PrivKey
|
||||
BeneficiaryAddr sdk.AccAddress
|
||||
}
|
||||
|
||||
// InstantiateHackatomExampleContract load and instantiate the "./testdata/hackatom.wasm" contract
|
||||
func InstantiateHackatomExampleContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) HackatomExampleInstance {
|
||||
contract := StoreHackatomExampleContract(t, ctx, keepers)
|
||||
|
||||
verifier, _, verifierAddr := keyPubAddr()
|
||||
fundAccounts(t, ctx, keepers.AccountKeeper, keepers.BankKeeper, verifierAddr, contract.InitialAmount)
|
||||
|
||||
beneficiary, _, beneficiaryAddr := keyPubAddr()
|
||||
initMsgBz := HackatomExampleInitMsg{
|
||||
Verifier: verifierAddr,
|
||||
Beneficiary: beneficiaryAddr,
|
||||
}.GetBytes(t)
|
||||
initialAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 100))
|
||||
contractAddr, err := keepers.WasmKeeper.Instantiate(ctx, contract.CodeID, contract.CreatorAddr, nil, initMsgBz, "demo contract to query", initialAmount)
|
||||
require.NoError(t, err)
|
||||
return HackatomExampleInstance{
|
||||
HackatomExampleContract: contract,
|
||||
Contract: contractAddr,
|
||||
Verifier: verifier,
|
||||
VerifierAddr: verifierAddr,
|
||||
Beneficiary: beneficiary,
|
||||
BeneficiaryAddr: beneficiaryAddr,
|
||||
}
|
||||
}
|
||||
|
||||
type HackatomExampleInitMsg struct {
|
||||
@@ -412,3 +415,91 @@ func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) {
|
||||
addr := sdk.AccAddress(pub.Address())
|
||||
return key, pub, addr
|
||||
}
|
||||
|
||||
var _ types.WasmerEngine = &MockWasmer{}
|
||||
|
||||
// MockWasmer implements types.WasmerEngine for testing purpose. One or multiple messages can be stubbed.
|
||||
// Without a stub function a panic is thrown.
|
||||
type MockWasmer struct {
|
||||
CreateFn func(code cosmwasm.WasmCode) (cosmwasm.CodeID, error)
|
||||
InstantiateFn func(code cosmwasm.CodeID, env wasmTypes.Env, info wasmTypes.MessageInfo, initMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) (*wasmTypes.InitResponse, uint64, error)
|
||||
ExecuteFn func(code cosmwasm.CodeID, env wasmTypes.Env, info wasmTypes.MessageInfo, executeMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) (*wasmTypes.HandleResponse, uint64, error)
|
||||
QueryFn func(code cosmwasm.CodeID, env wasmTypes.Env, queryMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) ([]byte, uint64, error)
|
||||
MigrateFn func(code cosmwasm.CodeID, env wasmTypes.Env, info wasmTypes.MessageInfo, migrateMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) (*wasmTypes.MigrateResponse, uint64, error)
|
||||
GetCodeFn func(code cosmwasm.CodeID) (cosmwasm.WasmCode, error)
|
||||
CleanupFn func()
|
||||
}
|
||||
|
||||
func (m *MockWasmer) Create(code cosmwasm.WasmCode) (cosmwasm.CodeID, error) {
|
||||
if m.CreateFn == nil {
|
||||
panic("not supposed to be called!")
|
||||
}
|
||||
return m.CreateFn(code)
|
||||
}
|
||||
|
||||
func (m *MockWasmer) Instantiate(code cosmwasm.CodeID, env wasmTypes.Env, info wasmTypes.MessageInfo, initMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) (*wasmTypes.InitResponse, uint64, error) {
|
||||
if m.InstantiateFn == nil {
|
||||
panic("not supposed to be called!")
|
||||
}
|
||||
|
||||
return m.InstantiateFn(code, env, info, initMsg, store, goapi, querier, gasMeter, gasLimit)
|
||||
}
|
||||
|
||||
func (m *MockWasmer) Execute(code cosmwasm.CodeID, env wasmTypes.Env, info wasmTypes.MessageInfo, executeMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) (*wasmTypes.HandleResponse, uint64, error) {
|
||||
if m.ExecuteFn == nil {
|
||||
panic("not supposed to be called!")
|
||||
}
|
||||
return m.ExecuteFn(code, env, info, executeMsg, store, goapi, querier, gasMeter, gasLimit)
|
||||
}
|
||||
|
||||
func (m *MockWasmer) Query(code cosmwasm.CodeID, env wasmTypes.Env, queryMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) ([]byte, uint64, error) {
|
||||
if m.QueryFn == nil {
|
||||
panic("not supposed to be called!")
|
||||
}
|
||||
return m.QueryFn(code, env, queryMsg, store, goapi, querier, gasMeter, gasLimit)
|
||||
}
|
||||
|
||||
func (m *MockWasmer) Migrate(code cosmwasm.CodeID, env wasmTypes.Env, info wasmTypes.MessageInfo, migrateMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) (*wasmTypes.MigrateResponse, uint64, error) {
|
||||
if m.MigrateFn == nil {
|
||||
panic("not supposed to be called!")
|
||||
}
|
||||
return m.MigrateFn(code, env, info, migrateMsg, store, goapi, querier, gasMeter, gasLimit)
|
||||
}
|
||||
|
||||
func (m *MockWasmer) GetCode(code cosmwasm.CodeID) (cosmwasm.WasmCode, error) {
|
||||
if m.GetCodeFn == nil {
|
||||
panic("not supposed to be called!")
|
||||
}
|
||||
return m.GetCodeFn(code)
|
||||
}
|
||||
|
||||
func (m *MockWasmer) Cleanup() {
|
||||
if m.CleanupFn == nil {
|
||||
panic("not supposed to be called!")
|
||||
}
|
||||
m.CleanupFn()
|
||||
}
|
||||
|
||||
var alwaysPanicMockWasmer = &MockWasmer{}
|
||||
|
||||
// selfCallingInstMockWasmer prepares a Wasmer mock that calls itself on instantiation.
|
||||
func selfCallingInstMockWasmer(executeCalled *bool) *MockWasmer {
|
||||
return &MockWasmer{
|
||||
|
||||
CreateFn: func(code cosmwasm.WasmCode) (cosmwasm.CodeID, error) {
|
||||
anyCodeID := bytes.Repeat([]byte{0x1}, 32)
|
||||
return anyCodeID, nil
|
||||
},
|
||||
InstantiateFn: func(code cosmwasm.CodeID, env wasmTypes.Env, info wasmTypes.MessageInfo, initMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) (*wasmTypes.InitResponse, uint64, error) {
|
||||
return &wasmTypes.InitResponse{
|
||||
Messages: []wasmTypes.CosmosMsg{
|
||||
{Wasm: &wasmTypes.WasmMsg{Execute: &wasmTypes.ExecuteMsg{ContractAddr: env.Contract.Address, Msg: []byte(`{}`)}}},
|
||||
},
|
||||
}, 1, nil
|
||||
},
|
||||
ExecuteFn: func(code cosmwasm.CodeID, env wasmTypes.Env, info wasmTypes.MessageInfo, executeMsg []byte, store cosmwasm.KVStore, goapi cosmwasm.GoAPI, querier cosmwasm.Querier, gasMeter cosmwasm.GasMeter, gasLimit uint64) (*wasmTypes.HandleResponse, uint64, error) {
|
||||
*executeCalled = true
|
||||
return &wasmTypes.HandleResponse{}, 1, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
102
x/wasm/internal/types/wasmer_engine.go
Normal file
102
x/wasm/internal/types/wasmer_engine.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/CosmWasm/go-cosmwasm"
|
||||
"github.com/CosmWasm/go-cosmwasm/types"
|
||||
)
|
||||
|
||||
// WasmerEngine defines the WASM contract runtime engine.
|
||||
type WasmerEngine interface {
|
||||
|
||||
// Create will compile the wasm code, and store the resulting pre-compile
|
||||
// as well as the original code. Both can be referenced later via CodeID
|
||||
// This must be done one time for given code, after which it can be
|
||||
// instatitated many times, and each instance called many times.
|
||||
//
|
||||
// For example, the code for all ERC-20 contracts should be the same.
|
||||
// This function stores the code for that contract only once, but it can
|
||||
// be instantiated with custom inputs in the future.
|
||||
Create(code cosmwasm.WasmCode) (cosmwasm.CodeID, error)
|
||||
|
||||
// Instantiate will create a new contract based on the given codeID.
|
||||
// We can set the initMsg (contract "genesis") here, and it then receives
|
||||
// an account and address and can be invoked (Execute) many times.
|
||||
//
|
||||
// Storage should be set with a PrefixedKVStore that this code can safely access.
|
||||
//
|
||||
// Under the hood, we may recompile the wasm, use a cached native compile, or even use a cached instance
|
||||
// for performance.
|
||||
Instantiate(
|
||||
code cosmwasm.CodeID,
|
||||
env types.Env,
|
||||
info types.MessageInfo,
|
||||
initMsg []byte,
|
||||
store cosmwasm.KVStore,
|
||||
goapi cosmwasm.GoAPI,
|
||||
querier cosmwasm.Querier,
|
||||
gasMeter cosmwasm.GasMeter,
|
||||
gasLimit uint64,
|
||||
) (*types.InitResponse, uint64, error)
|
||||
|
||||
// Execute calls a given contract. Since the only difference between contracts with the same CodeID is the
|
||||
// data in their local storage, and their address in the outside world, we need no ContractID here.
|
||||
// (That is a detail for the external, sdk-facing, side).
|
||||
//
|
||||
// The caller is responsible for passing the correct `store` (which must have been initialized exactly once),
|
||||
// and setting the env with relevent info on this instance (address, balance, etc)
|
||||
Execute(
|
||||
code cosmwasm.CodeID,
|
||||
env types.Env,
|
||||
info types.MessageInfo,
|
||||
executeMsg []byte,
|
||||
store cosmwasm.KVStore,
|
||||
goapi cosmwasm.GoAPI,
|
||||
querier cosmwasm.Querier,
|
||||
gasMeter cosmwasm.GasMeter,
|
||||
gasLimit uint64,
|
||||
) (*types.HandleResponse, uint64, error)
|
||||
|
||||
// Query allows a client to execute a contract-specific query. If the result is not empty, it should be
|
||||
// valid json-encoded data to return to the client.
|
||||
// The meaning of path and data can be determined by the code. Path is the suffix of the abci.QueryRequest.Path
|
||||
Query(
|
||||
code cosmwasm.CodeID,
|
||||
env types.Env,
|
||||
queryMsg []byte,
|
||||
store cosmwasm.KVStore,
|
||||
goapi cosmwasm.GoAPI,
|
||||
querier cosmwasm.Querier,
|
||||
gasMeter cosmwasm.GasMeter,
|
||||
gasLimit uint64,
|
||||
) ([]byte, uint64, error)
|
||||
|
||||
// Migrate will migrate an existing contract to a new code binary.
|
||||
// This takes storage of the data from the original contract and the CodeID of the new contract that should
|
||||
// replace it. This allows it to run a migration step if needed, or return an error if unable to migrate
|
||||
// the given data.
|
||||
//
|
||||
// MigrateMsg has some data on how to perform the migration.
|
||||
Migrate(
|
||||
code cosmwasm.CodeID,
|
||||
env types.Env,
|
||||
info types.MessageInfo,
|
||||
migrateMsg []byte,
|
||||
store cosmwasm.KVStore,
|
||||
goapi cosmwasm.GoAPI,
|
||||
querier cosmwasm.Querier,
|
||||
gasMeter cosmwasm.GasMeter,
|
||||
gasLimit uint64,
|
||||
) (*types.MigrateResponse, uint64, error)
|
||||
|
||||
// GetCode will load the original wasm code for the given code id.
|
||||
// This will only succeed if that code id was previously returned from
|
||||
// a call to Create.
|
||||
//
|
||||
// This can be used so that the (short) code id (hash) is stored in the iavl tree
|
||||
// and the larger binary blobs (wasm and pre-compiles) are all managed by the
|
||||
// rust library
|
||||
GetCode(code cosmwasm.CodeID) (cosmwasm.WasmCode, error)
|
||||
|
||||
// Cleanup should be called when no longer using this to free resources on the rust-side
|
||||
Cleanup()
|
||||
}
|
||||
@@ -85,11 +85,11 @@ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry)
|
||||
// AppModule implements an application module for the wasm module.
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
keeper Keeper
|
||||
keeper *Keeper
|
||||
}
|
||||
|
||||
// NewAppModule creates a new AppModule object
|
||||
func NewAppModule(keeper Keeper) AppModule {
|
||||
func NewAppModule(keeper *Keeper) AppModule {
|
||||
return AppModule{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
keeper: keeper,
|
||||
|
||||
@@ -36,7 +36,7 @@ func setupTest(t *testing.T) testData {
|
||||
module: NewAppModule(keeper),
|
||||
ctx: ctx,
|
||||
acctKeeper: acctKeeper,
|
||||
keeper: keeper,
|
||||
keeper: *keeper,
|
||||
bankKeeper: bankKeeper,
|
||||
}
|
||||
return data
|
||||
|
||||
Reference in New Issue
Block a user