Open jonathanpberger opened 2 weeks ago
@pharr117 see if @Reecepbcups has any thoughts on wasmd
I chatted with @jtieri very briefly about this in Pittsburgh. I think they can get off a wasmd fork & move the logic to the ante based on what I heard. Happy to have a call on this to review, I am pretty open this week.
Also I recommend wasmvm 1.5.x and not 2 (too new, had issues with tokenfactory, not worth the risk imo)
According to the devs, they forked to allow restriction of arbitrary code deployments. All contracts are gated by wormhole VAAs with some features added to their fork:
Fork commits that diff from the upstream, showing their changes: https://github.com/CosmWasm/wasmd/compare/main...wormhole-foundation:wasmd:wormhole-chain-v0.30.0
@pharr117 Thanks for sharing - high level looking at this, this fork can be removed without issue.
How this would look:
HasWasmInstantiateAllowlistFn
for any/select wasmd messages (init, store, etc). This will take reference to just the Wormhole & Wasmd keepersThis entirely removes the fork and makes your life easier :)
The SDK fork is still required, looks like they did something with the staking keeper for a sudo PoA, pretty simple.
Just put this together, not tested. Showcases the flow & gets off the fork.
package ante
import (
"github.com/CosmWasm/wasmd/x/wasm"
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/wormhole-foundation/wormchain/x/wormhole/keeper"
)
// Reject all wasmd message unless authorized
type WormholeWasmdGuard struct {
k keeper.Keeper
wasmdKeeper wasmkeeper.Keeper
}
func NewWormholeWasmdGuard(k keeper.Keeper, wasmd wasmkeeper.Keeper) WormholeWasmdGuard {
return WormholeWasmdGuard{
k: k,
wasmdKeeper: wasmd,
}
}
func (wh WormholeWasmdGuard) AnteHandle(request sdk.Request, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Request, err error) {
if request.IsReCheckTx() {
return next(request, tx, simulate)
}
if request.BlockHeight() < 1 {
// Don't reject gen_tx transactions
return next(request, tx, simulate)
}
for _, msg := range tx.GetMsgs() {
// from upstream fork: x/wasm/keeper/msg_server.go
if wasmInit, ok := msg.(*wasm.MsgInstantiateContract); ok {
if !wh.k.HasWasmInstantiateAllowlist(request, wasmInit.Sender, wasmInit.CodeID) {
return request, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "must use x/wormhole")
} else { continue }
}
if wasmInit, ok := msg.(*wasm.MsgInstantiateContract2); ok {
if !wh.k.HasWasmInstantiateAllowlist(request, wasmInit.Sender, wasmInit.CodeID) {
return request, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "must use x/wormhole")
} else { continue }
}
// TODO: There may be others. may want to have a "wasm." message prefix check here instead to always
// TODO: block EVERY wasmd message which is not one of the above
if _, ok := msg.(*wasm.MsgStoreCode); ok {
return request, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "must use x/wormhole")
}
if _, ok := msg.(*wasm.MsgMigrateContract); ok {
return request, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "must use x/wormhole")
}
if _, ok := msg.(*wasm.MsgUpdateAdmin); ok {
return request, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "must use x/wormhole")
}
if _, ok := msg.(*wasm.MsgClearAdmin); ok {
return request, sdkerrors.Wrapf(sdkerrors.ErrNotSupported, "must use x/wormhole")
}
}
// By this point, there is no signer that is not allowlisted or is a validator.
// Not authorized!
return request, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "signer must be current validator or allowlisted by current validator")
}