Skip to content

Commit

Permalink
feat!: use antehandlers for wasm calls to core
Browse files Browse the repository at this point in the history
  • Loading branch information
cgorenflo committed Nov 30, 2023
1 parent 6fbb8da commit b6c05ef
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 94 deletions.
35 changes: 20 additions & 15 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package app
import (
"encoding/json"
"fmt"
ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante"
"io"
stdlog "log"
"net/http"
Expand Down Expand Up @@ -83,7 +84,6 @@ import (
ibcclientclient "github.com/cosmos/ibc-go/v4/modules/core/02-client/client"
porttypes "github.com/cosmos/ibc-go/v4/modules/core/05-port/types"
ibchost "github.com/cosmos/ibc-go/v4/modules/core/24-host"
ibcante "github.com/cosmos/ibc-go/v4/modules/core/ante"
ibckeeper "github.com/cosmos/ibc-go/v4/modules/core/keeper"
"github.com/gorilla/mux"
ibchooks "github.com/osmosis-labs/osmosis/x/ibc-hooks"
Expand Down Expand Up @@ -245,7 +245,7 @@ func NewAxelarApp(
setKeeper(keepers, initIBCTransferKeeper(appCodec, keys, keepers, ics4Wrapper))

setKeeper(keepers, initAxelarIBCKeeper(keepers))
setKeeper(keepers, initWasmKeeper(appCodec, keys, keepers, bApp, wasmDir, wasmConfig, wasmOpts))
setKeeper(keepers, initWasmKeeper(encodingConfig, keys, keepers, bApp, wasmDir, wasmConfig, wasmOpts))
setKeeper(keepers, initWasmContractKeeper(keepers))

// set the contract keeper for the Ics20WasmHooks
Expand Down Expand Up @@ -594,6 +594,7 @@ func initAnteHandlers(encodingConfig axelarParams.EncodingConfig, keys map[strin

anteDecorators := []sdk.AnteDecorator{
ante.NewAnteHandlerDecorator(baseAnteHandler),
ibcante.NewAnteDecorator(getKeeper[ibckeeper.Keeper](keepers)),
}

// enforce wasm limits earlier in the ante handler chain
Expand All @@ -607,29 +608,33 @@ func initAnteHandlers(encodingConfig axelarParams.EncodingConfig, keys map[strin
}

anteDecorators = append(anteDecorators,
ante.NewLogMsgDecorator(encodingConfig.Codec),
ante.NewCheckCommissionRate(getKeeper[stakingkeeper.Keeper](keepers)),
ante.NewUndelegateDecorator(
getKeeper[multisigKeeper.Keeper](keepers),
getKeeper[nexusKeeper.Keeper](keepers),
getKeeper[snapKeeper.Keeper](keepers),
),
ante.NewCheckRefundFeeDecorator(
encodingConfig.InterfaceRegistry,
getKeeper[authkeeper.AccountKeeper](keepers),
getKeeper[stakingkeeper.Keeper](keepers),
getKeeper[snapKeeper.Keeper](keepers),
getKeeper[rewardKeeper.Keeper](keepers),
),
ante.NewCheckProxy(getKeeper[snapKeeper.Keeper](keepers)),
ante.NewRestrictedTx(getKeeper[permissionKeeper.Keeper](keepers)),
ibcante.NewAnteDecorator(getKeeper[ibckeeper.Keeper](keepers)),
ante.NewAnteHandlerDecorator(
initMessageAnteDecorators(encodingConfig, keepers).ToAnteHandler()),
)

anteHandler := sdk.ChainAnteDecorators(
anteDecorators...,
return sdk.ChainAnteDecorators(anteDecorators...)
}

func initMessageAnteDecorators(encodingConfig axelarParams.EncodingConfig, keepers *keeperCache) ante.MessageAnteHandler {
return ante.ChainMessageAnteDecorators(
ante.NewLogMsgDecorator(encodingConfig.Codec),
ante.NewCheckCommissionRate(getKeeper[stakingkeeper.Keeper](keepers)),
ante.NewUndelegateDecorator(
getKeeper[multisigKeeper.Keeper](keepers),
getKeeper[nexusKeeper.Keeper](keepers),
getKeeper[snapKeeper.Keeper](keepers),
),

ante.NewCheckProxy(getKeeper[snapKeeper.Keeper](keepers)),
ante.NewRestrictedTx(getKeeper[permissionKeeper.Keeper](keepers)),
)
return anteHandler
}

func initModuleAccountPermissions() map[string][]string {
Expand Down
43 changes: 38 additions & 5 deletions app/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package app

import (
"fmt"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
"github.com/axelarnetwork/axelar-core/x/ante"
"reflect"
"strings"

Expand Down Expand Up @@ -161,17 +163,21 @@ func initStakingKeeper(appCodec codec.Codec, keys map[string]*sdk.KVStoreKey, ke
return &stakingK
}

func initWasmKeeper(appCodec codec.Codec, keys map[string]*sdk.KVStoreKey, keepers *keeperCache, bApp *bam.BaseApp, wasmDir string, wasmConfig wasmtypes.WasmConfig, wasmOpts []wasm.Option) *wasm.Keeper {
func initWasmKeeper(encodingConfig axelarParams.EncodingConfig, keys map[string]*sdk.KVStoreKey, keepers *keeperCache, bApp *bam.BaseApp, wasmDir string, wasmConfig wasmtypes.WasmConfig, wasmOpts []wasm.Option) *wasm.Keeper {
// The last arguments can contain custom message handlers, and custom query handlers,
// if we want to allow any custom callbacks
wasmOpts = append(wasmOpts, wasmkeeper.WithMessageHandlerDecorator(func(old wasmkeeper.Messenger) wasmkeeper.Messenger {
return wasmkeeper.NewMessageHandlerChain(old, nexusKeeper.NewMessenger(getKeeper[nexusKeeper.Keeper](keepers)))
}))
wasmOpts = append(wasmOpts, wasmkeeper.WithMessageHandlerDecorator(
func(old wasmkeeper.Messenger) wasmkeeper.Messenger {
return withAnteChecks(
wasm.DefaultEncoders(), // todo add custom encoder
initMessageAnteDecorators(encodingConfig, keepers),
wasmkeeper.NewMessageHandlerChain(old, nexusKeeper.NewMessenger(getKeeper[nexusKeeper.Keeper](keepers))))
}))

scopedWasmK := getKeeper[capabilitykeeper.Keeper](keepers).ScopeToModule(wasm.ModuleName)
ibcKeeper := getKeeper[ibckeeper.Keeper](keepers)
wasmK := wasm.NewKeeper(
appCodec,
encodingConfig.Codec,
keys[wasm.StoreKey],
keepers.getSubspace(wasm.ModuleName),
getKeeper[authkeeper.AccountKeeper](keepers),
Expand All @@ -194,6 +200,33 @@ func initWasmKeeper(appCodec codec.Codec, keys map[string]*sdk.KVStoreKey, keepe
return &wasmK
}

type Messenger struct {
anteHandle ante.MessageAnteHandler
encoders wasm.MessageEncoders
messenger wasmkeeper.Messenger
}

func (m Messenger) DispatchMsg(ctx sdk.Context, contractAddr sdk.AccAddress, contractIBCPortID string, msg wasmvmtypes.CosmosMsg) (events []sdk.Event, data [][]byte, err error) {
sdkMsgs, err := m.encoders.Encode(ctx, contractAddr, contractIBCPortID, msg)
if err != nil {
return nil, nil, err
}
ctx, err = m.anteHandle(ctx, sdkMsgs, false) //todo: how do I get the simulate boolean?
if err != nil {
return nil, nil, err
}

return m.messenger.DispatchMsg(ctx, contractAddr, contractIBCPortID, msg)
}

func withAnteChecks(encoders wasmkeeper.MessageEncoders, anteHandler ante.MessageAnteHandler, messenger wasmkeeper.Messenger) wasmkeeper.Messenger {
return Messenger{
encoders: encoders,
anteHandle: anteHandler,
messenger: messenger,
}
}

func initGovernanceKeeper(appCodec codec.Codec, keys map[string]*sdk.KVStoreKey, keepers *keeperCache) *govkeeper.Keeper {
// Add governance proposal hooks
govRouter := govtypes.NewRouter()
Expand Down
33 changes: 33 additions & 0 deletions x/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,36 @@ func (decorator HandlerDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulat

return next(newCtx, tx, simulate)
}

type MessageAnteHandler func(ctx sdk.Context, msgs []sdk.Msg, simulate bool) (sdk.Context, error)
type MessageAnteDecorator interface {
AnteHandle(ctx sdk.Context, msgs []sdk.Msg, simulate bool, next MessageAnteHandler) (sdk.Context, error)
}

func ChainMessageAnteDecorators(chain ...MessageAnteDecorator) MessageAnteHandler {
if len(chain) == 0 {
return nil
}

// handle non-terminated decorators chain
if (chain[len(chain)-1] != Terminator{}) {
chain = append(chain, Terminator{})
}

return func(ctx sdk.Context, msgs []sdk.Msg, simulate bool) (sdk.Context, error) {
return chain[0].AnteHandle(ctx, msgs, simulate, ChainMessageAnteDecorators(chain[1:]...))
}
}

type Terminator struct{}

func (Terminator) AnteHandle(ctx sdk.Context, _ []sdk.Msg, _ bool, _ MessageAnteHandler) (sdk.Context, error) {
return ctx, nil
}

func (m MessageAnteHandler) ToAnteHandler() sdk.AnteHandler {
return func(ctx sdk.Context, tx sdk.Tx, simulate bool) (sdk.Context, error) {
msgs := tx.GetMsgs()
return m(ctx, msgs, simulate)
}
}
6 changes: 2 additions & 4 deletions x/ante/check_commission_rate.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ func NewCheckCommissionRate(staking types.Staking) CheckCommissionRate {
}

// AnteHandle fails the transaction if it finds any validator registering a commission rate that is below the minimum
func (d CheckCommissionRate) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
msgs := tx.GetMsgs()

func (d CheckCommissionRate) AnteHandle(ctx sdk.Context, msgs []sdk.Msg, simulate bool, next MessageAnteHandler) (sdk.Context, error) {
for _, msg := range msgs {
switch msg := msg.(type) {
case *stakingtypes.MsgCreateValidator:
Expand Down Expand Up @@ -58,5 +56,5 @@ func (d CheckCommissionRate) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate boo
}
}

return next(ctx, tx, simulate)
return next(ctx, msgs, simulate)
}
39 changes: 13 additions & 26 deletions x/ante/check_commission_rate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,21 @@ import (
func TestCheckCommissionRate(t *testing.T) {
var (
handler ante.CheckCommissionRate
tx *mock.TxMock
msg sdk.Msg
staking *mock.StakingMock
)

valAddr := rand.ValAddr().String()

letTxThrough := func(t *testing.T) {
tx = &mock.TxMock{
GetMsgsFunc: func() []sdk.Msg {
return []sdk.Msg{msg}
},
}

_, err := handler.AnteHandle(sdk.Context{}, tx, false,
func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { return sdk.Context{}, nil })
letMsgsThrough := func(t *testing.T) {
_, err := handler.AnteHandle(sdk.Context{}, []sdk.Msg{msg}, false,
func(sdk.Context, []sdk.Msg, bool) (sdk.Context, error) { return sdk.Context{}, nil })
assert.NoError(t, err)
}

stopTx := func(t *testing.T) {
tx = &mock.TxMock{
GetMsgsFunc: func() []sdk.Msg {
return []sdk.Msg{msg}
},
}

_, err := handler.AnteHandle(sdk.Context{}, tx, false,
func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { return sdk.Context{}, nil })
stopMsgs := func(t *testing.T) {
_, err := handler.AnteHandle(sdk.Context{}, []sdk.Msg{msg}, false,
func(sdk.Context, []sdk.Msg, bool) (sdk.Context, error) { return sdk.Context{}, nil })
assert.Error(t, err)
}

Expand Down Expand Up @@ -85,22 +72,22 @@ func TestCheckCommissionRate(t *testing.T) {

givenCheckCommissionRateAnteHandler.
When("a tx with MsgCreateValidator with commission rate below minimum is received", createValidator(sdk.NewDecWithPrec(49, 3), sdk.NewDecWithPrec(51, 3))).
Then("should return an error", stopTx).
Then("should return an error", stopMsgs).
Run(t)

givenCheckCommissionRateAnteHandler.
When("a tx with MsgCreateValidator with max commission rate below minimum is received", createValidator(sdk.NewDecWithPrec(51, 3), sdk.NewDecWithPrec(49, 3))).
Then("should return an error", stopTx).
Then("should return an error", stopMsgs).
Run(t)

givenCheckCommissionRateAnteHandler.
When("a tx with MsgEditValidator with commission rate below minimum is received", editValidator(sdk.NewDecWithPrec(50, 3), sdk.NewDecWithPrec(49, 3))).
Then("should return an error", stopTx).
Then("should return an error", stopMsgs).
Run(t)

givenCheckCommissionRateAnteHandler.
When("a tx with MsgEditValidator for validator with existing commission rate below minimum being increased is received", editValidator(sdk.NewDecWithPrec(39, 3), sdk.NewDecWithPrec(49, 3))).
Then("should go through", letTxThrough).
Then("should go through", letMsgsThrough).
Run(t)

givenCheckCommissionRateAnteHandler.
Expand All @@ -111,16 +98,16 @@ func TestCheckCommissionRate(t *testing.T) {
}
setValidatorCommission(sdk.NewDecWithPrec(49, 3))
}).
Then("should go through", letTxThrough).
Then("should go through", letMsgsThrough).
Run(t)

givenCheckCommissionRateAnteHandler.
When("a tx with eligible MsgCreateValidator is received", createValidator(sdk.NewDecWithPrec(50, 3), sdk.NewDecWithPrec(51, 3))).
Then("should go through", letTxThrough).
Then("should go through", letMsgsThrough).
Run(t)

givenCheckCommissionRateAnteHandler.
When("a tx with eligible MsgEditValidator is received", editValidator(sdk.NewDecWithPrec(50, 3), sdk.NewDecWithPrec(51, 3))).
Then("should go through", letTxThrough).
Then("should go through", letMsgsThrough).
Run(t)
}
7 changes: 3 additions & 4 deletions x/ante/check_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ func NewCheckProxy(snapshotter types.Snapshotter) CheckProxy {
}

// AnteHandle fails the transaction if it finds any validator holding multiSig share of active keys is trying to unbond
func (d CheckProxy) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
func (d CheckProxy) AnteHandle(ctx sdk.Context, msgs []sdk.Msg, simulate bool, next MessageAnteHandler) (sdk.Context, error) {
// exempt genesis validator(s) from this check
if ctx.BlockHeight() == 0 {
return next(ctx, tx, simulate)
return next(ctx, msgs, simulate)
}

msgs := tx.GetMsgs()
for _, msg := range msgs {
switch msg := msg.(type) {
case *stakingtypes.MsgCreateValidator:
Expand All @@ -43,5 +42,5 @@ func (d CheckProxy) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next s
}
}

return next(ctx, tx, simulate)
return next(ctx, msgs, simulate)
}
8 changes: 3 additions & 5 deletions x/ante/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ func NewLogMsgDecorator(cdc codec.Codec) LogMsgDecorator {
}

// AnteHandle logs all messages in blocks
func (d LogMsgDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
func (d LogMsgDecorator) AnteHandle(ctx sdk.Context, msgs []sdk.Msg, simulate bool, next MessageAnteHandler) (sdk.Context, error) {
if simulate || ctx.IsCheckTx() {
return next(ctx, tx, simulate)
return next(ctx, msgs, simulate)
}

msgs := tx.GetMsgs()

for _, msg := range msgs {
logger(ctx).Debug(fmt.Sprintf("received message of type %s in block %d: %s",
proto.MessageName(msg),
Expand All @@ -33,5 +31,5 @@ func (d LogMsgDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, n
))
}

return next(ctx, tx, simulate)
return next(ctx, msgs, simulate)
}
5 changes: 2 additions & 3 deletions x/ante/restricted_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ func NewRestrictedTx(permission types.Permission) RestrictedTx {
}

// AnteHandle fails if the signer is not authorized to send the transaction
func (d RestrictedTx) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
msgs := tx.GetMsgs()
func (d RestrictedTx) AnteHandle(ctx sdk.Context, msgs []sdk.Msg, simulate bool, next MessageAnteHandler) (sdk.Context, error) {
for _, msg := range msgs {
signer := msg.GetSigners()[0]
signerRole := d.permission.GetRole(ctx, signer)
Expand All @@ -42,5 +41,5 @@ func (d RestrictedTx) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next
}
}

return next(ctx, tx, simulate)
return next(ctx, msgs, simulate)
}
Loading

0 comments on commit b6c05ef

Please sign in to comment.