github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/keeper/ante.go (about)

     1  package keeper
     2  
     3  import (
     4  	"encoding/binary"
     5  
     6  	types2 "github.com/fibonacci-chain/fbc/libs/tendermint/types"
     7  
     8  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     9  
    10  	"github.com/fibonacci-chain/fbc/x/wasm/types"
    11  )
    12  
    13  type HandlerOption struct {
    14  	WasmConfig        *types.WasmConfig
    15  	TXCounterStoreKey sdk.StoreKey
    16  }
    17  
    18  // CountTXDecorator ante handler to count the tx position in a block.
    19  type CountTXDecorator struct {
    20  	storeKey sdk.StoreKey
    21  }
    22  
    23  // NewCountTXDecorator constructor
    24  func NewCountTXDecorator(storeKey sdk.StoreKey) *CountTXDecorator {
    25  	return &CountTXDecorator{storeKey: storeKey}
    26  }
    27  
    28  // AnteHandle handler stores a tx counter with current height encoded in the store to let the app handle
    29  // global rollback behavior instead of keeping state in the handler itself.
    30  // The ante handler passes the counter value via sdk.Context upstream. See `types.TXCounter(ctx)` to read the value.
    31  // Simulations don't get a tx counter value assigned.
    32  func (a CountTXDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
    33  	if simulate || !types2.HigherThanEarth(ctx.BlockHeight()) {
    34  		return next(ctx, tx, simulate)
    35  	}
    36  	currentGasmeter := ctx.GasMeter()
    37  	ctx.SetGasMeter(sdk.NewInfiniteGasMeter())
    38  	store := ctx.KVStore(a.storeKey)
    39  	currentHeight := ctx.BlockHeight()
    40  
    41  	var txCounter uint32 // start with 0
    42  	// load counter when exists
    43  	if bz := store.Get(types.TXCounterPrefix); bz != nil {
    44  		lastHeight, val := decodeHeightCounter(bz)
    45  		if currentHeight == lastHeight {
    46  			// then use stored counter
    47  			txCounter = val
    48  		} // else use `0` from above to start with
    49  	}
    50  	// store next counter value for current height
    51  	store.Set(types.TXCounterPrefix, encodeHeightCounter(currentHeight, txCounter+1))
    52  
    53  	ctx.SetGasMeter(currentGasmeter)
    54  	return next(types.WithTXCounter(ctx, txCounter), tx, simulate)
    55  }
    56  
    57  func encodeHeightCounter(height int64, counter uint32) []byte {
    58  	b := make([]byte, 4)
    59  	binary.BigEndian.PutUint32(b, counter)
    60  	return append(sdk.Uint64ToBigEndian(uint64(height)), b...)
    61  }
    62  
    63  func decodeHeightCounter(bz []byte) (int64, uint32) {
    64  	return int64(sdk.BigEndianToUint64(bz[0:8])), binary.BigEndian.Uint32(bz[8:])
    65  }
    66  
    67  // LimitSimulationGasDecorator ante decorator to limit gas in simulation calls
    68  type LimitSimulationGasDecorator struct {
    69  	gasLimit *sdk.Gas
    70  }
    71  
    72  // NewLimitSimulationGasDecorator constructor accepts nil value to fallback to block gas limit.
    73  func NewLimitSimulationGasDecorator(gasLimit *sdk.Gas) *LimitSimulationGasDecorator {
    74  	if gasLimit != nil && *gasLimit == 0 {
    75  		panic("gas limit must not be zero")
    76  	}
    77  	return &LimitSimulationGasDecorator{gasLimit: gasLimit}
    78  }
    79  
    80  // AnteHandle that limits the maximum gas available in simulations only.
    81  // A custom max value can be configured and will be applied when set. The value should not
    82  // exceed the max block gas limit.
    83  // Different values on nodes are not consensus breaking as they affect only
    84  // simulations but may have effect on client user experience.
    85  //
    86  // When no custom value is set then the max block gas is used as default limit.
    87  func (d LimitSimulationGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
    88  	if !simulate {
    89  		// Wasm code is not executed in checkTX so that we don't need to limit it further.
    90  		// Tendermint rejects the TX afterwards when the tx.gas > max block gas.
    91  		// On deliverTX we rely on the tendermint/sdk mechanics that ensure
    92  		// tx has gas set and gas < max block gas
    93  		return next(ctx, tx, simulate)
    94  	}
    95  
    96  	// apply custom node gas limit
    97  	if d.gasLimit != nil {
    98  		newCtx := ctx.SetGasMeter(sdk.NewGasMeter(*d.gasLimit))
    99  		return next(*newCtx, tx, simulate)
   100  	}
   101  
   102  	// default to max block gas when set, to be on the safe side
   103  	if maxGas := ctx.ConsensusParams().GetBlock().MaxGas; maxGas > 0 {
   104  		newCtx := ctx.SetGasMeter(sdk.NewGasMeter(sdk.Gas(maxGas)))
   105  		return next(*newCtx, tx, simulate)
   106  	}
   107  	return next(ctx, tx, simulate)
   108  }