|
|
@ -580,12 +580,12 @@ type CallArgs struct { |
|
|
|
Data hexutil.Bytes `json:"data"` |
|
|
|
Data hexutil.Bytes `json:"data"` |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, error) { |
|
|
|
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, bool, error) { |
|
|
|
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) |
|
|
|
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) |
|
|
|
|
|
|
|
|
|
|
|
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
|
|
|
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
|
|
|
if state == nil || err != nil { |
|
|
|
if state == nil || err != nil { |
|
|
|
return nil, common.Big0, err |
|
|
|
return nil, common.Big0, false, err |
|
|
|
} |
|
|
|
} |
|
|
|
// Set sender address or use a default if none specified
|
|
|
|
// Set sender address or use a default if none specified
|
|
|
|
addr := args.From |
|
|
|
addr := args.From |
|
|
@ -623,7 +623,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr |
|
|
|
// Get a new instance of the EVM.
|
|
|
|
// Get a new instance of the EVM.
|
|
|
|
evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg) |
|
|
|
evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, common.Big0, err |
|
|
|
return nil, common.Big0, false, err |
|
|
|
} |
|
|
|
} |
|
|
|
// Wait for the context to be done and cancel the evm. Even if the
|
|
|
|
// Wait for the context to be done and cancel the evm. Even if the
|
|
|
|
// EVM has finished, cancelling may be done (repeatedly)
|
|
|
|
// EVM has finished, cancelling may be done (repeatedly)
|
|
|
@ -635,26 +635,28 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr |
|
|
|
// Setup the gas pool (also for unmetered requests)
|
|
|
|
// Setup the gas pool (also for unmetered requests)
|
|
|
|
// and apply the message.
|
|
|
|
// and apply the message.
|
|
|
|
gp := new(core.GasPool).AddGas(math.MaxBig256) |
|
|
|
gp := new(core.GasPool).AddGas(math.MaxBig256) |
|
|
|
// TODO utilize failed flag to help gas estimation
|
|
|
|
res, gas, failed, err := core.ApplyMessage(evm, msg, gp) |
|
|
|
res, gas, _, err := core.ApplyMessage(evm, msg, gp) |
|
|
|
|
|
|
|
if err := vmError(); err != nil { |
|
|
|
if err := vmError(); err != nil { |
|
|
|
return nil, common.Big0, err |
|
|
|
return nil, common.Big0, false, err |
|
|
|
} |
|
|
|
} |
|
|
|
return res, gas, err |
|
|
|
return res, gas, failed, err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Call executes the given transaction on the state for the given block number.
|
|
|
|
// Call executes the given transaction on the state for the given block number.
|
|
|
|
// It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
|
|
|
|
// It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
|
|
|
|
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { |
|
|
|
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { |
|
|
|
result, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true}) |
|
|
|
result, _, _, err := s.doCall(ctx, args, blockNr, vm.Config{DisableGasMetering: true}) |
|
|
|
return (hexutil.Bytes)(result), err |
|
|
|
return (hexutil.Bytes)(result), err |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction.
|
|
|
|
// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction.
|
|
|
|
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) { |
|
|
|
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) { |
|
|
|
// Binary search the gas requirement, as it may be higher than the amount used
|
|
|
|
// Binary search the gas requirement, as it may be higher than the amount used
|
|
|
|
var lo, hi uint64 |
|
|
|
var ( |
|
|
|
if (*big.Int)(&args.Gas).Sign() != 0 { |
|
|
|
lo uint64 = params.TxGas - 1 |
|
|
|
|
|
|
|
hi uint64 |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
if (*big.Int)(&args.Gas).Uint64() >= params.TxGas { |
|
|
|
hi = (*big.Int)(&args.Gas).Uint64() |
|
|
|
hi = (*big.Int)(&args.Gas).Uint64() |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// Retrieve the current pending block to act as the gas ceiling
|
|
|
|
// Retrieve the current pending block to act as the gas ceiling
|
|
|
@ -669,10 +671,10 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (* |
|
|
|
mid := (hi + lo) / 2 |
|
|
|
mid := (hi + lo) / 2 |
|
|
|
(*big.Int)(&args.Gas).SetUint64(mid) |
|
|
|
(*big.Int)(&args.Gas).SetUint64(mid) |
|
|
|
|
|
|
|
|
|
|
|
_, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}) |
|
|
|
_, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}) |
|
|
|
|
|
|
|
|
|
|
|
// If the transaction became invalid or used all the gas (failed), raise the gas limit
|
|
|
|
// If the transaction became invalid or execution failed, raise the gas limit
|
|
|
|
if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 { |
|
|
|
if err != nil || failed { |
|
|
|
lo = mid |
|
|
|
lo = mid |
|
|
|
continue |
|
|
|
continue |
|
|
|
} |
|
|
|
} |
|
|
@ -683,10 +685,11 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (* |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ExecutionResult groups all structured logs emitted by the EVM
|
|
|
|
// ExecutionResult groups all structured logs emitted by the EVM
|
|
|
|
// while replaying a transaction in debug mode as well as the amount of
|
|
|
|
// while replaying a transaction in debug mode as well as transaction
|
|
|
|
// gas used and the return value
|
|
|
|
// execution status, the amount of gas used and the return value
|
|
|
|
type ExecutionResult struct { |
|
|
|
type ExecutionResult struct { |
|
|
|
Gas *big.Int `json:"gas"` |
|
|
|
Gas *big.Int `json:"gas"` |
|
|
|
|
|
|
|
Failed bool `json:"failed"` |
|
|
|
ReturnValue string `json:"returnValue"` |
|
|
|
ReturnValue string `json:"returnValue"` |
|
|
|
StructLogs []StructLogRes `json:"structLogs"` |
|
|
|
StructLogs []StructLogRes `json:"structLogs"` |
|
|
|
} |
|
|
|
} |
|
|
|