Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions utils/proxygasmeter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// https://github.com/MANTRA-Chain/mantrachain/pull/438

package utils

import (
"fmt"

storetypes "cosmossdk.io/store/types"
)

var _ storetypes.GasMeter = &ProxyGasMeter{}

// ProxyGasMeter wraps another GasMeter, but enforces a lower gas limit.
// Gas consumption is delegated to the wrapped GasMeter, so it won't risk losing gas accounting compared to standalone
// gas meter.
type ProxyGasMeter struct {
storetypes.GasMeter
limit storetypes.Gas
}

// NewProxyGasMeter returns a new ProxyGasMeter which wraps the provided gas meter.
// The limit is the maximum gas that can be consumed on top of consumed gas of the wrapped gas meter.
//
// If limit is greater than or equal to the remaining gas, no wrapping is needed and the original gas meter is returned.
func NewProxyGasMeter(gasMeter storetypes.GasMeter, limit storetypes.Gas) storetypes.GasMeter {
if limit >= gasMeter.GasRemaining() {
return gasMeter
}

return &ProxyGasMeter{
GasMeter: gasMeter,
limit: limit + gasMeter.GasConsumed(),
}
}

func (pgm ProxyGasMeter) GasRemaining() storetypes.Gas {
if pgm.IsPastLimit() {
return 0
}
return pgm.limit - pgm.GasConsumed()
}

func (pgm ProxyGasMeter) Limit() storetypes.Gas {
return pgm.limit
}

func (pgm ProxyGasMeter) IsPastLimit() bool {
return pgm.GasConsumed() > pgm.limit
}

func (pgm ProxyGasMeter) IsOutOfGas() bool {
return pgm.GasConsumed() >= pgm.limit
}

func (pgm ProxyGasMeter) ConsumeGas(amount storetypes.Gas, descriptor string) {
pgm.GasMeter.ConsumeGas(amount, descriptor)

if pgm.GasConsumed() > pgm.limit {
panic(storetypes.ErrorOutOfGas{Descriptor: descriptor})
}
}

func (pgm ProxyGasMeter) String() string {
return fmt.Sprintf("ProxyGasMeter{consumed: %d, limit: %d}", pgm.GasConsumed(), pgm.limit)
}
47 changes: 47 additions & 0 deletions utils/proxygasmeter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package utils

import (
"testing"

storetypes "cosmossdk.io/store/types"
"github.com/stretchr/testify/require"
)

func TestProxyGasMeter(t *testing.T) {
baseGas := uint64(1000)
limit := uint64(300)

bgm := storetypes.NewGasMeter(baseGas)
pgm := NewProxyGasMeter(bgm, limit)

require.Equal(t, storetypes.Gas(0), pgm.GasConsumed())
require.Equal(t, limit, pgm.Limit())
require.Equal(t, limit, pgm.GasRemaining())

pgm.ConsumeGas(100, "test")
require.Equal(t, storetypes.Gas(100), pgm.GasConsumed())
require.Equal(t, storetypes.Gas(100), bgm.GasConsumed())
require.Equal(t, limit-100, pgm.GasRemaining())
require.False(t, pgm.IsOutOfGas())
require.False(t, pgm.IsPastLimit())

pgm.ConsumeGas(200, "test")
require.Equal(t, storetypes.Gas(300), pgm.GasConsumed())
require.Equal(t, storetypes.Gas(300), bgm.GasConsumed())
require.Equal(t, storetypes.Gas(0), pgm.GasRemaining())
require.Equal(t, storetypes.Gas(700), bgm.GasRemaining())
require.True(t, pgm.IsOutOfGas())
require.False(t, pgm.IsPastLimit())

require.Panics(t, func() {
pgm.ConsumeGas(1, "test")
})
require.Equal(t, storetypes.Gas(699), bgm.GasRemaining())

pgm.RefundGas(2, "test")
require.Equal(t, storetypes.Gas(701), bgm.GasRemaining())
require.Equal(t, storetypes.Gas(299), pgm.GasConsumed())
require.Equal(t, storetypes.Gas(1), pgm.GasRemaining())
require.False(t, pgm.IsOutOfGas())
require.False(t, pgm.IsPastLimit())
}
4 changes: 2 additions & 2 deletions x/tokenfactory/keeper/before_send.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"context"
"encoding/json"

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

"github.com/neutron-org/neutron/v8/utils"
"github.com/neutron-org/neutron/v8/x/tokenfactory/types"

errorsmod "cosmossdk.io/errors"
Expand Down Expand Up @@ -170,7 +170,7 @@ func (k Keeper) callBeforeSendListener(ctx context.Context, from, to sdk.AccAddr
return errorsmod.Wrapf(err, "failed to call before send hook for denom %s", coin.Denom)
}
} else {
childCtx := c.WithGasMeter(types2.NewGasMeter(types.TrackBeforeSendGasLimit))
childCtx := c.WithGasMeter(utils.NewProxyGasMeter(c.GasMeter(), 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)
Expand Down
Loading