diff --git a/CHANGELOG.md b/CHANGELOG.md index dc6582729..671a86194 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Mempool discards any transaction with repeated nullifier [#1388] ### Changed +- Extraction from mempool consider Gas expenditure estimation [#1421] - Add GasLimit to the Block's header [#1416] - Reduce wire messages needed for propagating an Agreement vote - Improve fallback procedure to revert multiple ephemeral blocks [#1343] @@ -30,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Default configuration values loading [#1419] +[#1421]: (https://github.com/dusk-network/dusk-blockchain/issues/1421) [#1419]: (https://github.com/dusk-network/dusk-blockchain/issues/1419) [#1418]: (https://github.com/dusk-network/dusk-blockchain/issues/1418) [#1416]: (https://github.com/dusk-network/dusk-blockchain/issues/1416) diff --git a/pkg/core/data/ipc/transactions/payload_decoded.go b/pkg/core/data/ipc/transactions/payload_decoded.go index 715002db7..78331255a 100644 --- a/pkg/core/data/ipc/transactions/payload_decoded.go +++ b/pkg/core/data/ipc/transactions/payload_decoded.go @@ -193,3 +193,17 @@ func UnmarshalTransactionPayloadDecoded(r *bytes.Buffer, f *TransactionPayloadDe return nil } + +// EstimatedGasSpent return the estimated amount of Gas that a transaction will +// spend. For now it uses `t.Call` to determine if it's a normal transfer or it +// is an intercontract call. +// TODO: further improvement should take care of the contractAddress to compare +// it against historical data. +func (p *TransactionPayloadDecoded) EstimatedGasSpent() uint64 { + if p.Call == nil { + // This is a normal transfer transaction + return 300_000_000 + } + // This is an inter-contract call + return 1_200_000_000 +} diff --git a/pkg/core/mempool/mempool.go b/pkg/core/mempool/mempool.go index 81ef77a55..6739cf9ba 100644 --- a/pkg/core/mempool/mempool.go +++ b/pkg/core/mempool/mempool.go @@ -436,6 +436,7 @@ func (m Mempool) processGetMempoolTxsRequest(r rpcbus.Request) (interface{}, err // processGetMempoolTxsBySizeRequest returns a subset of verified mempool txs which // 1. contains only highest fee txs // 2. has total txs size not bigger than maxTxsSize (request param) +// 3. has total txs EstimatedGasSpent not bigger than BlockGasLimit+10% // Called by BlockGenerator on generating a new candidate block. func (m Mempool) processGetMempoolTxsBySizeRequest(r rpcbus.Request) (interface{}, error) { // Read maxTxsSize param @@ -447,19 +448,41 @@ func (m Mempool) processGetMempoolTxsBySizeRequest(r rpcbus.Request) (interface{ } txs := make([]transactions.ContractCall, 0) + gasLimit := config.Get().State.BlockGasLimit + // The slippageGasLimit is the threshold that consider the "estimated gas + // spent" acceptable even if it exceeds the strict GasLimit. This is + // required to avoid to iterate the whole meempol until it fit perfectly + // the block GasLimit + slippageGasLimit := gasLimit + gasLimit/10 var totalSize uint32 + var totalGas uint64 err := m.verified.RangeSort(func(k txHash, t TxDesc) (bool, error) { - var done bool - totalSize += uint32(t.size) + decoded, err := t.tx.Decode() + if err != nil { + // Cannot decode, skip the tx. + // This should never happen, keeping `err` to log it properly` + return false, err + } + totalGas += decoded.EstimatedGasSpent() + if totalGas > slippageGasLimit { + // Total gas exceeded the slippage threshold, skip the tx + return false, nil + } + + totalSize += uint32(t.size) if totalSize <= maxTxsSize { txs = append(txs, t.tx) - } else { - done = true } + // We stop to iterate the mempool if: + // 1. The totalGas exceeded the gasLimit (but still below the slippage + // threshold) + // 2. The totalSize exceeds the limit + done := totalGas >= gasLimit || totalSize >= maxTxsSize + return done, nil }) if err != nil {