Bug: STMRunner passes nil transaction bytes to deliverTx when estimate is false
### Summary
In `blockstm/txnrunner.go`, `STMRunner.Run` fails to pass the raw transaction bytes to `deliverTx` when the `estimate` flag is `false`. This results in `deliverTx` being called with `nil` tx bytes, which will result in the transaction not executing in `BaseApp.RunTx`.
### Affected Code
https://github.com/cosmos/cosmos-sdk/blob/main/blockstm/txnrunner.go#L66-L96
```
var (
estimates []MultiLocations
memTxs [][]byte
)
if e.estimate {
memTxs, estimates = preEstimates(txs, e.workers, authStore, bankStore, e.coinDenom(ms), e.txDecoder)
}
// ...inside ExecuteBlockWithEstimates callback:
var memTx []byte
if memTxs != nil {
memTx = memTxs[txn]
}
results[txn] = deliverTx(memTx, msWrapper{ms}, int(txn), cache)
```
When `estimate` is `false`:
1. `memTxs` remains its zero value (`nil`)
2. `if memTxs != nil` check is `false`, so `memTx` stays `nil`
3. `deliverTx(nil, ...)` is called — the original `txs[txn]` bytes are never passed
### Comparison with DefaultRunner
`DefaultRunner` correctly passes the raw transaction bytes:
https://github.com/cosmos/cosmos-sdk/blob/main/baseapp/txnrunner/default.go#L34
```
response = deliverTx(rawTx, nil, i, nil)
```
### Suggested Fix
Fall back to the original `txs[txn]` when `memTxs` is nil or when the entry is nil:
```
var memTx []byte
if memTxs != nil && memTxs[txn] != nil {
memTx = memTxs[txn]
} else {
memTx = txs[txn]
}
```
This ensures raw transaction bytes are always passed to `deliverTx`, consistent with `DefaultRunner` behavior. It also handles the edge case where `preEstimates` skips a malformed transaction.
2 条评论