Merge pull request #586 from CosmWasm/event_types_440

Refactor events
This commit is contained in:
Ethan Frey
2021-08-11 15:51:49 +02:00
committed by GitHub
16 changed files with 466 additions and 333 deletions

View File

@@ -402,6 +402,17 @@ If the original contract execution example above was actually the result of a me
and it registered a ReplyOn clause, the `reply` function on that contract would receive the entire 11 events in the example
above, and would need to use the `message` markers to locate the segment of interest.
## Governance Events
The governance process is handled by the cosmos-sdk `gov` module. We do not emit any events of type "message" anymore in v0.18+.
Context-specific events are emitted as described above. `Execution` and `Migration` return some contract result though that are
emitted as:
```go
sdk.NewEvent(
"gov_contract_result",
sdk.NewAttribute("result", hex.EncodeToString(data)),
)
```
## IBC Events
TODO: define what the default SDK messages are here and what we add to our custom keeper events.

View File

@@ -21,20 +21,6 @@ func newWasmModuleEvent(customAttributes []wasmvmtypes.EventAttribute, contractA
return sdk.Events{sdk.NewEvent(types.WasmModuleEventType, attrs...)}, nil
}
// returns true when a wasm module event was emitted for this contract already
func hasWasmModuleEvent(ctx sdk.Context, contractAddr sdk.AccAddress) bool {
for _, e := range ctx.EventManager().Events() {
if e.Type == types.WasmModuleEventType {
for _, a := range e.Attributes {
if string(a.Key) == types.AttributeKeyContractAddr && string(a.Value) == contractAddr.String() {
return true
}
}
}
}
return false
}
const eventTypeMinLength = 2
// newCustomEvents converts wasmvm events from a contract response to sdk type events

View File

@@ -251,3 +251,17 @@ func TestNewWasmModuleEvent(t *testing.T) {
})
}
}
// returns true when a wasm module event was emitted for this contract already
func hasWasmModuleEvent(ctx sdk.Context, contractAddr sdk.AccAddress) bool {
for _, e := range ctx.EventManager().Events() {
if e.Type == types.WasmModuleEventType {
for _, a := range e.Attributes {
if string(a.Key) == types.AttributeKeyContractAddr && string(a.Value) == contractAddr.String() {
return true
}
}
}
}
return false
}

View File

@@ -18,6 +18,8 @@ import (
"github.com/tendermint/tendermint/libs/log"
"math"
"path/filepath"
"strconv"
"strings"
"time"
)
@@ -178,6 +180,16 @@ func (k Keeper) create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte,
}
codeInfo := types.NewCodeInfo(checksum, creator, *instantiateAccess)
k.storeCodeInfo(ctx, codeID, codeInfo)
evt := sdk.NewEvent(
types.EventTypeStoreCode,
sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)),
)
for _, f := range strings.Split(report.RequiredFeatures, ",") {
evt.AppendAttributes(sdk.NewAttribute(types.AttributeKeyFeature, strings.TrimSpace(f)))
}
ctx.EventManager().EmitEvent(evt)
return codeID, nil
}
@@ -293,7 +305,12 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A
k.appendToContractHistory(ctx, contractAddress, historyEntry)
k.storeContractInfo(ctx, contractAddress, &contractInfo)
// dispatch submessages then messages
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeInstantiate,
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()),
sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)),
))
data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events)
if err != nil {
return nil, nil, sdkerrors.Wrap(err, "dispatch")
@@ -332,11 +349,16 @@ func (k Keeper) execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller
return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
}
// dispatch submessages then messages
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeExecute,
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()),
))
data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events)
if err != nil {
return nil, sdkerrors.Wrap(err, "dispatch")
}
return data, nil
}
@@ -396,11 +418,17 @@ func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller
k.addToContractCodeSecondaryIndex(ctx, contractAddress, historyEntry)
k.storeContractInfo(ctx, contractAddress, contractInfo)
// dispatch submessages then messages
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeMigrate,
sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(newCodeID, 10)),
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()),
))
data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events)
if err != nil {
return nil, sdkerrors.Wrap(err, "dispatch")
}
return data, nil
}
@@ -428,11 +456,16 @@ func (k Keeper) Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte
return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
}
// dispatch submessages then messages
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeSudo,
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()),
))
data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events)
if err != nil {
return nil, sdkerrors.Wrap(err, "dispatch")
}
return data, nil
}
@@ -461,11 +494,16 @@ func (k Keeper) reply(ctx sdk.Context, contractAddress sdk.AccAddress, reply was
return nil, sdkerrors.Wrap(types.ErrExecuteFailed, execErr.Error())
}
// dispatch submessages then messages
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeReply,
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddress.String()),
))
data, err := k.handleContractResponse(ctx, contractAddress, contractInfo.IBCPortID, res.Messages, res.Attributes, res.Data, res.Events)
if err != nil {
return nil, sdkerrors.Wrap(err, "dispatch")
}
return data, nil
}
@@ -709,6 +747,11 @@ func (k Keeper) pinCode(ctx sdk.Context, codeID uint64) error {
store := ctx.KVStore(k.storeKey)
// store 1 byte to not run into `nil` debugging issues
store.Set(types.GetPinnedCodeIndexPrefix(codeID), []byte{1})
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypePinCode,
sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)),
))
return nil
}
@@ -724,6 +767,11 @@ func (k Keeper) unpinCode(ctx sdk.Context, codeID uint64) error {
store := ctx.KVStore(k.storeKey)
store.Delete(types.GetPinnedCodeIndexPrefix(codeID))
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeUnpinCode,
sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(codeID, 10)),
))
return nil
}
@@ -775,7 +823,7 @@ func (k *Keeper) handleContractResponse(
attributeGasCost := k.gasRegister.EventCosts(attrs, evts)
ctx.GasMeter().ConsumeGas(attributeGasCost, "Custom contract event attributes")
// emit all events from this contract itself
if len(attrs) != 0 || !hasWasmModuleEvent(ctx, contractAddr) {
if len(attrs) != 0 {
wasmEvents, err := newWasmModuleEvent(attrs, contractAddr)
if err != nil {
return nil, err
@@ -985,7 +1033,9 @@ func NewBankCoinTransferrer(keeper types.BankKeeper) BankCoinTransferrer {
// TransferCoins transfers coins from source to destination account when coin send was enabled for them and the recipient
// is not in the blocked address list.
func (c BankCoinTransferrer) TransferCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error {
func (c BankCoinTransferrer) TransferCoins(parentCtx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error {
em := sdk.NewEventManager()
ctx := parentCtx.WithEventManager(em)
if err := c.keeper.SendEnabledCoins(ctx, amt...); err != nil {
return err
}
@@ -996,6 +1046,12 @@ func (c BankCoinTransferrer) TransferCoins(ctx sdk.Context, fromAddr sdk.AccAddr
if sdkerr != nil {
return sdkerr
}
for _, e := range em.Events() {
if e.Type == sdk.EventTypeMessage { // skip messages as we talk to the keeper directly
continue
}
parentCtx.EventManager().EmitEvent(e)
}
return nil
}
@@ -1016,12 +1072,19 @@ func NewDefaultWasmVMContractResponseHandler(md msgDispatcher) *DefaultWasmVMCon
// Handle processes the data returned by a contract invocation.
func (h DefaultWasmVMContractResponseHandler) Handle(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, messages []wasmvmtypes.SubMsg, origRspData []byte) ([]byte, error) {
em := sdk.NewEventManager()
result := origRspData
switch rsp, err := h.md.DispatchSubmessages(ctx, contractAddr, ibcPort, messages); {
switch rsp, err := h.md.DispatchSubmessages(ctx.WithEventManager(em), contractAddr, ibcPort, messages); {
case err != nil:
return nil, sdkerrors.Wrap(err, "submessages")
case rsp != nil:
result = rsp
}
// emit non message type events only
for _, e := range em.Events() {
if e.Type != sdk.EventTypeMessage {
ctx.EventManager().EmitEvent(e)
}
}
return result, nil
}

View File

@@ -40,13 +40,17 @@ func TestCreate(t *testing.T) {
wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm")
require.NoError(t, err)
contractID, err := keeper.Create(ctx, creator, wasmCode, nil)
em := sdk.NewEventManager()
codeID, err := keeper.Create(ctx.WithEventManager(em), creator, wasmCode, nil)
require.NoError(t, err)
require.Equal(t, uint64(1), contractID)
require.Equal(t, uint64(1), codeID)
// and verify content
storedCode, err := keepers.WasmKeeper.GetByteCode(ctx, contractID)
storedCode, err := keepers.WasmKeeper.GetByteCode(ctx, codeID)
require.NoError(t, err)
require.Equal(t, wasmCode, storedCode)
// and events emitted
exp := sdk.Events{sdk.NewEvent("store_code", sdk.NewAttribute("code_id", "1"))}
assert.Equal(t, exp, em.Events())
}
func TestCreateStoresInstantiatePermission(t *testing.T) {
@@ -277,8 +281,9 @@ func TestInstantiate(t *testing.T) {
gasBefore := ctx.GasMeter().GasConsumed()
em := sdk.NewEventManager()
// create with no balance is also legal
gotContractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, initMsgBz, "demo contract 1", nil)
gotContractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx.WithEventManager(em), codeID, creator, nil, initMsgBz, "demo contract 1", nil)
require.NoError(t, err)
require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhuc53mp6", gotContractAddr.String())
@@ -301,6 +306,15 @@ func TestInstantiate(t *testing.T) {
Msg: json.RawMessage(initMsgBz),
}}
assert.Equal(t, exp, keepers.WasmKeeper.GetContractHistory(ctx, gotContractAddr))
// and events emitted
expEvt := sdk.Events{
sdk.NewEvent("instantiate",
sdk.NewAttribute("_contract_address", gotContractAddr.String()), sdk.NewAttribute("code_id", "1")),
sdk.NewEvent("wasm",
sdk.NewAttribute("_contract_address", gotContractAddr.String()), sdk.NewAttribute("Let the", "hacking begin")),
}
assert.Equal(t, expEvt, em.Events())
}
func TestInstantiateWithDeposit(t *testing.T) {
@@ -508,8 +522,9 @@ func TestExecute(t *testing.T) {
// verifier can execute, and get proper gas amount
start := time.Now()
gasBefore := ctx.GasMeter().GasConsumed()
res, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"release":{}}`), topUp)
em := sdk.NewEventManager()
// when
res, err = keepers.ContractKeeper.Execute(ctx.WithEventManager(em), addr, fred, []byte(`{"release":{}}`), topUp)
diff := time.Now().Sub(start)
require.NoError(t, err)
require.NotNil(t, res)
@@ -530,6 +545,12 @@ func TestExecute(t *testing.T) {
require.NotNil(t, contractAcct)
assert.Equal(t, sdk.Coins(nil), bankKeeper.GetAllBalances(ctx, contractAcct.GetAddress()))
// and events emitted
require.Len(t, em.Events(), 5)
expEvt := sdk.NewEvent("execute",
sdk.NewAttribute("_contract_address", addr.String()))
assert.Equal(t, expEvt, em.Events()[1])
t.Logf("Duration: %v (%d gas)\n", diff, gasAfter-gasBefore)
}
@@ -1014,6 +1035,13 @@ func TestMigrateWithDispatchedMessage(t *testing.T) {
assert.Equal(t, "burnt 1 keys", string(data))
type dict map[string]interface{}
expEvents := []dict{
{
"Type": "migrate",
"Attr": []dict{
{"code_id": "2"},
{"_contract_address": contractAddr},
},
},
{
"Type": "wasm",
"Attr": []dict{
@@ -1030,21 +1058,9 @@ func TestMigrateWithDispatchedMessage(t *testing.T) {
{"amount": "100000denom"},
},
},
{
"Type": "message",
"Attr": []dict{
{"sender": contractAddr},
},
},
{
"Type": "message",
"Attr": []dict{
{"module": "bank"},
},
},
}
expJSONEvts := string(mustMarshal(t, expEvents))
assert.JSONEq(t, expJSONEvts, prettyEvents(t, ctx.EventManager().Events()))
assert.JSONEq(t, expJSONEvts, prettyEvents(t, ctx.EventManager().Events()), prettyEvents(t, ctx.EventManager().Events()))
// all persistent data cleared
m := keepers.WasmKeeper.QueryRaw(ctx, contractAddr, []byte("config"))
@@ -1160,7 +1176,6 @@ func TestSudo(t *testing.T) {
}
initMsgBz, err := json.Marshal(initMsg)
require.NoError(t, err)
addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit)
require.NoError(t, err)
require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhuc53mp6", addr.String())
@@ -1183,7 +1198,10 @@ func TestSudo(t *testing.T) {
sudoMsg, err := json.Marshal(msg)
require.NoError(t, err)
_, err = keepers.WasmKeeper.Sudo(ctx, addr, sudoMsg)
em := sdk.NewEventManager()
// when
_, err = keepers.WasmKeeper.Sudo(ctx.WithEventManager(em), addr, sudoMsg)
require.NoError(t, err)
// ensure community now exists and got paid
@@ -1191,6 +1209,12 @@ func TestSudo(t *testing.T) {
require.NotNil(t, comAcct)
balance := bankKeeper.GetBalance(ctx, comAcct.GetAddress(), "denom")
assert.Equal(t, sdk.NewInt64Coin("denom", 76543), balance)
// and events emitted
require.Len(t, em.Events(), 2)
expEvt := sdk.NewEvent("sudo",
sdk.NewAttribute("_contract_address", addr.String()))
assert.Equal(t, expEvt, em.Events()[0])
}
func prettyEvents(t *testing.T, events sdk.Events) string {
@@ -1355,6 +1379,66 @@ func TestClearContractAdmin(t *testing.T) {
}
}
func TestPinCode(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
k := keepers.WasmKeeper
var capturedChecksums []wasmvm.Checksum
mock := wasmtesting.MockWasmer{PinFn: func(checksum wasmvm.Checksum) error {
capturedChecksums = append(capturedChecksums, checksum)
return nil
}}
wasmtesting.MakeInstantiable(&mock)
myCodeID := StoreRandomContract(t, ctx, keepers, &mock).CodeID
require.Equal(t, uint64(1), myCodeID)
em := sdk.NewEventManager()
// when
gotErr := k.pinCode(ctx.WithEventManager(em), myCodeID)
// then
require.NoError(t, gotErr)
assert.NotEmpty(t, capturedChecksums)
assert.True(t, k.IsPinnedCode(ctx, myCodeID))
// and events
exp := sdk.Events{sdk.NewEvent("pin_code", sdk.NewAttribute("code_id", "1"))}
assert.Equal(t, exp, em.Events())
}
func TestUnpinCode(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
k := keepers.WasmKeeper
var capturedChecksums []wasmvm.Checksum
mock := wasmtesting.MockWasmer{
PinFn: func(checksum wasmvm.Checksum) error {
return nil
},
UnpinFn: func(checksum wasmvm.Checksum) error {
capturedChecksums = append(capturedChecksums, checksum)
return nil
}}
wasmtesting.MakeInstantiable(&mock)
myCodeID := StoreRandomContract(t, ctx, keepers, &mock).CodeID
require.Equal(t, uint64(1), myCodeID)
err := k.pinCode(ctx, myCodeID)
require.NoError(t, err)
em := sdk.NewEventManager()
// when
gotErr := k.unpinCode(ctx.WithEventManager(em), myCodeID)
// then
require.NoError(t, gotErr)
assert.NotEmpty(t, capturedChecksums)
assert.False(t, k.IsPinnedCode(ctx, myCodeID))
// and events
exp := sdk.Events{sdk.NewEvent("unpin_code", sdk.NewAttribute("code_id", "1"))}
assert.Equal(t, exp, em.Events())
}
func TestInitializePinnedCodes(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
k := keepers.WasmKeeper
@@ -1364,7 +1448,7 @@ func TestInitializePinnedCodes(t *testing.T) {
capturedChecksums = append(capturedChecksums, checksum)
return nil
}}
wasmtesting.MakeIBCInstantiable(&mock)
wasmtesting.MakeInstantiable(&mock)
const testItems = 3
myCodeIDs := make([]uint64, testItems)
@@ -1436,6 +1520,7 @@ func TestNewDefaultWasmVMContractResponseHandler(t *testing.T) {
setup func(m *wasmtesting.MockMsgDispatcher)
expErr bool
expData []byte
expEvts sdk.Events
}{
"submessage overwrites result when set": {
srcData: []byte("otherData"),
@@ -1446,6 +1531,7 @@ func TestNewDefaultWasmVMContractResponseHandler(t *testing.T) {
},
expErr: false,
expData: []byte("mySubMsgData"),
expEvts: sdk.Events{},
},
"submessage overwrites result when empty": {
srcData: []byte("otherData"),
@@ -1456,6 +1542,7 @@ func TestNewDefaultWasmVMContractResponseHandler(t *testing.T) {
},
expErr: false,
expData: []byte(""),
expEvts: sdk.Events{},
},
"submessage do not overwrite result when nil": {
srcData: []byte("otherData"),
@@ -1466,6 +1553,7 @@ func TestNewDefaultWasmVMContractResponseHandler(t *testing.T) {
},
expErr: false,
expData: []byte("otherData"),
expEvts: sdk.Events{},
},
"submessage error aborts process": {
setup: func(m *wasmtesting.MockMsgDispatcher) {
@@ -1475,6 +1563,24 @@ func TestNewDefaultWasmVMContractResponseHandler(t *testing.T) {
},
expErr: true,
},
"message events filtered out": {
setup: func(m *wasmtesting.MockMsgDispatcher) {
m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) {
ctx.EventManager().EmitEvent(sdk.NewEvent(sdk.EventTypeMessage))
return nil, nil
}
},
expEvts: sdk.Events{},
},
"message emit non message events": {
setup: func(m *wasmtesting.MockMsgDispatcher) {
m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) {
ctx.EventManager().EmitEvent(sdk.NewEvent("myEvent"))
return nil, nil
}
},
expEvts: sdk.Events{sdk.NewEvent("myEvent")},
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
@@ -1484,15 +1590,60 @@ func TestNewDefaultWasmVMContractResponseHandler(t *testing.T) {
var mock wasmtesting.MockMsgDispatcher
spec.setup(&mock)
d := NewDefaultWasmVMContractResponseHandler(&mock)
// when
em := sdk.NewEventManager()
gotData, gotErr := d.Handle(sdk.Context{}, RandomAccountAddress(t), "ibc-port", msgs, spec.srcData)
// when
gotData, gotErr := d.Handle(sdk.Context{}.WithEventManager(em), RandomAccountAddress(t), "ibc-port", msgs, spec.srcData)
if spec.expErr {
require.Error(t, gotErr)
return
}
require.NoError(t, gotErr)
assert.Equal(t, spec.expData, gotData)
assert.Equal(t, spec.expEvts, em.Events())
})
}
}
func TestReply(t *testing.T) {
ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
k := keepers.WasmKeeper
var mock wasmtesting.MockWasmer
wasmtesting.MakeInstantiable(&mock)
example := SeedNewContractInstance(t, ctx, keepers, &mock)
specs := map[string]struct {
rsp wasmvmtypes.Response
expData []byte
expErr bool
expEvt sdk.Events
}{
"all good": {
rsp: wasmvmtypes.Response{Data: []byte("foo")},
expData: []byte("foo"),
expEvt: sdk.Events{sdk.NewEvent("reply", sdk.NewAttribute("_contract_address", example.Contract.String()))},
},
"error": {
expErr: true,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
if spec.expErr {
return nil, 1, errors.New("testing")
}
return &spec.rsp, 1, nil
}
em := sdk.NewEventManager()
gotData, gotErr := k.reply(ctx.WithEventManager(em), example.Contract, wasmvmtypes.Reply{})
if spec.expErr {
require.Error(t, gotErr)
return
}
require.NoError(t, gotErr)
assert.Equal(t, spec.expData, gotData)
assert.Equal(t, spec.expEvt, em.Events())
})
}
}

View File

@@ -2,8 +2,6 @@ package keeper
import (
"context"
"encoding/hex"
"fmt"
"github.com/CosmWasm/wasmd/x/wasm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -25,18 +23,18 @@ func (m msgServer) StoreCode(goCtx context.Context, msg *types.MsgStoreCode) (*t
if err != nil {
return nil, sdkerrors.Wrap(err, "sender")
}
codeID, err := m.keeper.Create(ctx, senderAddr, msg.WASMByteCode, msg.InstantiatePermission)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeySigner, msg.Sender),
sdk.NewAttribute(types.AttributeKeyCodeID, fmt.Sprintf("%d", codeID)),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
))
codeID, err := m.keeper.Create(ctx, senderAddr, msg.WASMByteCode, msg.InstantiatePermission)
if err != nil {
return nil, err
}
return &types.MsgStoreCodeResponse{
CodeID: codeID,
}, nil
@@ -56,20 +54,17 @@ func (m msgServer) InstantiateContract(goCtx context.Context, msg *types.MsgInst
}
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
))
contractAddr, data, err := m.keeper.Instantiate(ctx, msg.CodeID, senderAddr, adminAddr, msg.Msg, msg.Label, msg.Funds)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeySigner, msg.Sender),
sdk.NewAttribute(types.AttributeKeyCodeID, fmt.Sprintf("%d", msg.CodeID)),
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddr.String()),
sdk.NewAttribute(types.AttributeResultDataHex, hex.EncodeToString(data)),
))
return &types.MsgInstantiateContractResponse{
Address: contractAddr.String(),
Data: data,
@@ -87,19 +82,17 @@ func (m msgServer) ExecuteContract(goCtx context.Context, msg *types.MsgExecuteC
return nil, sdkerrors.Wrap(err, "contract")
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
))
data, err := m.keeper.Execute(ctx, contractAddr, senderAddr, msg.Msg, msg.Funds)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeySigner, msg.Sender),
sdk.NewAttribute(types.AttributeKeyContractAddr, msg.Contract),
sdk.NewAttribute(types.AttributeResultDataHex, hex.EncodeToString(data)),
))
return &types.MsgExecuteContractResponse{
Data: data,
}, nil
@@ -116,20 +109,17 @@ func (m msgServer) MigrateContract(goCtx context.Context, msg *types.MsgMigrateC
return nil, sdkerrors.Wrap(err, "contract")
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
))
data, err := m.keeper.Migrate(ctx, contractAddr, senderAddr, msg.CodeID, msg.Msg)
if err != nil {
return nil, err
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeySigner, msg.Sender),
sdk.NewAttribute(types.AttributeKeyCodeID, fmt.Sprintf("%d", msg.CodeID)),
sdk.NewAttribute(types.AttributeKeyContractAddr, msg.Contract),
sdk.NewAttribute(types.AttributeResultDataHex, hex.EncodeToString(data)),
))
return &types.MsgMigrateContractResponse{
Data: data,
}, nil
@@ -150,17 +140,16 @@ func (m msgServer) UpdateAdmin(goCtx context.Context, msg *types.MsgUpdateAdmin)
return nil, sdkerrors.Wrap(err, "new admin")
}
if err := m.keeper.UpdateContractAdmin(ctx, contractAddr, senderAddr, newAdminAddr); err != nil {
return nil, err
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeySigner, msg.Sender),
sdk.NewAttribute(types.AttributeKeyContractAddr, msg.Contract),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
))
if err := m.keeper.UpdateContractAdmin(ctx, contractAddr, senderAddr, newAdminAddr); err != nil {
return nil, err
}
return &types.MsgUpdateAdminResponse{}, nil
}
@@ -175,16 +164,15 @@ func (m msgServer) ClearAdmin(goCtx context.Context, msg *types.MsgClearAdmin) (
return nil, sdkerrors.Wrap(err, "contract")
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender),
))
if err := m.keeper.ClearContractAdmin(ctx, contractAddr, senderAddr); err != nil {
return nil, err
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeySigner, msg.Sender),
sdk.NewAttribute(types.AttributeKeyContractAddr, msg.Contract),
))
return &types.MsgClearAdminResponse{}, nil
}

View File

@@ -2,12 +2,10 @@ package keeper
import (
"encoding/hex"
"fmt"
"github.com/CosmWasm/wasmd/x/wasm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"strconv"
)
// NewWasmProposalHandler creates a new governance Handler for wasm proposals
@@ -58,18 +56,8 @@ func handleStoreCodeProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types
if err != nil {
return sdkerrors.Wrap(err, "run as address")
}
codeID, err := k.Create(ctx, runAsAddr, p.WASMByteCode, p.InstantiatePermission)
if err != nil {
return err
}
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyCodeID, fmt.Sprintf("%d", codeID)),
)
ctx.EventManager().EmitEvent(ourEvent)
return nil
_, err = k.Create(ctx, runAsAddr, p.WASMByteCode, p.InstantiatePermission)
return err
}
func handleInstantiateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.InstantiateContractProposal) error {
@@ -85,19 +73,15 @@ func handleInstantiateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p typ
return sdkerrors.Wrap(err, "admin")
}
contractAddr, data, err := k.Instantiate(ctx, p.CodeID, runAsAddr, adminAddr, p.Msg, p.Label, p.Funds)
_, data, err := k.Instantiate(ctx, p.CodeID, runAsAddr, adminAddr, p.Msg, p.Label, p.Funds)
if err != nil {
return err
}
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyCodeID, fmt.Sprintf("%d", p.CodeID)),
sdk.NewAttribute(types.AttributeKeyContractAddr, contractAddr.String()),
sdk.NewAttribute(types.AttributeResultDataHex, hex.EncodeToString(data)),
)
ctx.EventManager().EmitEvent(ourEvent)
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeGovContractResult,
sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)),
))
return nil
}
@@ -119,14 +103,10 @@ func handleMigrateProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.M
return err
}
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyCodeID, fmt.Sprintf("%d", p.CodeID)),
sdk.NewAttribute(types.AttributeKeyContractAddr, p.Contract),
sdk.NewAttribute(types.AttributeResultDataHex, hex.EncodeToString(data)),
)
ctx.EventManager().EmitEvent(ourEvent)
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeGovContractResult,
sdk.NewAttribute(types.AttributeKeyResultDataHex, hex.EncodeToString(data)),
))
return nil
}
@@ -143,17 +123,7 @@ func handleUpdateAdminProposal(ctx sdk.Context, k types.ContractOpsKeeper, p typ
return sdkerrors.Wrap(err, "run as address")
}
if err := k.UpdateContractAdmin(ctx, contractAddr, nil, newAdminAddr); err != nil {
return err
}
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyContractAddr, p.Contract),
)
ctx.EventManager().EmitEvent(ourEvent)
return nil
return k.UpdateContractAdmin(ctx, contractAddr, nil, newAdminAddr)
}
func handleClearAdminProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.ClearAdminProposal) error {
@@ -168,12 +138,6 @@ func handleClearAdminProposal(ctx sdk.Context, k types.ContractOpsKeeper, p type
if err := k.ClearContractAdmin(ctx, contractAddr, nil); err != nil {
return err
}
ourEvent := sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyContractAddr, p.Contract),
)
ctx.EventManager().EmitEvent(ourEvent)
return nil
}
@@ -186,14 +150,6 @@ func handlePinCodesProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.
return sdkerrors.Wrapf(err, "code id: %d", v)
}
}
for _, v := range p.CodeIDs {
ourEvent := sdk.NewEvent(
types.EventTypePinCode,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(v, 10)),
)
ctx.EventManager().EmitEvent(ourEvent)
}
return nil
}
@@ -206,13 +162,5 @@ func handleUnpinCodesProposal(ctx sdk.Context, k types.ContractOpsKeeper, p type
return sdkerrors.Wrapf(err, "code id: %d", v)
}
}
for _, v := range p.CodeIDs {
ourEvent := sdk.NewEvent(
types.EventTypeUnpinCode,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyCodeID, strconv.FormatUint(v, 10)),
)
ctx.EventManager().EmitEvent(ourEvent)
}
return nil
}

View File

@@ -111,8 +111,12 @@ func TestInstantiateProposal(t *testing.T) {
}}
assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddr))
// and event
require.Len(t, em.Events(), 2, "%#v", em.Events())
require.Len(t, em.Events()[1].Attributes, 4)
require.Len(t, em.Events(), 3, "%#v", em.Events())
require.Equal(t, types.EventTypeInstantiate, em.Events()[0].Type)
require.Equal(t, types.WasmModuleEventType, em.Events()[1].Type)
require.Equal(t, types.EventTypeGovContractResult, em.Events()[2].Type)
require.Len(t, em.Events()[2].Attributes, 1)
require.NotEmpty(t, em.Events()[2].Attributes[0])
}
func TestMigrateProposal(t *testing.T) {
@@ -192,7 +196,10 @@ func TestMigrateProposal(t *testing.T) {
assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddr))
// and events emitted
require.Len(t, em.Events(), 2)
require.Len(t, em.Events()[1].Attributes, 4)
assert.Equal(t, types.EventTypeMigrate, em.Events()[0].Type)
require.Equal(t, types.EventTypeGovContractResult, em.Events()[1].Type)
require.Len(t, em.Events()[1].Attributes, 1)
assert.Equal(t, types.AttributeKeyResultDataHex, string(em.Events()[1].Attributes[0].Key))
}
func TestAdminProposals(t *testing.T) {

View File

@@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting"
"github.com/CosmWasm/wasmd/x/wasm/types"
wasmvm "github.com/CosmWasm/wasmvm"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -92,14 +93,13 @@ func TestOnConnectChannel(t *testing.T) {
const myContractGas = 40
specs := map[string]struct {
contractAddr sdk.AccAddress
contractResp *wasmvmtypes.IBCBasicResponse
contractErr error
overwriteMessenger *wasmtesting.MockMessageHandler
expContractGas sdk.Gas
expErr bool
expContractEventAttrs int
expNoEvents bool
contractAddr sdk.AccAddress
contractResp *wasmvmtypes.IBCBasicResponse
contractErr error
overwriteMessenger *wasmtesting.MockMessageHandler
expContractGas sdk.Gas
expErr bool
expEventTypes []string
}{
"consume contract gas": {
contractAddr: example.Contract,
@@ -115,7 +115,6 @@ func TestOnConnectChannel(t *testing.T) {
},
contractErr: errors.New("test, ignore"),
expErr: true,
expNoEvents: true,
},
"dispatch contract messages on success": {
contractAddr: example.Contract,
@@ -130,7 +129,7 @@ func TestOnConnectChannel(t *testing.T) {
contractResp: &wasmvmtypes.IBCBasicResponse{
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
expContractEventAttrs: 1,
expEventTypes: []string{types.WasmModuleEventType},
},
"messenger errors returned, events stored": {
contractAddr: example.Contract,
@@ -139,14 +138,13 @@ func TestOnConnectChannel(t *testing.T) {
Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}},
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expContractEventAttrs: 1,
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expEventTypes: []string{types.WasmModuleEventType},
},
"unknown contract address": {
contractAddr: RandomAccountAddress(t),
expErr: true,
expNoEvents: true,
},
}
for name, spec := range specs {
@@ -177,16 +175,10 @@ func TestOnConnectChannel(t *testing.T) {
err := keepers.WasmKeeper.OnConnectChannel(ctx, spec.contractAddr, msg)
// then
events := ctx.EventManager().Events()
if spec.expErr {
require.Error(t, err)
assert.Empty(t, capturedMsgs) // no messages captured on error
if spec.expNoEvents {
require.Len(t, events, 0)
} else {
require.Len(t, events, 1)
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
}
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
return
}
require.NoError(t, err)
@@ -198,9 +190,7 @@ func TestOnConnectChannel(t *testing.T) {
for i, m := range spec.contractResp.Messages {
assert.Equal(t, (*capturedMsgs)[i], m.Msg)
}
// verify events
require.Len(t, events, 1)
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
})
}
}
@@ -214,14 +204,13 @@ func TestOnCloseChannel(t *testing.T) {
const myContractGas = 40
specs := map[string]struct {
contractAddr sdk.AccAddress
contractResp *wasmvmtypes.IBCBasicResponse
contractErr error
overwriteMessenger *wasmtesting.MockMessageHandler
expContractGas sdk.Gas
expErr bool
expContractEventAttrs int
expNoEvents bool
contractAddr sdk.AccAddress
contractResp *wasmvmtypes.IBCBasicResponse
contractErr error
overwriteMessenger *wasmtesting.MockMessageHandler
expContractGas sdk.Gas
expErr bool
expEventTypes []string
}{
"consume contract gas": {
contractAddr: example.Contract,
@@ -237,7 +226,6 @@ func TestOnCloseChannel(t *testing.T) {
},
contractErr: errors.New("test, ignore"),
expErr: true,
expNoEvents: true,
},
"dispatch contract messages on success": {
contractAddr: example.Contract,
@@ -252,7 +240,7 @@ func TestOnCloseChannel(t *testing.T) {
contractResp: &wasmvmtypes.IBCBasicResponse{
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
expContractEventAttrs: 1,
expEventTypes: []string{types.WasmModuleEventType},
},
"messenger errors returned, events stored": {
contractAddr: example.Contract,
@@ -261,14 +249,13 @@ func TestOnCloseChannel(t *testing.T) {
Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}},
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expContractEventAttrs: 1,
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expEventTypes: []string{types.WasmModuleEventType},
},
"unknown contract address": {
contractAddr: RandomAccountAddress(t),
expErr: true,
expNoEvents: true,
},
}
for name, spec := range specs {
@@ -298,16 +285,10 @@ func TestOnCloseChannel(t *testing.T) {
err := keepers.WasmKeeper.OnCloseChannel(ctx, spec.contractAddr, msg)
// then
events := ctx.EventManager().Events()
if spec.expErr {
require.Error(t, err)
assert.Empty(t, capturedMsgs) // no messages captured on error
if spec.expNoEvents {
require.Len(t, events, 0)
} else {
require.Len(t, events, 1)
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
}
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
return
}
require.NoError(t, err)
@@ -319,8 +300,7 @@ func TestOnCloseChannel(t *testing.T) {
for i, m := range spec.contractResp.Messages {
assert.Equal(t, (*capturedMsgs)[i], m.Msg)
}
require.Len(t, events, 1)
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
})
}
}
@@ -342,10 +322,7 @@ func TestOnRecvPacket(t *testing.T) {
expContractGas sdk.Gas
expAck []byte
expErr bool
// normally 0 on error, 1 on success, if we return custom events, this may be > 1
expContractEvents int
// how many custom attributes are on the "wasm" event (not counting _contract_address)
expContractEventAttrs int
expEventTypes []string
}{
"consume contract gas": {
contractAddr: example.Contract,
@@ -353,14 +330,12 @@ func TestOnRecvPacket(t *testing.T) {
contractResp: &wasmvmtypes.IBCReceiveResponse{
Acknowledgement: []byte("myAck"),
},
expAck: []byte("myAck"),
expContractEvents: 1,
expAck: []byte("myAck"),
},
"can return empty ack": {
contractAddr: example.Contract,
expContractGas: myContractGas,
contractResp: &wasmvmtypes.IBCReceiveResponse{},
expContractEvents: 1,
contractAddr: example.Contract,
expContractGas: myContractGas,
contractResp: &wasmvmtypes.IBCReceiveResponse{},
},
"consume gas on error, ignore events + messages": {
contractAddr: example.Contract,
@@ -380,8 +355,7 @@ func TestOnRecvPacket(t *testing.T) {
Acknowledgement: []byte("myAck"),
Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}},
},
expContractEvents: 1,
expAck: []byte("myAck"),
expAck: []byte("myAck"),
},
"emit contract attributes on success": {
contractAddr: example.Contract,
@@ -390,9 +364,8 @@ func TestOnRecvPacket(t *testing.T) {
Acknowledgement: []byte("myAck"),
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
expContractEvents: 1,
expContractEventAttrs: 1,
expAck: []byte("myAck"),
expEventTypes: []string{types.WasmModuleEventType},
expAck: []byte("myAck"),
},
"emit contract events on success": {
contractAddr: example.Contract,
@@ -408,9 +381,8 @@ func TestOnRecvPacket(t *testing.T) {
}},
}},
},
expContractEvents: 2,
expContractEventAttrs: 1,
expAck: []byte("myAck"),
expEventTypes: []string{types.WasmModuleEventType, "wasm-custom"},
expAck: []byte("myAck"),
},
"messenger errors returned, events stored": {
contractAddr: example.Contract,
@@ -420,10 +392,9 @@ func TestOnRecvPacket(t *testing.T) {
Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}},
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expContractEvents: 1,
expContractEventAttrs: 1,
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expEventTypes: []string{types.WasmModuleEventType},
},
"submessage reply can overwrite ack data": {
contractAddr: example.Contract,
@@ -435,8 +406,8 @@ func TestOnRecvPacket(t *testing.T) {
mockReplyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
return &wasmvmtypes.Response{Data: []byte("myBetterAck")}, 0, nil
},
expAck: []byte("myBetterAck"),
expContractEvents: 1,
expAck: []byte("myBetterAck"),
expEventTypes: []string{types.EventTypeReply},
},
"unknown contract address": {
contractAddr: RandomAccountAddress(t),
@@ -473,14 +444,10 @@ func TestOnRecvPacket(t *testing.T) {
gotAck, err := keepers.WasmKeeper.OnRecvPacket(ctx, spec.contractAddr, msg)
// then
events := ctx.EventManager().Events()
if spec.expErr {
require.Error(t, err)
assert.Empty(t, capturedMsgs) // no messages captured on error
require.Len(t, events, spec.expContractEvents)
if spec.expContractEvents > 0 {
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
}
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
return
}
require.NoError(t, err)
@@ -494,8 +461,7 @@ func TestOnRecvPacket(t *testing.T) {
for i, m := range spec.contractResp.Messages {
assert.Equal(t, (*capturedMsgs)[i], m.Msg)
}
require.Len(t, events, spec.expContractEvents)
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
})
}
}
@@ -509,14 +475,13 @@ func TestOnAckPacket(t *testing.T) {
const myContractGas = 40
specs := map[string]struct {
contractAddr sdk.AccAddress
contractResp *wasmvmtypes.IBCBasicResponse
contractErr error
overwriteMessenger *wasmtesting.MockMessageHandler
expContractGas sdk.Gas
expErr bool
expContractEventAttrs int
expNoEvents bool
contractAddr sdk.AccAddress
contractResp *wasmvmtypes.IBCBasicResponse
contractErr error
overwriteMessenger *wasmtesting.MockMessageHandler
expContractGas sdk.Gas
expErr bool
expEventTypes []string
}{
"consume contract gas": {
contractAddr: example.Contract,
@@ -532,7 +497,6 @@ func TestOnAckPacket(t *testing.T) {
},
contractErr: errors.New("test, ignore"),
expErr: true,
expNoEvents: true,
},
"dispatch contract messages on success": {
contractAddr: example.Contract,
@@ -547,7 +511,7 @@ func TestOnAckPacket(t *testing.T) {
contractResp: &wasmvmtypes.IBCBasicResponse{
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
expContractEventAttrs: 1,
expEventTypes: []string{types.WasmModuleEventType},
},
"messenger errors returned, events stored": {
contractAddr: example.Contract,
@@ -556,14 +520,13 @@ func TestOnAckPacket(t *testing.T) {
Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}},
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expContractEventAttrs: 1,
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expEventTypes: []string{types.WasmModuleEventType},
},
"unknown contract address": {
contractAddr: RandomAccountAddress(t),
expErr: true,
expNoEvents: true,
},
}
for name, spec := range specs {
@@ -588,16 +551,11 @@ func TestOnAckPacket(t *testing.T) {
err := keepers.WasmKeeper.OnAckPacket(ctx, spec.contractAddr, myAck)
// then
events := ctx.EventManager().Events()
if spec.expErr {
require.Error(t, err)
assert.Empty(t, capturedMsgs) // no messages captured on error
if spec.expNoEvents {
require.Len(t, events, 0)
} else {
require.Len(t, events, 1)
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
}
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
return
}
require.NoError(t, err)
@@ -609,9 +567,7 @@ func TestOnAckPacket(t *testing.T) {
for i, m := range spec.contractResp.Messages {
assert.Equal(t, (*capturedMsgs)[i], m.Msg)
}
require.Len(t, events, 1)
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
})
}
}
@@ -631,16 +587,12 @@ func TestOnTimeoutPacket(t *testing.T) {
overwriteMessenger *wasmtesting.MockMessageHandler
expContractGas sdk.Gas
expErr bool
// normally 0 on error, 1 on success, if we return custom events, this may be > 1
expContractEvents int
// how many custom attributes are on the "wasm" event (not counting _contract_address)
expContractEventAttrs int
expEventTypes []string
}{
"consume contract gas": {
contractAddr: example.Contract,
expContractGas: myContractGas,
contractResp: &wasmvmtypes.IBCBasicResponse{},
expContractEvents: 1,
contractAddr: example.Contract,
expContractGas: myContractGas,
contractResp: &wasmvmtypes.IBCBasicResponse{},
},
"consume gas on error, ignore events + messages": {
contractAddr: example.Contract,
@@ -658,7 +610,6 @@ func TestOnTimeoutPacket(t *testing.T) {
contractResp: &wasmvmtypes.IBCBasicResponse{
Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}},
},
expContractEvents: 1,
},
"emit contract attributes on success": {
contractAddr: example.Contract,
@@ -666,8 +617,7 @@ func TestOnTimeoutPacket(t *testing.T) {
contractResp: &wasmvmtypes.IBCBasicResponse{
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
expContractEvents: 1,
expContractEventAttrs: 1,
expEventTypes: []string{types.WasmModuleEventType},
},
"emit contract events on success": {
contractAddr: example.Contract,
@@ -682,21 +632,18 @@ func TestOnTimeoutPacket(t *testing.T) {
}},
}},
},
expContractEvents: 2,
expContractEventAttrs: 1,
expEventTypes: []string{types.WasmModuleEventType, "wasm-custom"},
},
// TODO: I am a bit confued this does return events on error...
"messenger errors returned, events stored": {
"messenger errors returned, events stored before": {
contractAddr: example.Contract,
expContractGas: myContractGas + 10,
contractResp: &wasmvmtypes.IBCBasicResponse{
Messages: []wasmvmtypes.SubMsg{{ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Bank: &wasmvmtypes.BankMsg{}}}, {ReplyOn: wasmvmtypes.ReplyNever, Msg: wasmvmtypes.CosmosMsg{Custom: json.RawMessage(`{"foo":"bar"}`)}}},
Attributes: []wasmvmtypes.EventAttribute{{Key: "Foo", Value: "Bar"}},
},
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expContractEvents: 1,
expContractEventAttrs: 1,
overwriteMessenger: wasmtesting.NewErroringMessageHandler(),
expErr: true,
expEventTypes: []string{types.WasmModuleEventType},
},
"unknown contract address": {
contractAddr: RandomAccountAddress(t),
@@ -725,14 +672,10 @@ func TestOnTimeoutPacket(t *testing.T) {
err := keepers.WasmKeeper.OnTimeoutPacket(ctx, spec.contractAddr, msg)
// then
events := ctx.EventManager().Events()
if spec.expErr {
require.Error(t, err)
assert.Empty(t, capturedMsgs) // no messages captured on error
require.Len(t, events, spec.expContractEvents)
if spec.expContractEvents > 0 {
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
}
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
return
}
require.NoError(t, err)
@@ -744,8 +687,15 @@ func TestOnTimeoutPacket(t *testing.T) {
for i, m := range spec.contractResp.Messages {
assert.Equal(t, (*capturedMsgs)[i], m.Msg)
}
require.Len(t, events, spec.expContractEvents)
assert.Len(t, events[0].Attributes, 1+spec.expContractEventAttrs)
assert.Equal(t, spec.expEventTypes, stripTypes(ctx.EventManager().Events()))
})
}
}
func stripTypes(events sdk.Events) []string {
var r []string
for _, e := range events {
r = append(r, e.Type)
}
return r
}

View File

@@ -210,7 +210,7 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) {
assertReturnedEvents := func(expectedEvents int) assertion {
return func(t *testing.T, ctx sdk.Context, contract, emptyAccount string, response wasmvmtypes.SubcallResult) {
assert.Len(t, response.Ok.Events, expectedEvents)
require.Len(t, response.Ok.Events, expectedEvents)
}
}
@@ -231,14 +231,14 @@ func TestDispatchSubMsgErrorHandling(t *testing.T) {
assertGotContractAddr := func(t *testing.T, ctx sdk.Context, contract, emptyAccount string, response wasmvmtypes.SubcallResult) {
// should get the events emitted on new contract
event := response.Ok.Events[0]
assert.Equal(t, event.Type, "wasm")
require.Equal(t, event.Type, "instantiate")
assert.Equal(t, event.Attributes[0].Key, "_contract_address")
eventAddr := event.Attributes[0].Value
assert.NotEqual(t, contract, eventAddr)
// data field is the raw canonical address
// QUESTION: why not types.MsgInstantiateContractResponse? difference between calling Router and Service?
assert.Len(t, response.Ok.Data, 20)
require.Len(t, response.Ok.Data, 20)
resAddr := sdk.AccAddress(response.Ok.Data)
assert.Equal(t, eventAddr, resAddr.String())
}

View File

@@ -17,4 +17,7 @@ done
# create the zip variant
gzip -k hackatom.wasm
mv hackatom.wasm.gz hackatom.wasm.gzip
mv hackatom.wasm.gz hackatom.wasm.gzip
rm -f version.txt
echo "$tag" >version.txt

Binary file not shown.

Binary file not shown.

1
x/wasm/keeper/testdata/version.txt vendored Normal file
View File

@@ -0,0 +1 @@
v0.16.0+contracts

View File

@@ -179,11 +179,12 @@ func TestHandleInstantiate(t *testing.T) {
require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhuc53mp6", contractBech32Addr)
// this should be standard x/wasm init event, nothing from contract
require.Equal(t, 2, len(res.Events), prettyEvents(res.Events))
assert.Equal(t, "wasm", res.Events[0].Type)
assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[0].Attributes[0])
assert.Equal(t, "message", res.Events[1].Type)
assertAttribute(t, "module", "wasm", res.Events[1].Attributes[0])
require.Equal(t, 3, len(res.Events), prettyEvents(res.Events))
require.Equal(t, "message", res.Events[0].Type)
assertAttribute(t, "module", "wasm", res.Events[0].Attributes[0])
require.Equal(t, "instantiate", res.Events[1].Type)
require.Equal(t, "wasm", res.Events[2].Type)
assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[2].Attributes[0])
assertCodeList(t, q, data.ctx, 1)
assertCodeBytes(t, q, data.ctx, 1, testContract)
@@ -235,13 +236,14 @@ func TestHandleExecute(t *testing.T) {
contractBech32Addr := parseInitResponse(t, res.Data)
require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhuc53mp6", contractBech32Addr)
// this should be standard x/wasm init event, plus a bank send event (2), with no custom contract events
require.Equal(t, 3, len(res.Events), prettyEvents(res.Events))
assert.Equal(t, "transfer", res.Events[0].Type)
assert.Equal(t, "wasm", res.Events[1].Type)
assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[1].Attributes[0])
assert.Equal(t, "message", res.Events[2].Type)
assertAttribute(t, "module", "wasm", res.Events[2].Attributes[0])
// this should be standard x/wasm message event, init event, plus a bank send event (2), with no custom contract events
require.Equal(t, 4, len(res.Events), prettyEvents(res.Events))
require.Equal(t, "message", res.Events[0].Type)
assertAttribute(t, "module", "wasm", res.Events[0].Attributes[0])
require.Equal(t, "transfer", res.Events[1].Type)
require.Equal(t, "instantiate", res.Events[2].Type)
require.Equal(t, "wasm", res.Events[3].Type)
assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[3].Attributes[0])
// ensure bob doesn't exist
bobAcct := data.acctKeeper.GetAccount(data.ctx, bob)
@@ -271,29 +273,33 @@ func TestHandleExecute(t *testing.T) {
assertExecuteResponse(t, res.Data, []byte{0xf0, 0x0b, 0xaa})
// this should be standard message event, plus x/wasm init event, plus 2 bank send event, plus a special event from the contract
require.Equal(t, 5, len(res.Events), prettyEvents(res.Events))
require.Equal(t, 6, len(res.Events), prettyEvents(res.Events))
assert.Equal(t, "message", res.Events[0].Type)
assertAttribute(t, "module", "wasm", res.Events[0].Attributes[0])
require.Equal(t, "transfer", res.Events[1].Type)
require.Len(t, res.Events[1].Attributes, 3)
assertAttribute(t, "recipient", contractBech32Addr, res.Events[1].Attributes[0])
assertAttribute(t, "sender", fred.String(), res.Events[1].Attributes[1])
assertAttribute(t, "amount", "5000denom", res.Events[1].Attributes[2])
assert.Equal(t, "execute", res.Events[2].Type)
require.Equal(t, "transfer", res.Events[0].Type)
require.Len(t, res.Events[0].Attributes, 3)
assertAttribute(t, "recipient", contractBech32Addr, res.Events[0].Attributes[0])
assertAttribute(t, "sender", fred.String(), res.Events[0].Attributes[1])
assertAttribute(t, "amount", "5000denom", res.Events[0].Attributes[2])
// custom contract event attribute
assert.Equal(t, "wasm", res.Events[1].Type)
assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[1].Attributes[0])
assertAttribute(t, "action", "release", res.Events[1].Attributes[1])
assert.Equal(t, "wasm", res.Events[3].Type)
assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[3].Attributes[0])
assertAttribute(t, "action", "release", res.Events[3].Attributes[1])
// custom contract event
assert.Equal(t, "wasm-hackatom", res.Events[2].Type)
assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[1].Attributes[0])
assertAttribute(t, "action", "release", res.Events[1].Attributes[1])
assert.Equal(t, "wasm-hackatom", res.Events[4].Type)
assertAttribute(t, "_contract_address", contractBech32Addr, res.Events[4].Attributes[0])
assertAttribute(t, "action", "release", res.Events[4].Attributes[1])
// second transfer (this without conflicting message)
assert.Equal(t, "transfer", res.Events[3].Type)
assertAttribute(t, "recipient", bob.String(), res.Events[3].Attributes[0])
assertAttribute(t, "sender", contractBech32Addr, res.Events[3].Attributes[1])
assertAttribute(t, "amount", "105000denom", res.Events[3].Attributes[2])
assert.Equal(t, "transfer", res.Events[5].Type)
assertAttribute(t, "recipient", bob.String(), res.Events[5].Attributes[0])
assertAttribute(t, "sender", contractBech32Addr, res.Events[5].Attributes[1])
assertAttribute(t, "amount", "105000denom", res.Events[5].Attributes[2])
// finally, standard x/wasm tag
assert.Equal(t, "message", res.Events[4].Type)
assertAttribute(t, "module", "wasm", res.Events[4].Attributes[0])
// ensure bob now exists and got both payments released
bobAcct = data.acctKeeper.GetAccount(data.ctx, bob)

View File

@@ -1,23 +1,28 @@
package types
const (
// WasmModuleEventType is stored with any contract TX
// WasmModuleEventType is stored with any contract TX that returns non empty EventAttributes
WasmModuleEventType = "wasm"
// CustomContractEventPrefix contracts can create custom events. To not mix them with other system events they got the `wasm-` prefix.
CustomContractEventPrefix = "wasm-"
EventTypePinCode = "pin_code"
EventTypeUnpinCode = "unpin_code"
EventTypeStoreCode = "store_code"
EventTypeInstantiate = "instantiate"
EventTypeExecute = "execute"
EventTypeMigrate = "migrate"
EventTypePinCode = "pin_code"
EventTypeUnpinCode = "unpin_code"
EventTypeSudo = "sudo"
EventTypeReply = "reply"
EventTypeGovContractResult = "gov_contract_result"
)
// event attributes returned from contract execution
const (
AttributeReservedPrefix = "_"
AttributeKeyContractAddr = "_contract_address"
)
AttributeReservedPrefix = "_"
// event attributes returned under "message" type - no prefix needed there
const (
AttributeKeyCodeID = "code_id"
AttributeKeySigner = "signer"
AttributeResultDataHex = "result"
AttributeKeyContractAddr = "_contract_address"
AttributeKeyCodeID = "code_id"
AttributeKeyResultDataHex = "result"
AttributeKeyFeature = "feature"
)