Skip to content

Commit

Permalink
reuse VerifyStorageValue in ICQ and state_verifier
Browse files Browse the repository at this point in the history
  • Loading branch information
pr0n00gler committed Nov 28, 2024
1 parent c74f625 commit 0475289
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 23 deletions.
54 changes: 33 additions & 21 deletions x/tokenfactory/keeper/before_send.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package keeper
import (
"context"
"encoding/json"
"strings"

types2 "cosmossdk.io/store/types"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/neutron-org/neutron/v5/x/tokenfactory/types"
Expand Down Expand Up @@ -103,8 +104,8 @@ func (h Hooks) BlockBeforeSend(ctx context.Context, from, to sdk.AccAddress, amo
// If blockBeforeSend is true, sudoMsg wraps BlockBeforeSendMsg, otherwise sudoMsg wraps TrackBeforeSendMsg.
// Note that we gas meter trackBeforeSend to prevent infinite contract calls.
// CONTRACT: this should not be called in beginBlock or endBlock since out of gas will cause this method to panic.
func (k Keeper) callBeforeSendListener(ctx context.Context, from, to sdk.AccAddress, amount sdk.Coins, blockBeforeSend bool) (err error) {
c := sdk.UnwrapSDKContext(ctx)
func (k Keeper) callBeforeSendListener(goCtx context.Context, from, to sdk.AccAddress, amount sdk.Coins, blockBeforeSend bool) (err error) {
ctx := sdk.UnwrapSDKContext(goCtx)

defer func() {
if r := recover(); r != nil {
Expand All @@ -113,7 +114,7 @@ func (k Keeper) callBeforeSendListener(ctx context.Context, from, to sdk.AccAddr
}()

for _, coin := range amount {
contractAddr := k.GetBeforeSendHook(ctx, coin.Denom)
contractAddr := k.GetBeforeSendHook(goCtx, coin.Denom)
if contractAddr != "" {
cwAddr, err := sdk.AccAddressFromBech32(contractAddr)
if err != nil {
Expand All @@ -124,8 +125,8 @@ func (k Keeper) callBeforeSendListener(ctx context.Context, from, to sdk.AccAddr
// NOTE: hooks must already be whitelisted before they can be added, so under normal operation this check should never fail.
// It is here as an emergency override if we want to shutoff a hook. We do not return the error because once it is removed from the whitelist
// a hook should not be able to block a send.
if err := k.AssertIsHookWhitelisted(c, coin.Denom, cwAddr); err != nil {
c.Logger().Error(
if err := k.AssertIsHookWhitelisted(ctx, coin.Denom, cwAddr); err != nil {
ctx.Logger().Error(
"Skipped hook execution due to missing whitelist",
"err", err,
"denom", coin.Denom,
Expand All @@ -137,9 +138,6 @@ func (k Keeper) callBeforeSendListener(ctx context.Context, from, to sdk.AccAddr
var msgBz []byte

// get msgBz, either BlockBeforeSend or TrackBeforeSend
// Note that for trackBeforeSend, we need to gas meter computations to prevent infinite loop
// specifically because module to module sends are not gas metered.
// We don't need to do this for blockBeforeSend since blockBeforeSend is not called during module to module sends.
if blockBeforeSend {
msg := types.BlockBeforeSendSudoMsg{
BlockBeforeSend: types.BlockBeforeSendMsg{
Expand All @@ -163,22 +161,36 @@ func (k Keeper) callBeforeSendListener(ctx context.Context, from, to sdk.AccAddr
return err
}

// if its track before send, apply gas meter to prevent infinite loop
if blockBeforeSend {
_, err = k.contractKeeper.Sudo(c, cwAddr, msgBz)
if err != nil {
return errorsmod.Wrapf(err, "failed to call before send hook for denom %s", coin.Denom)
em := sdk.NewEventManager()

childCtx := ctx.WithGasMeter(storetypes.NewGasMeter(types.SudoHookGasLimit))
_, err = k.contractKeeper.Sudo(childCtx.WithEventManager(em), cwAddr, msgBz)
if err != nil {
k.Logger(ctx).Debug("TokenFactory hooks: failed to sudo",
"error", err, "contract_address", cwAddr)

ctx.EventManager().EmitEvent(sdk.NewEvent(types.EventFailedSudoCall,
[]sdk.Attribute{sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeBeforeSendHookAddress, cwAddr.String()),
sdk.NewAttribute(types.AttributeSudoErrorText, err.Error()),
}...))

// don't block or prevent transfer if there is no contract for some reason
// It's not quite possible, but it's good to have such check just in case
if strings.Contains(err.Error(), "no such contract") {
return nil
}
} else {
childCtx := c.WithGasMeter(types2.NewGasMeter(types.TrackBeforeSendGasLimit))
_, err = k.contractKeeper.Sudo(childCtx, cwAddr, msgBz)
if err != nil {
return errorsmod.Wrapf(err, "failed to call before send hook for denom %s", coin.Denom)

// TF hooks should not block or prevent transfers from module accounts
if k.isModuleAccount(ctx, from) {
return nil
}

// consume gas used for calling contract to the parent ctx
c.GasMeter().ConsumeGas(childCtx.GasMeter().GasConsumed(), "track before send gas")
return errorsmod.Wrapf(err, "failed to call send hook for denom %s", coin.Denom)
}

// consume gas used for calling contract to the parent ctx
ctx.GasMeter().ConsumeGas(childCtx.GasMeter().GasConsumed(), "track before send gas")
}
}
return nil
Expand Down
4 changes: 2 additions & 2 deletions x/tokenfactory/types/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ package types

const ConsensusVersion = 2

// TrackBeforeSendGasLimit value is increased to allow existing approved tokenfactory hooks to work properly.
// SudoHookGasLimit value is increased to allow existing approved tokenfactory hooks to work properly.
// In the next coordinated upgrade, this will become a chain parameter.
var TrackBeforeSendGasLimit = uint64(500_000)
var SudoHookGasLimit = uint64(500_000)
2 changes: 2 additions & 0 deletions x/tokenfactory/types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ const (
AttributeNewAdmin = "new_admin"
AttributeDenomMetadata = "denom_metadata"
AttributeBeforeSendHookAddress = "before_send_hook_address"
AttributeSudoErrorText = "sudo_error_text"
EventFailedSudoCall = "failed_sudo_call"
)

0 comments on commit 0475289

Please sign in to comment.