@@ -40,6 +40,7 @@ import (
40
40
"github.com/ethereum/go-ethereum/core/types"
41
41
"github.com/ethereum/go-ethereum/core/vm"
42
42
"github.com/ethereum/go-ethereum/crypto"
43
+ "github.com/ethereum/go-ethereum/eth/gasestimator"
43
44
"github.com/ethereum/go-ethereum/eth/tracers/logger"
44
45
"github.com/ethereum/go-ethereum/log"
45
46
"github.com/ethereum/go-ethereum/p2p"
@@ -1120,15 +1121,16 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
1120
1121
return doCall (ctx , b , args , state , header , overrides , blockOverrides , timeout , globalGasCap )
1121
1122
}
1122
1123
1123
- func newRevertError (result * core.ExecutionResult ) * revertError {
1124
- reason , errUnpack := abi .UnpackRevert (result .Revert ())
1125
- err := errors .New ("execution reverted" )
1124
+ func newRevertError (revert []byte ) * revertError {
1125
+ err := vm .ErrExecutionReverted
1126
+
1127
+ reason , errUnpack := abi .UnpackRevert (revert )
1126
1128
if errUnpack == nil {
1127
- err = fmt .Errorf ("execution reverted : %v" , reason )
1129
+ err = fmt .Errorf ("%w : %v" , vm . ErrExecutionReverted , reason )
1128
1130
}
1129
1131
return & revertError {
1130
1132
error : err ,
1131
- reason : hexutil .Encode (result . Revert () ),
1133
+ reason : hexutil .Encode (revert ),
1132
1134
}
1133
1135
}
1134
1136
@@ -1167,147 +1169,44 @@ func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrO
1167
1169
}
1168
1170
// If the result contains a revert reason, try to unpack and return it.
1169
1171
if len (result .Revert ()) > 0 {
1170
- return nil , newRevertError (result )
1172
+ return nil , newRevertError (result . Revert () )
1171
1173
}
1172
1174
return result .Return (), result .Err
1173
1175
}
1174
1176
1175
- // executeEstimate is a helper that executes the transaction under a given gas limit and returns
1176
- // true if the transaction fails for a reason that might be related to not enough gas. A non-nil
1177
- // error means execution failed due to reasons unrelated to the gas limit.
1178
- func executeEstimate (ctx context.Context , b Backend , args TransactionArgs , state * state.StateDB , header * types.Header , gasCap uint64 , gasLimit uint64 ) (bool , * core.ExecutionResult , error ) {
1179
- args .Gas = (* hexutil .Uint64 )(& gasLimit )
1180
- result , err := doCall (ctx , b , args , state , header , nil , nil , 0 , gasCap )
1181
- if err != nil {
1182
- if errors .Is (err , core .ErrIntrinsicGas ) {
1183
- return true , nil , nil // Special case, raise gas limit
1184
- }
1185
- return true , nil , err // Bail out
1186
- }
1187
- return result .Failed (), result , nil
1188
- }
1189
-
1190
1177
// DoEstimateGas returns the lowest possible gas limit that allows the transaction to run
1191
1178
// successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if
1192
1179
// there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil &
1193
1180
// non-zero) and `gasCap` (if non-zero).
1194
1181
func DoEstimateGas (ctx context.Context , b Backend , args TransactionArgs , blockNrOrHash rpc.BlockNumberOrHash , overrides * StateOverride , gasCap uint64 ) (hexutil.Uint64 , error ) {
1195
- // Binary search the gas limit, as it may need to be higher than the amount used
1196
- var (
1197
- lo uint64 // lowest-known gas limit where tx execution fails
1198
- hi uint64 // lowest-known gas limit where tx execution succeeds
1199
- )
1200
- // Use zero address if sender unspecified.
1201
- if args .From == nil {
1202
- args .From = new (common.Address )
1203
- }
1204
- // Determine the highest gas limit can be used during the estimation.
1205
- if args .Gas != nil && uint64 (* args .Gas ) >= params .TxGas {
1206
- hi = uint64 (* args .Gas )
1207
- } else {
1208
- // Retrieve the block to act as the gas ceiling
1209
- block , err := b .BlockByNumberOrHash (ctx , blockNrOrHash )
1210
- if err != nil {
1211
- return 0 , err
1212
- }
1213
- if block == nil {
1214
- return 0 , errors .New ("block not found" )
1215
- }
1216
- hi = block .GasLimit ()
1217
- }
1218
- // Normalize the max fee per gas the call is willing to spend.
1219
- var feeCap * big.Int
1220
- if args .GasPrice != nil && (args .MaxFeePerGas != nil || args .MaxPriorityFeePerGas != nil ) {
1221
- return 0 , errors .New ("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified" )
1222
- } else if args .GasPrice != nil {
1223
- feeCap = args .GasPrice .ToInt ()
1224
- } else if args .MaxFeePerGas != nil {
1225
- feeCap = args .MaxFeePerGas .ToInt ()
1226
- } else {
1227
- feeCap = common .Big0
1228
- }
1229
-
1182
+ // Retrieve the base state and mutate it with any overrides
1230
1183
state , header , err := b .StateAndHeaderByNumberOrHash (ctx , blockNrOrHash )
1231
1184
if state == nil || err != nil {
1232
1185
return 0 , err
1233
1186
}
1234
- if err : = overrides .Apply (state ); err != nil {
1187
+ if err = overrides .Apply (state ); err != nil {
1235
1188
return 0 , err
1236
1189
}
1237
-
1238
- // Recap the highest gas limit with account's available balance.
1239
- if feeCap .BitLen () != 0 {
1240
- balance := state .GetBalance (* args .From ) // from can't be nil
1241
- available := new (big.Int ).Set (balance )
1242
- if args .Value != nil {
1243
- if args .Value .ToInt ().Cmp (available ) >= 0 {
1244
- return 0 , core .ErrInsufficientFundsForTransfer
1245
- }
1246
- available .Sub (available , args .Value .ToInt ())
1247
- }
1248
- allowance := new (big.Int ).Div (available , feeCap )
1249
-
1250
- // If the allowance is larger than maximum uint64, skip checking
1251
- if allowance .IsUint64 () && hi > allowance .Uint64 () {
1252
- transfer := args .Value
1253
- if transfer == nil {
1254
- transfer = new (hexutil.Big )
1255
- }
1256
- log .Warn ("Gas estimation capped by limited funds" , "original" , hi , "balance" , balance ,
1257
- "sent" , transfer .ToInt (), "maxFeePerGas" , feeCap , "fundable" , allowance )
1258
- hi = allowance .Uint64 ()
1259
- }
1190
+ // Construct the gas estimator option from the user input
1191
+ opts := & gasestimator.Options {
1192
+ Config : b .ChainConfig (),
1193
+ Chain : NewChainContext (ctx , b ),
1194
+ Header : header ,
1195
+ State : state ,
1260
1196
}
1261
- // Recap the highest gas allowance with specified gascap.
1262
- if gasCap != 0 && hi > gasCap {
1263
- log .Warn ("Caller gas above allowance, capping" , "requested" , hi , "cap" , gasCap )
1264
- hi = gasCap
1265
- }
1266
-
1267
- // We first execute the transaction at the highest allowable gas limit, since if this fails we
1268
- // can return error immediately.
1269
- failed , result , err := executeEstimate (ctx , b , args , state .Copy (), header , gasCap , hi )
1197
+ // Run the gas estimation andwrap any revertals into a custom return
1198
+ call , err := args .ToMessage (gasCap , header .BaseFee )
1270
1199
if err != nil {
1271
1200
return 0 , err
1272
1201
}
1273
- if failed {
1274
- if result != nil && ! errors .Is (result .Err , vm .ErrOutOfGas ) {
1275
- if len (result .Revert ()) > 0 {
1276
- return 0 , newRevertError (result )
1277
- }
1278
- return 0 , result .Err
1279
- }
1280
- return 0 , fmt .Errorf ("gas required exceeds allowance (%d)" , hi )
1281
- }
1282
- // For almost any transaction, the gas consumed by the unconstrained execution above
1283
- // lower-bounds the gas limit required for it to succeed. One exception is those txs that
1284
- // explicitly check gas remaining in order to successfully execute within a given limit, but we
1285
- // probably don't want to return a lowest possible gas limit for these cases anyway.
1286
- lo = result .UsedGas - 1
1287
-
1288
- // Binary search for the smallest gas limit that allows the tx to execute successfully.
1289
- for lo + 1 < hi {
1290
- mid := (hi + lo ) / 2
1291
- if mid > lo * 2 {
1292
- // Most txs don't need much higher gas limit than their gas used, and most txs don't
1293
- // require near the full block limit of gas, so the selection of where to bisect the
1294
- // range here is skewed to favor the low side.
1295
- mid = lo * 2
1296
- }
1297
- failed , _ , err = executeEstimate (ctx , b , args , state .Copy (), header , gasCap , mid )
1298
- if err != nil {
1299
- // This should not happen under normal conditions since if we make it this far the
1300
- // transaction had run without error at least once before.
1301
- log .Error ("execution error in estimate gas" , "err" , err )
1302
- return 0 , err
1303
- }
1304
- if failed {
1305
- lo = mid
1306
- } else {
1307
- hi = mid
1202
+ estimate , revert , err := gasestimator .Estimate (ctx , call , opts , gasCap )
1203
+ if err != nil {
1204
+ if len (revert ) > 0 {
1205
+ return 0 , newRevertError (revert )
1308
1206
}
1207
+ return 0 , err
1309
1208
}
1310
- return hexutil .Uint64 (hi ), nil
1209
+ return hexutil .Uint64 (estimate ), nil
1311
1210
}
1312
1211
1313
1212
// EstimateGas returns the lowest possible gas limit that allows the transaction to run
0 commit comments