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 }