@@ -29,6 +29,7 @@ import (
29
29
"github.com/XinFinOrg/XDPoSChain/XDCx"
30
30
"github.com/XinFinOrg/XDPoSChain/XDCxlending"
31
31
"github.com/XinFinOrg/XDPoSChain/accounts"
32
+ "github.com/XinFinOrg/XDPoSChain/accounts/abi"
32
33
"github.com/XinFinOrg/XDPoSChain/accounts/abi/bind"
33
34
"github.com/XinFinOrg/XDPoSChain/accounts/keystore"
34
35
"github.com/XinFinOrg/XDPoSChain/common"
@@ -54,7 +55,6 @@ import (
54
55
var _ bind.ContractBackend = (* SimulatedBackend )(nil )
55
56
56
57
var errBlockNumberUnsupported = errors .New ("SimulatedBackend cannot access blocks other than the latest block" )
57
- var errGasEstimationFailed = errors .New ("gas required exceeds allowance or always failing transaction" )
58
58
59
59
// SimulatedBackend implements bind.ContractBackend, simulating a blockchain in
60
60
// the background. Its main purpose is to allow easily testing contract bindings.
@@ -161,6 +161,12 @@ func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend {
161
161
return backend
162
162
}
163
163
164
+ // Close terminates the underlying blockchain's update loop.
165
+ func (b * SimulatedBackend ) Close () error {
166
+ b .blockchain .Stop ()
167
+ return nil
168
+ }
169
+
164
170
// Commit imports all the pending transactions as a single block and starts a
165
171
// fresh new state.
166
172
func (b * SimulatedBackend ) Commit () {
@@ -290,8 +296,11 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call XDPoSChain.Cal
290
296
if err != nil {
291
297
return nil , err
292
298
}
293
- rval , _ , _ , err := b .callContract (ctx , call , b .blockchain .CurrentBlock (), state )
294
- return rval , err
299
+ res , err := b .callContract (ctx , call , b .blockchain .CurrentBlock (), state )
300
+ if err != nil {
301
+ return nil , err
302
+ }
303
+ return res .Return (), nil
295
304
}
296
305
297
306
// PendingCallContract executes a contract call on the pending state.
@@ -300,8 +309,11 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call XDPoSCh
300
309
defer b .mu .Unlock ()
301
310
defer b .pendingState .RevertToSnapshot (b .pendingState .Snapshot ())
302
311
303
- rval , _ , _ , err := b .callContract (ctx , call , b .pendingBlock , b .pendingState )
304
- return rval , err
312
+ res , err := b .callContract (ctx , call , b .pendingBlock , b .pendingState )
313
+ if err != nil {
314
+ return nil , err
315
+ }
316
+ return res .Return (), nil
305
317
}
306
318
307
319
// PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving
@@ -348,42 +360,70 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call XDPoSChain.Call
348
360
cap = hi
349
361
350
362
// Create a helper to check if a gas allowance results in an executable transaction
351
- executable := func (gas uint64 ) bool {
363
+ executable := func (gas uint64 ) ( bool , * core. ExecutionResult , error ) {
352
364
call .Gas = gas
353
365
354
366
snapshot := b .pendingState .Snapshot ()
355
- _ , _ , failed , err := b .callContract (ctx , call , b .pendingBlock , b .pendingState )
367
+ res , err := b .callContract (ctx , call , b .pendingBlock , b .pendingState )
356
368
b .pendingState .RevertToSnapshot (snapshot )
357
369
358
- if err != nil || failed {
359
- return false
370
+ if err != nil {
371
+ if err == core .ErrIntrinsicGas {
372
+ return true , nil , nil // Special case, raise gas limit
373
+ }
374
+ return true , nil , err // Bail out
360
375
}
361
- return true
376
+ return res . Failed (), res , nil
362
377
}
363
378
// Execute the binary search and hone in on an executable gas limit
364
379
for lo + 1 < hi {
365
380
mid := (hi + lo ) / 2
366
- if ! executable (mid ) {
381
+ failed , _ , err := executable (mid )
382
+
383
+ // If the error is not nil(consensus error), it means the provided message
384
+ // call or transaction will never be accepted no matter how much gas it is
385
+ // assigned. Return the error directly, don't struggle any more
386
+ if err != nil {
387
+ return 0 , err
388
+ }
389
+ if failed {
367
390
lo = mid
368
391
} else {
369
392
hi = mid
370
393
}
371
394
}
372
395
// Reject the transaction as invalid if it still fails at the highest allowance
373
396
if hi == cap {
374
- if ! executable (hi ) {
375
- return 0 , errGasEstimationFailed
397
+ failed , result , err := executable (hi )
398
+ if err != nil {
399
+ return 0 , err
400
+ }
401
+ if failed {
402
+ if result != nil && result .Err != vm .ErrOutOfGas {
403
+ errMsg := fmt .Sprintf ("always failing transaction (%v)" , result .Err )
404
+ if len (result .Revert ()) > 0 {
405
+ ret , err := abi .UnpackRevert (result .Revert ())
406
+ if err != nil {
407
+ errMsg += fmt .Sprintf (" (%#x)" , result .Revert ())
408
+ } else {
409
+ errMsg += fmt .Sprintf (" (%s)" , ret )
410
+ }
411
+ }
412
+ return 0 , errors .New (errMsg )
413
+ }
414
+ // Otherwise, the specified gas cap is too low
415
+ return 0 , fmt .Errorf ("gas required exceeds allowance (%d)" , cap )
376
416
}
377
417
}
378
418
return hi , nil
379
419
}
380
420
381
421
// callContract implements common code between normal and pending contract calls.
382
422
// state is modified during execution, make sure to copy it if necessary.
383
- func (b * SimulatedBackend ) callContract (ctx context.Context , call XDPoSChain.CallMsg , block * types.Block , statedb * state.StateDB ) (ret [] byte , usedGas uint64 , failed bool , err error ) {
423
+ func (b * SimulatedBackend ) callContract (ctx context.Context , call XDPoSChain.CallMsg , block * types.Block , statedb * state.StateDB ) (* core. ExecutionResult , error ) {
384
424
// Gas prices post 1559 need to be initialized
385
425
if call .GasPrice != nil && (call .GasFeeCap != nil || call .GasTipCap != nil ) {
386
- return nil , 0 , false , errors .New ("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified" )
426
+ return nil , errors .New ("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified" )
387
427
}
388
428
head := b .blockchain .CurrentHeader ()
389
429
if ! b .blockchain .Config ().IsEIP1559 (head .Number ) {
@@ -438,8 +478,8 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.Cal
438
478
vmenv := vm .NewEVM (evmContext , txContext , statedb , nil , b .config , vm.Config {NoBaseFee : true })
439
479
gaspool := new (core.GasPool ).AddGas (math .MaxUint64 )
440
480
owner := common.Address {}
441
- ret , usedGas , failed , err , _ = core .NewStateTransition (vmenv , msg , gaspool ).TransitionDb (owner )
442
- return
481
+ res , err , _ : = core .NewStateTransition (vmenv , msg , gaspool ).TransitionDb (owner )
482
+ return res , err
443
483
}
444
484
445
485
// SendTransaction updates the pending block to include the given transaction.
0 commit comments