@@ -114,7 +114,7 @@ func headerByNumberOrHash(ctx context.Context, tx kv.Tx, blockNrOrHash rpc.Block
114114}
115115
116116// EstimateGas implements eth_estimateGas. Returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain.
117- func (api * APIImpl ) EstimateGas (ctx context.Context , argsOrNil * ethapi2.CallArgs ) (hexutil.Uint64 , error ) {
117+ func (api * APIImpl ) EstimateGas (ctx context.Context , argsOrNil * ethapi2.CallArgs , blockNrOrHash * rpc. BlockNumberOrHash ) (hexutil.Uint64 , error ) {
118118 var args ethapi2.CallArgs
119119 // if we actually get CallArgs here, we use them
120120 if argsOrNil != nil {
@@ -138,39 +138,36 @@ func (api *APIImpl) EstimateGas(ctx context.Context, argsOrNil *ethapi2.CallArgs
138138 args .From = new (libcommon.Address )
139139 }
140140
141- chainConfig , err := api .chainConfig (ctx , dbtx )
142- if err != nil {
143- return 0 , err
144- }
145-
146- latestCanBlockNumber , latestCanHash , isLatest , err := rpchelper .GetCanonicalBlockNumber (latestNumOrHash , dbtx , api .filters ) // DoCall cannot be executed on non-canonical blocks
147- if err != nil {
148- return 0 , err
149- }
150-
151- // try and get the block from the lru cache first then try DB before failing
152- block := api .tryBlockFromLru (latestCanHash )
153- if block == nil {
154- block , err = api .blockWithSenders (ctx , dbtx , latestCanHash , latestCanBlockNumber )
155- if err != nil {
156- return 0 , err
157- }
158- }
159- if block == nil {
160- return 0 , fmt .Errorf ("could not find latest block in cache or db" )
161- }
162-
163- stateReader , err := rpchelper .CreateStateReaderFromBlockNumber (ctx , dbtx , latestCanBlockNumber , isLatest , 0 , api .stateCache , api .historyV3 (dbtx ), chainConfig .ChainName )
164- if err != nil {
165- return 0 , err
141+ bNrOrHash := rpc .BlockNumberOrHashWithNumber (rpc .PendingBlockNumber )
142+ if blockNrOrHash != nil {
143+ bNrOrHash = * blockNrOrHash
166144 }
167- header := block .HeaderNoCopy ()
168145
169146 // Determine the highest gas limit can be used during the estimation.
170147 if args .Gas != nil && uint64 (* args .Gas ) >= params .TxGas {
171148 hi = uint64 (* args .Gas )
172149 } else {
173- hi = header .GasLimit
150+ // Retrieve the block to act as the gas ceiling
151+ h , err := headerByNumberOrHash (ctx , dbtx , bNrOrHash , api )
152+ if err != nil {
153+ return 0 , err
154+ }
155+ if h == nil {
156+ // if a block number was supplied and there is no header return 0
157+ if blockNrOrHash != nil {
158+ return 0 , nil
159+ }
160+
161+ // block number not supplied, so we haven't found a pending block, read the latest block instead
162+ h , err = headerByNumberOrHash (ctx , dbtx , latestNumOrHash , api )
163+ if err != nil {
164+ return 0 , err
165+ }
166+ if h == nil {
167+ return 0 , nil
168+ }
169+ }
170+ hi = h .GasLimit
174171 }
175172
176173 var feeCap * big.Int
@@ -224,8 +221,35 @@ func (api *APIImpl) EstimateGas(ctx context.Context, argsOrNil *ethapi2.CallArgs
224221 }
225222 gasCap = hi
226223
224+ chainConfig , err := api .chainConfig (ctx , dbtx )
225+ if err != nil {
226+ return 0 , err
227+ }
227228 engine := api .engine ()
228229
230+ latestCanBlockNumber , latestCanHash , isLatest , err := rpchelper .GetCanonicalBlockNumber (latestNumOrHash , dbtx , api .filters ) // DoCall cannot be executed on non-canonical blocks
231+ if err != nil {
232+ return 0 , err
233+ }
234+
235+ // try and get the block from the lru cache first then try DB before failing
236+ block := api .tryBlockFromLru (latestCanHash )
237+ if block == nil {
238+ block , err = api .blockWithSenders (ctx , dbtx , latestCanHash , latestCanBlockNumber )
239+ if err != nil {
240+ return 0 , err
241+ }
242+ }
243+ if block == nil {
244+ return 0 , fmt .Errorf ("could not find latest block in cache or db" )
245+ }
246+
247+ stateReader , err := rpchelper .CreateStateReaderFromBlockNumber (ctx , dbtx , latestCanBlockNumber , isLatest , 0 , api .stateCache , api .historyV3 (dbtx ), chainConfig .ChainName )
248+ if err != nil {
249+ return 0 , err
250+ }
251+ header := block .HeaderNoCopy ()
252+
229253 caller , err := transactions .NewReusableCaller (engine , stateReader , nil , header , args , api .GasCap , latestNumOrHash , dbtx , api ._blockReader , chainConfig , api .evmCallTimeout )
230254 if err != nil {
231255 return 0 , err
0 commit comments