Skip to content

Commit

Permalink
fix bug of wasm pgu (#3097)
Browse files Browse the repository at this point in the history
* fix bug

* fix ut

* update

* add recover when simulate wasm with watchdb

---------

Co-authored-by: KamiD <[email protected]>
  • Loading branch information
yann-sjtu and KamiD authored Apr 12, 2023
1 parent 9fb2deb commit 48271e7
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 42 deletions.
61 changes: 40 additions & 21 deletions libs/cosmos-sdk/baseapp/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -445,51 +445,70 @@ func handleSimulate(app *BaseApp, path []string, height int64, txBytes []byte, o
}
}
if isPureWasm {
wasmSimulator := simulator.NewWasmSimulator()
defer wasmSimulator.Release()
return handleSimulateWasm(height, txBytes, msgs)
}
}
gInfo, res, err := app.Simulate(txBytes, tx, height, overrideBytes, from)

wasmSimulator.Context().GasMeter().ConsumeGas(73000, "general ante check cost")
wasmSimulator.Context().GasMeter().ConsumeGas(uint64(10*len(txBytes)), "tx size cost")
res, err := wasmSimulator.Simulate(msgs)
if err != nil {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate wasm tx"))
}
// if path contains mempool, it means to enable MaxGasUsedPerBlock
// return the actual gasUsed even though simulate tx failed
isMempoolSim := hasExtraPaths && path[2] == "mempool"
if err != nil && !isMempoolSim {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx"))
}

simRes := sdk.SimulationResponse{
GasInfo: gInfo,
Result: res,
}

return abci.ResponseQuery{
Codespace: sdkerrors.RootCodespace,
Height: height,
Value: codec.Cdc.MustMarshalBinaryBare(simRes),
}
}

func handleSimulateWasm(height int64, txBytes []byte, msgs []sdk.Msg) (abciRes abci.ResponseQuery) {
wasmSimulator := simulator.NewWasmSimulator()
defer wasmSimulator.Release()
defer func() {
if r := recover(); r != nil {
gasMeter := wasmSimulator.Context().GasMeter()
simRes := sdk.SimulationResponse{
GasInfo: sdk.GasInfo{
GasUsed: gasMeter.GasConsumed(),
},
Result: res,
}
return abci.ResponseQuery{
abciRes = abci.ResponseQuery{
Codespace: sdkerrors.RootCodespace,
Height: height,
Value: codec.Cdc.MustMarshalBinaryBare(simRes),
}
}
}()

}
gInfo, res, err := app.Simulate(txBytes, tx, height, overrideBytes, from)

// if path contains mempool, it means to enable MaxGasUsedPerBlock
// return the actual gasUsed even though simulate tx failed
isMempoolSim := hasExtraPaths && path[2] == "mempool"
if err != nil && !isMempoolSim {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate tx"))
wasmSimulator.Context().GasMeter().ConsumeGas(73000, "general ante check cost")
wasmSimulator.Context().GasMeter().ConsumeGas(uint64(10*len(txBytes)), "tx size cost")
res, err := wasmSimulator.Simulate(msgs)
if err != nil {
return sdkerrors.QueryResult(sdkerrors.Wrap(err, "failed to simulate wasm tx"))
}

gasMeter := wasmSimulator.Context().GasMeter()
simRes := sdk.SimulationResponse{
GasInfo: gInfo,
Result: res,
GasInfo: sdk.GasInfo{
GasUsed: gasMeter.GasConsumed(),
},
Result: res,
}

return abci.ResponseQuery{
Codespace: sdkerrors.RootCodespace,
Height: height,
Value: codec.Cdc.MustMarshalBinaryBare(simRes),
}
}

func handleQueryApp(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
if len(path) >= 2 {
switch path[1] {
Expand Down
36 changes: 15 additions & 21 deletions libs/tendermint/mempool/clist_mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,16 +344,8 @@ func (mem *CListMempool) CheckTx(tx types.Tx, cb func(*abci.Response), txInfo Tx
defer mem.updateMtx.RUnlock()

var err error
var gasUsed int64
if cfg.DynamicConfig.GetMaxGasUsedPerBlock() > -1 {
gasUsed = mem.txInfoparser.GetTxHistoryGasUsed(tx)
if gasUsed < 0 {
simuRes, err := mem.simulateTx(tx)
if err != nil {
return err
}
gasUsed = int64(simuRes.GasUsed)
}
txInfo.gasUsed = mem.txInfoparser.GetTxHistoryGasUsed(tx)
}

if mem.preCheck != nil {
Expand All @@ -371,16 +363,16 @@ func (mem *CListMempool) CheckTx(tx types.Tx, cb func(*abci.Response), txInfo Tx
types.SignatureCache().Add(txkey[:], txInfo.from)
}
reqRes := mem.proxyAppConn.CheckTxAsync(abci.RequestCheckTx{Tx: tx, Type: txInfo.checkType, From: txInfo.wtx.GetFrom(), Nonce: nonce})
if cfg.DynamicConfig.GetMaxGasUsedPerBlock() > -1 {
if r, ok := reqRes.Response.Value.(*abci.Response_CheckTx); ok {
if r, ok := reqRes.Response.Value.(*abci.Response_CheckTx); ok {
if txInfo.gasUsed <= 0 || txInfo.gasUsed > r.CheckTx.GasWanted {
txInfo.gasUsed = r.CheckTx.GasWanted
}
if cfg.DynamicConfig.GetMaxGasUsedPerBlock() > -1 {
mem.logger.Info(fmt.Sprintf("mempool.SimulateTx: txhash<%s>, gasLimit<%d>, gasUsed<%d>",
hex.EncodeToString(tx.Hash(mem.Height())), r.CheckTx.GasWanted, gasUsed))
if gasUsed < r.CheckTx.GasWanted {
r.CheckTx.GasWanted = gasUsed
}

hex.EncodeToString(tx.Hash(mem.Height())), r.CheckTx.GasWanted, txInfo.gasUsed))
}
}

reqRes.SetCallback(mem.reqResCb(tx, txInfo, cb))
atomic.AddInt64(&mem.checkCnt, 1)

Expand Down Expand Up @@ -702,7 +694,8 @@ func (mem *CListMempool) resCbFirstTime(

memTx := &mempoolTx{
height: mem.Height(),
gasWanted: r.CheckTx.GasWanted,
gasLimit: r.CheckTx.GasWanted,
gasWanted: txInfo.gasUsed,
tx: tx,
realTx: r.CheckTx.Tx,
nodeKey: txInfo.wtx.GetNodeKey(),
Expand Down Expand Up @@ -1245,8 +1238,9 @@ func MultiPriceBump(rawPrice *big.Int, priceBump int64) *big.Int {

// mempoolTx is a transaction that successfully ran
type mempoolTx struct {
height int64 // height that this tx had been validated in
gasWanted int64 // amount of gas this tx states it will require
height int64 // height that this tx had been validated in
gasWanted int64 // amount of gas this tx states it will require
gasLimit int64
tx types.Tx //
realTx abci.TxEssentials
nodeKey []byte
Expand Down Expand Up @@ -1447,10 +1441,10 @@ func (mem *CListMempool) simulationJob(memTx *mempoolTx) {
return
}
gas := int64(simuRes.GasUsed) * int64(cfg.DynamicConfig.GetPGUAdjustment()*100) / 100
atomic.StoreInt64(&memTx.gasWanted, gas)
if gas < atomic.LoadInt64(&memTx.gasWanted) {
if gas < atomic.LoadInt64(&memTx.gasLimit) {
atomic.StoreInt64(&memTx.gasWanted, gas)
}
atomic.AddUint32(&memTx.isSim, 1)
mem.gasCache.Add(hex.EncodeToString(memTx.realTx.TxHash()), gas)
}

Expand Down
2 changes: 2 additions & 0 deletions libs/tendermint/mempool/mempool.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ type TxInfo struct {
wtx *WrappedTx
checkType abci.CheckTxType

gasUsed int64

wrapCMTx *types.WrapCMTx
}

Expand Down

0 comments on commit 48271e7

Please sign in to comment.