mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-11 06:23:47 +00:00
core/types, core/vm: mark tx execution as failed if error return
Motivation:
Current problem with gas estimation is not all cases is correct
using gas metrics, e.g. in the frontier contract deploys can fail without
consuming all gas due to have not enough gas to store contract code.
So a `failed` flag is useful which can detect the vm execution
status.
In Addition:
the `Reverted` flag has been removed, since it is too sensitive to
insert addtional field to it.
This commit is contained in:
parent
66d8ff8983
commit
65a6cc2f1e
12 changed files with 123 additions and 136 deletions
|
|
@ -167,7 +167,7 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rval, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
|
rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
|
||||||
return rval, err
|
return rval, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,7 +177,7 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereu
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
|
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
|
||||||
|
|
||||||
rval, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
||||||
return rval, err
|
return rval, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,11 +215,11 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||||
call.Gas = new(big.Int).SetUint64(mid)
|
call.Gas = new(big.Int).SetUint64(mid)
|
||||||
|
|
||||||
snapshot := b.pendingState.Snapshot()
|
snapshot := b.pendingState.Snapshot()
|
||||||
_, gas, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
||||||
b.pendingState.RevertToSnapshot(snapshot)
|
b.pendingState.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
// If the transaction became invalid or used all the gas (failed), raise the gas limit
|
// If the transaction became invalid or failed, raise the gas limit
|
||||||
if err != nil || gas.Cmp(call.Gas) == 0 {
|
if err != nil || failed {
|
||||||
lo = mid
|
lo = mid
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -231,7 +231,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||||
|
|
||||||
// callContract implemens common code between normal and pending contract calls.
|
// callContract implemens common code between normal and pending contract calls.
|
||||||
// state is modified during execution, make sure to copy it if necessary.
|
// state is modified during execution, make sure to copy it if necessary.
|
||||||
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, *big.Int, error) {
|
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, *big.Int, bool, error) {
|
||||||
// Ensure message is initialized properly.
|
// Ensure message is initialized properly.
|
||||||
if call.GasPrice == nil {
|
if call.GasPrice == nil {
|
||||||
call.GasPrice = big.NewInt(1)
|
call.GasPrice = big.NewInt(1)
|
||||||
|
|
@ -253,8 +253,8 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
|
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
|
||||||
gaspool := new(core.GasPool).AddGas(math.MaxBig256)
|
gaspool := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, gasUsed, _, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
ret, gasUsed, _, failed, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||||
return ret, gasUsed, err
|
return ret, gasUsed, failed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTransaction updates the pending block to include the given transaction.
|
// SendTransaction updates the pending block to include the given transaction.
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEVM(context, statedb, config, cfg)
|
vmenv := vm.NewEVM(context, statedb, config, cfg)
|
||||||
// Apply the transaction to the current state (included in the env)
|
// Apply the transaction to the current state (included in the env)
|
||||||
_, gas, reverted, err := ApplyMessage(vmenv, msg, gp)
|
_, gas, _, err := ApplyMessage(vmenv, msg, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +111,6 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common
|
||||||
receipt := types.NewReceipt(root.Bytes(), usedGas)
|
receipt := types.NewReceipt(root.Bytes(), usedGas)
|
||||||
receipt.TxHash = tx.Hash()
|
receipt.TxHash = tx.Hash()
|
||||||
receipt.GasUsed = new(big.Int).Set(gas)
|
receipt.GasUsed = new(big.Int).Set(gas)
|
||||||
receipt.Reverted = reverted
|
|
||||||
// if the transaction created a contract, store the creation address in the receipt.
|
// if the transaction created a contract, store the creation address in the receipt.
|
||||||
if msg.To() == nil {
|
if msg.To() == nil {
|
||||||
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
|
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
|
||||||
|
|
|
||||||
|
|
@ -130,8 +130,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
||||||
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, bool, error) {
|
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, bool, error) {
|
||||||
st := NewStateTransition(evm, msg, gp)
|
st := NewStateTransition(evm, msg, gp)
|
||||||
|
|
||||||
ret, _, gasUsed, reverted, err := st.TransitionDb()
|
ret, _, gasUsed, failed, err := st.TransitionDb()
|
||||||
return ret, gasUsed, reverted, err
|
return ret, gasUsed, failed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) from() vm.AccountRef {
|
func (st *StateTransition) from() vm.AccountRef {
|
||||||
|
|
@ -208,7 +208,7 @@ func (st *StateTransition) preCheck() error {
|
||||||
// TransitionDb will transition the state by applying the current message and returning the result
|
// TransitionDb will transition the state by applying the current message and returning the result
|
||||||
// including the required gas for the operation as well as the used gas. It returns an error if it
|
// including the required gas for the operation as well as the used gas. It returns an error if it
|
||||||
// failed. An error indicates a consensus issue.
|
// failed. An error indicates a consensus issue.
|
||||||
func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, reverted bool, err error) {
|
func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, failed bool, err error) {
|
||||||
if err = st.preCheck(); err != nil {
|
if err = st.preCheck(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -236,11 +236,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
||||||
vmerr error
|
vmerr error
|
||||||
)
|
)
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
ret, _, st.gas, reverted, vmerr = evm.Create(sender, st.data, st.gas, st.value)
|
ret, _, st.gas, failed, vmerr = evm.Create(sender, st.data, st.gas, st.value)
|
||||||
} else {
|
} else {
|
||||||
// Increment the nonce for the next transaction
|
// Increment the nonce for the next transaction
|
||||||
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1)
|
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1)
|
||||||
ret, st.gas, reverted, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value)
|
ret, st.gas, failed, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value)
|
||||||
}
|
}
|
||||||
if vmerr != nil {
|
if vmerr != nil {
|
||||||
log.Debug("VM returned with error", "err", vmerr)
|
log.Debug("VM returned with error", "err", vmerr)
|
||||||
|
|
@ -256,7 +256,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
||||||
st.refundGas()
|
st.refundGas()
|
||||||
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(st.gasUsed(), st.gasPrice))
|
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(st.gasUsed(), st.gasPrice))
|
||||||
|
|
||||||
return ret, requiredGas, st.gasUsed(), reverted, err
|
return ret, requiredGas, st.gasUsed(), failed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) refundGas() {
|
func (st *StateTransition) refundGas() {
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
||||||
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
||||||
ContractAddress common.Address `json:"contractAddress"`
|
ContractAddress common.Address `json:"contractAddress"`
|
||||||
GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"`
|
GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"`
|
||||||
Reverted bool `json:"reverted" gencode:"required"`
|
|
||||||
}
|
}
|
||||||
var enc Receipt
|
var enc Receipt
|
||||||
enc.PostState = r.PostState
|
enc.PostState = r.PostState
|
||||||
|
|
@ -30,7 +29,6 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
||||||
enc.TxHash = r.TxHash
|
enc.TxHash = r.TxHash
|
||||||
enc.ContractAddress = r.ContractAddress
|
enc.ContractAddress = r.ContractAddress
|
||||||
enc.GasUsed = (*hexutil.Big)(r.GasUsed)
|
enc.GasUsed = (*hexutil.Big)(r.GasUsed)
|
||||||
enc.Reverted = r.Reverted
|
|
||||||
return json.Marshal(&enc)
|
return json.Marshal(&enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,7 +41,6 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
||||||
TxHash *common.Hash `json:"transactionHash" gencodec:"required"`
|
TxHash *common.Hash `json:"transactionHash" gencodec:"required"`
|
||||||
ContractAddress *common.Address `json:"contractAddress"`
|
ContractAddress *common.Address `json:"contractAddress"`
|
||||||
GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"`
|
GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"`
|
||||||
Reverted *bool `json:"reverted" gencode:"required"`
|
|
||||||
}
|
}
|
||||||
var dec Receipt
|
var dec Receipt
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
|
|
@ -76,8 +73,5 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
||||||
return errors.New("missing required field 'gasUsed' for Receipt")
|
return errors.New("missing required field 'gasUsed' for Receipt")
|
||||||
}
|
}
|
||||||
r.GasUsed = (*big.Int)(dec.GasUsed)
|
r.GasUsed = (*big.Int)(dec.GasUsed)
|
||||||
if dec.Reverted != nil {
|
|
||||||
r.Reverted = *dec.Reverted
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,6 @@ type Receipt struct {
|
||||||
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
TxHash common.Hash `json:"transactionHash" gencodec:"required"`
|
||||||
ContractAddress common.Address `json:"contractAddress"`
|
ContractAddress common.Address `json:"contractAddress"`
|
||||||
GasUsed *big.Int `json:"gasUsed" gencodec:"required"`
|
GasUsed *big.Int `json:"gasUsed" gencodec:"required"`
|
||||||
// The Reverted field is true if transaction is reverted during state transition,
|
|
||||||
// As the transaction revert will cause all the remaining gas to be consumed,
|
|
||||||
// This field could help to gas estimation.
|
|
||||||
Reverted bool `json:"reverted" gencode:"required"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type receiptMarshaling struct {
|
type receiptMarshaling struct {
|
||||||
|
|
@ -95,7 +91,7 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
|
||||||
for i, log := range r.Logs {
|
for i, log := range r.Logs {
|
||||||
logs[i] = (*LogForStorage)(log)
|
logs[i] = (*LogForStorage)(log)
|
||||||
}
|
}
|
||||||
return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed, r.Reverted})
|
return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
|
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
|
||||||
|
|
@ -109,7 +105,6 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||||
ContractAddress common.Address
|
ContractAddress common.Address
|
||||||
Logs []*LogForStorage
|
Logs []*LogForStorage
|
||||||
GasUsed *big.Int
|
GasUsed *big.Int
|
||||||
Reverted bool
|
|
||||||
}
|
}
|
||||||
if err := s.Decode(&receipt); err != nil {
|
if err := s.Decode(&receipt); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -121,7 +116,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||||
r.Logs[i] = (*Log)(log)
|
r.Logs[i] = (*Log)(log)
|
||||||
}
|
}
|
||||||
// Assign the implementation fields
|
// Assign the implementation fields
|
||||||
r.TxHash, r.ContractAddress, r.GasUsed, r.Reverted = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed, receipt.Reverted
|
r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,7 @@ type Contract struct {
|
||||||
Args []byte
|
Args []byte
|
||||||
|
|
||||||
DelegateCall bool
|
DelegateCall bool
|
||||||
Reverted bool // use to represent whether transaction is reverted during state transition
|
Failed bool // Used to identify the execution status of the current transaction
|
||||||
// child's reverted field changed will also affect parent.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContract returns a new contract environment for the execution of EVM.
|
// NewContract returns a new contract environment for the execution of EVM.
|
||||||
|
|
@ -154,11 +153,11 @@ func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code [
|
||||||
self.CodeAddr = addr
|
self.CodeAddr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkReverted mark current transaction's execution has meet revert.
|
// MarkFailed mark current transaction's execution failed.
|
||||||
func (self *Contract) MarkReverted() {
|
func (self *Contract) MarkFailed() {
|
||||||
self.Reverted = true
|
self.Failed = true
|
||||||
// affect parent recursively
|
// affect parent recursively
|
||||||
if parent, ok := self.caller.(*Contract); ok {
|
if parent, ok := self.caller.(*Contract); ok {
|
||||||
parent.MarkReverted()
|
parent.MarkFailed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ func (evm *EVM) Cancel() {
|
||||||
// Call executes the contract associated with the addr with the given input as parameters. It also handles any
|
// Call executes the contract associated with the addr with the given input as parameters. It also handles any
|
||||||
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
|
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
|
||||||
// case of an execution error or failed value transfer.
|
// case of an execution error or failed value transfer.
|
||||||
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, reverted bool, err error) {
|
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, failed bool, err error) {
|
||||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
return nil, gas, false, nil
|
return nil, gas, false, nil
|
||||||
}
|
}
|
||||||
|
|
@ -163,9 +163,10 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
// when we're in homestead this also counts for code storage gas errors.
|
// when we're in homestead this also counts for code storage gas errors.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
evm.Revert(snapshot, contract)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
contract.MarkFailed()
|
||||||
}
|
}
|
||||||
return ret, contract.Gas, contract.Reverted, err
|
return ret, contract.Gas, contract.Failed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CallCode executes the contract associated with the addr with the given input as parameters. It also handles any
|
// CallCode executes the contract associated with the addr with the given input as parameters. It also handles any
|
||||||
|
|
@ -200,7 +201,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
|
||||||
ret, err = run(evm, snapshot, contract, input)
|
ret, err = run(evm, snapshot, contract, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
evm.Revert(snapshot, contract)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
contract.MarkFailed()
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, contract.Gas, err
|
return ret, contract.Gas, err
|
||||||
|
|
@ -234,14 +236,15 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||||
ret, err = run(evm, snapshot, contract, input)
|
ret, err = run(evm, snapshot, contract, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
evm.Revert(snapshot, contract)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
contract.MarkFailed()
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, contract.Gas, err
|
return ret, contract.Gas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new contract using code as deployment code.
|
// Create creates a new contract using code as deployment code.
|
||||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, reverted bool, err error) {
|
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, failed bool, err error) {
|
||||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
return nil, common.Address{}, gas, false, nil
|
return nil, common.Address{}, gas, false, nil
|
||||||
}
|
}
|
||||||
|
|
@ -295,7 +298,12 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||||
if maxCodeSizeExceeded ||
|
if maxCodeSizeExceeded ||
|
||||||
(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
|
(err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
evm.Revert(snapshot, contract)
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
}
|
||||||
|
// When the virtual machine returns an error or stores an excessive contract code,
|
||||||
|
// the execution of the transaction is marked as failed.
|
||||||
|
if maxCodeSizeExceeded || err != nil {
|
||||||
|
contract.MarkFailed()
|
||||||
}
|
}
|
||||||
// If the vm returned with an error the return value should be set to nil.
|
// If the vm returned with an error the return value should be set to nil.
|
||||||
// This isn't consensus critical but merely to for behaviour reasons such as
|
// This isn't consensus critical but merely to for behaviour reasons such as
|
||||||
|
|
@ -304,7 +312,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||||
ret = nil
|
ret = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, contractAddr, contract.Gas, contract.Reverted, err
|
return ret, contractAddr, contract.Gas, contract.Failed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainConfig returns the evmironment's chain configuration
|
// ChainConfig returns the evmironment's chain configuration
|
||||||
|
|
@ -312,10 +320,3 @@ func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
||||||
|
|
||||||
// Interpreter returns the EVM interpreter
|
// Interpreter returns the EVM interpreter
|
||||||
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }
|
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }
|
||||||
|
|
||||||
// Revert revert all state changes made since the given revision.
|
|
||||||
// set `reverted` flag recursively.
|
|
||||||
func (evm *EVM) Revert(snapshot int, contract *Contract) {
|
|
||||||
evm.StateDB.RevertToSnapshot(snapshot)
|
|
||||||
contract.MarkReverted()
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -551,7 +551,7 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
||||||
}
|
}
|
||||||
|
|
||||||
contract.UseGas(gas)
|
contract.UseGas(gas)
|
||||||
// ignore reverted here since it is only useful in vm entry.
|
// ignore failed flag here since it is only useful in vm entrance.
|
||||||
_, addr, returnGas, _, suberr := evm.Create(contract, input, gas, value)
|
_, addr, returnGas, _, suberr := evm.Create(contract, input, gas, value)
|
||||||
// Push item on the stack based on the returned error. If the ruleset is
|
// Push item on the stack based on the returned error. If the ruleset is
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
|
|
@ -589,7 +589,7 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
||||||
if value.Sign() != 0 {
|
if value.Sign() != 0 {
|
||||||
gas += params.CallStipend
|
gas += params.CallStipend
|
||||||
}
|
}
|
||||||
// ignore revert here, same with opCreate.
|
// ignore failed flag here, same with opCreate.
|
||||||
ret, returnGas, _, err := evm.Call(contract, address, args, gas, value)
|
ret, returnGas, _, err := evm.Call(contract, address, args, gas, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, bool, err
|
||||||
// set the receiver's (the executing contract) code for execution.
|
// set the receiver's (the executing contract) code for execution.
|
||||||
cfg.State.SetCode(address, code)
|
cfg.State.SetCode(address, code)
|
||||||
// Call the code with the given configuration.
|
// Call the code with the given configuration.
|
||||||
ret, _, reverted, err := vmenv.Call(
|
ret, _, failed, err := vmenv.Call(
|
||||||
sender,
|
sender,
|
||||||
common.StringToAddress("contract"),
|
common.StringToAddress("contract"),
|
||||||
input,
|
input,
|
||||||
|
|
@ -121,7 +121,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, bool, err
|
||||||
cfg.Value,
|
cfg.Value,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ret, cfg.State, reverted, err
|
return ret, cfg.State, failed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create executes the code using the EVM create method
|
// Create executes the code using the EVM create method
|
||||||
|
|
@ -141,13 +141,13 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, bool, er
|
||||||
)
|
)
|
||||||
|
|
||||||
// Call the code with the given configuration.
|
// Call the code with the given configuration.
|
||||||
code, address, leftOverGas, reverted, err := vmenv.Create(
|
code, address, leftOverGas, failed, err := vmenv.Create(
|
||||||
sender,
|
sender,
|
||||||
input,
|
input,
|
||||||
cfg.GasLimit,
|
cfg.GasLimit,
|
||||||
cfg.Value,
|
cfg.Value,
|
||||||
)
|
)
|
||||||
return code, address, leftOverGas, reverted, err
|
return code, address, leftOverGas, failed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call executes the code given by the contract's address. It will return the
|
// Call executes the code given by the contract's address. It will return the
|
||||||
|
|
@ -162,7 +162,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, bo
|
||||||
|
|
||||||
sender := cfg.State.GetOrNewStateObject(cfg.Origin)
|
sender := cfg.State.GetOrNewStateObject(cfg.Origin)
|
||||||
// Call the code with the given configuration.
|
// Call the code with the given configuration.
|
||||||
ret, leftOverGas, reverted, err := vmenv.Call(
|
ret, leftOverGas, failed, err := vmenv.Call(
|
||||||
sender,
|
sender,
|
||||||
address,
|
address,
|
||||||
input,
|
input,
|
||||||
|
|
@ -170,5 +170,5 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, bo
|
||||||
cfg.Value,
|
cfg.Value,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ret, leftOverGas, reverted, err
|
return ret, leftOverGas, failed, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,21 +119,21 @@ func TestCall(t *testing.T) {
|
||||||
|
|
||||||
func TestTransactionReverted(t *testing.T) {
|
func TestTransactionReverted(t *testing.T) {
|
||||||
/*
|
/*
|
||||||
Contract Source Code
|
Contract Source Code
|
||||||
```
|
```
|
||||||
contract Demo {
|
contract Demo {
|
||||||
function Demo() {}
|
function Demo() {}
|
||||||
function IllegalDivision() returns(int) {
|
function IllegalDivision() returns(int) {
|
||||||
var dividend = 0;
|
var dividend = 0;
|
||||||
return 1 / dividend;
|
return 1 / dividend;
|
||||||
}
|
}
|
||||||
function LegalDivision() returns(int) {
|
function LegalDivision() returns(int) {
|
||||||
var dividend = 1;
|
var dividend = 1;
|
||||||
return 1 / dividend;
|
return 1 / dividend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
var definition = `[{"constant":false,"inputs":[],"name":"LegalDivision","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"IllegalDivision","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}]`
|
var definition = `[{"constant":false,"inputs":[],"name":"LegalDivision","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"IllegalDivision","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}]`
|
||||||
var rawcode = common.Hex2Bytes("6060604052341561000c57fe5b5b5b5b60f88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632d256662146044578063522de105146067575bfe5b3415604b57fe5b6051608a565b6040518082815260200191505060405180910390f35b3415606e57fe5b607460ab565b6040518082815260200191505060405180910390f35b60006000600190508060ff16600181151560a057fe5b0460ff1691505b5090565b60006000600090508060ff16600181151560c157fe5b0460ff1691505b50905600a165627a7a7230582091585859014c4644d0427bf34abc65433b5874993ddea00cac57bcb87ee4cb6b0029")
|
var rawcode = common.Hex2Bytes("6060604052341561000c57fe5b5b5b5b60f88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632d256662146044578063522de105146067575bfe5b3415604b57fe5b6051608a565b6040518082815260200191505060405180910390f35b3415606e57fe5b607460ab565b6040518082815260200191505060405180910390f35b60006000600190508060ff16600181151560a057fe5b0460ff1691505b5090565b60006000600090508060ff16600181151560c157fe5b0460ff1691505b50905600a165627a7a7230582091585859014c4644d0427bf34abc65433b5874993ddea00cac57bcb87ee4cb6b0029")
|
||||||
|
|
||||||
|
|
@ -151,7 +151,7 @@ func TestTransactionReverted(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
var reverted bool
|
var failed bool
|
||||||
// deploy
|
// deploy
|
||||||
cfg := &Config{
|
cfg := &Config{
|
||||||
Origin: common.HexToAddress("sender"),
|
Origin: common.HexToAddress("sender"),
|
||||||
|
|
@ -160,58 +160,58 @@ func TestTransactionReverted(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_, _, reverted, _ = Execute(code, legalDivision, cfg)
|
_, _, failed, _ = Execute(code, legalDivision, cfg)
|
||||||
if reverted != false {
|
if failed != false {
|
||||||
t.Fatal("Expect false, got true")
|
t.Fatal("Expect false, got true")
|
||||||
}
|
}
|
||||||
_, _, reverted, _ = Execute(code, illegalDivision, cfg)
|
_, _, failed, _ = Execute(code, illegalDivision, cfg)
|
||||||
if reverted != true {
|
if failed != true {
|
||||||
t.Fatal("Expect true, got false")
|
t.Fatal("Expect true, got false")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDelegateReverted(t *testing.T) {
|
func TestDelegateReverted(t *testing.T) {
|
||||||
/*
|
/*
|
||||||
Contract Source Code
|
Contract Source Code
|
||||||
```
|
```
|
||||||
contract Relay {
|
contract Relay {
|
||||||
address public currentVersion;
|
address public currentVersion;
|
||||||
address public owner;
|
address public owner;
|
||||||
|
|
||||||
modifier onlyOwner() {
|
modifier onlyOwner() {
|
||||||
if (msg.sender != owner) {
|
if (msg.sender != owner) {
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
_;
|
_;
|
||||||
}
|
}
|
||||||
function Relay(address _address) {
|
function Relay(address _address) {
|
||||||
currentVersion = _address;
|
currentVersion = _address;
|
||||||
owner = msg.sender;
|
owner = msg.sender;
|
||||||
}
|
}
|
||||||
function changeContract(address newVersion) public
|
function changeContract(address newVersion) public
|
||||||
onlyOwner()
|
onlyOwner()
|
||||||
{
|
{
|
||||||
currentVersion = newVersion;
|
currentVersion = newVersion;
|
||||||
}
|
}
|
||||||
function() {
|
function() {
|
||||||
if(!currentVersion.delegatecall(msg.data)) throw;
|
if(!currentVersion.delegatecall(msg.data)) throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contract Demo {
|
contract Demo {
|
||||||
function Demo() {
|
function Demo() {
|
||||||
}
|
}
|
||||||
function IllegalDivision() returns(int) {
|
function IllegalDivision() returns(int) {
|
||||||
var dividend = 0;
|
var dividend = 0;
|
||||||
return 1 / dividend;
|
return 1 / dividend;
|
||||||
}
|
}
|
||||||
function LegalDivision() returns(int) {
|
function LegalDivision() returns(int) {
|
||||||
var dividend = 1;
|
var dividend = 1;
|
||||||
return 1 / dividend;
|
return 1 / dividend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
var definition = `[{"constant":false,"inputs":[],"name":"LegalDivision","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"IllegalDivision","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}]`
|
var definition = `[{"constant":false,"inputs":[],"name":"LegalDivision","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"IllegalDivision","outputs":[{"name":"","type":"int256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"}]`
|
||||||
var rawcode1 = common.Hex2Bytes("6060604052341561000c57fe5b5b5b5b60f88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632d256662146044578063522de105146067575bfe5b3415604b57fe5b6051608a565b6040518082815260200191505060405180910390f35b3415606e57fe5b607460ab565b6040518082815260200191505060405180910390f35b60006000600190508060ff16600181151560a057fe5b0460ff1691505b5090565b60006000600090508060ff16600181151560c157fe5b0460ff1691505b50905600a165627a7a7230582091585859014c4644d0427bf34abc65433b5874993ddea00cac57bcb87ee4cb6b0029")
|
var rawcode1 = common.Hex2Bytes("6060604052341561000c57fe5b5b5b5b60f88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632d256662146044578063522de105146067575bfe5b3415604b57fe5b6051608a565b6040518082815260200191505060405180910390f35b3415606e57fe5b607460ab565b6040518082815260200191505060405180910390f35b60006000600190508060ff16600181151560a057fe5b0460ff1691505b5090565b60006000600090508060ff16600181151560c157fe5b0460ff1691505b50905600a165627a7a7230582091585859014c4644d0427bf34abc65433b5874993ddea00cac57bcb87ee4cb6b0029")
|
||||||
var rawcode2 = common.Hex2Bytes("6060604052341561000c57fe5b60405160208061039c833981016040528080519060200190919050505b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505b6102df806100bd6000396000f30060606040523615610055576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633d71c3af146100ea5780638da5cb5b146101205780639d888e8614610172575b341561005d57fe5b6100e85b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600036600060405160200152604051808383808284378201915050925050506020604051808303818560325a03f415156100d057fe5b50506040518051905015156100e55760006000fd5b5b565b005b34156100f257fe5b61011e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101c4565b005b341561012857fe5b610130610267565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561017a57fe5b61018261028d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102215760006000fd5b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a723058208496aa0ef6d67e2e0423b76e8fd61b92e0047fe2e20ad20f887caf2b378dfa300029")
|
var rawcode2 = common.Hex2Bytes("6060604052341561000c57fe5b60405160208061039c833981016040528080519060200190919050505b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505b6102df806100bd6000396000f30060606040523615610055576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633d71c3af146100ea5780638da5cb5b146101205780639d888e8614610172575b341561005d57fe5b6100e85b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600036600060405160200152604051808383808284378201915050925050506020604051808303818560325a03f415156100d057fe5b50506040518051905015156100e55760006000fd5b5b565b005b34156100f257fe5b61011e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101c4565b005b341561012857fe5b610130610267565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561017a57fe5b61018261028d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102215760006000fd5b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a723058208496aa0ef6d67e2e0423b76e8fd61b92e0047fe2e20ad20f887caf2b378dfa300029")
|
||||||
|
|
@ -230,7 +230,7 @@ func TestDelegateReverted(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
var reverted bool
|
var failed bool
|
||||||
// deploy
|
// deploy
|
||||||
cfg := &Config{
|
cfg := &Config{
|
||||||
Origin: common.HexToAddress("sender"),
|
Origin: common.HexToAddress("sender"),
|
||||||
|
|
@ -244,12 +244,12 @@ func TestDelegateReverted(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_, _, reverted, _ = Call(addr2, legalDivision, cfg)
|
_, _, failed, _ = Call(addr2, legalDivision, cfg)
|
||||||
if reverted != false {
|
if failed != false {
|
||||||
t.Fatal("Expect false, got true")
|
t.Fatal("Expect false, got true")
|
||||||
}
|
}
|
||||||
_, _, reverted, _ = Call(addr2, illegalDivision, cfg)
|
_, _, failed, _ = Call(addr2, illegalDivision, cfg)
|
||||||
if reverted != true {
|
if failed != true {
|
||||||
t.Fatal("Expect true, got false")
|
t.Fatal("Expect true, got false")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -543,7 +543,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.
|
||||||
|
|
||||||
// Run the transaction with tracing enabled.
|
// Run the transaction with tracing enabled.
|
||||||
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{Debug: true, Tracer: tracer})
|
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{Debug: true, Tracer: tracer})
|
||||||
ret, gas, reverted, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
|
ret, gas, failed, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tracing failed: %v", err)
|
return nil, fmt.Errorf("tracing failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -553,7 +553,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.
|
||||||
Gas: gas,
|
Gas: gas,
|
||||||
ReturnValue: fmt.Sprintf("%x", ret),
|
ReturnValue: fmt.Sprintf("%x", ret),
|
||||||
StructLogs: ethapi.FormatLogs(tracer.StructLogs()),
|
StructLogs: ethapi.FormatLogs(tracer.StructLogs()),
|
||||||
Reverted: reverted,
|
Failed: failed,
|
||||||
}, nil
|
}, nil
|
||||||
case *ethapi.JavascriptTracer:
|
case *ethapi.JavascriptTracer:
|
||||||
return tracer.GetResult()
|
return tracer.GetResult()
|
||||||
|
|
@ -591,7 +591,7 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int) (co
|
||||||
|
|
||||||
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{})
|
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(tx.Gas())
|
gp := new(core.GasPool).AddGas(tx.Gas())
|
||||||
_, _, _,err := core.ApplyMessage(vmenv, msg, gp)
|
_, _, _, err := core.ApplyMessage(vmenv, msg, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
|
return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -637,17 +637,17 @@ 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)
|
||||||
res, gas, _, err := core.ApplyMessage(evm, msg, gp)
|
res, gas, failed, 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -670,10 +670,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 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
|
||||||
}
|
}
|
||||||
|
|
@ -690,7 +690,7 @@ type ExecutionResult struct {
|
||||||
Gas *big.Int `json:"gas"`
|
Gas *big.Int `json:"gas"`
|
||||||
ReturnValue string `json:"returnValue"`
|
ReturnValue string `json:"returnValue"`
|
||||||
StructLogs []StructLogRes `json:"structLogs"`
|
StructLogs []StructLogRes `json:"structLogs"`
|
||||||
Reverted bool `json:"reverted"`
|
Failed bool `json:"failed"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
||||||
|
|
@ -1081,7 +1081,6 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[
|
||||||
"contractAddress": nil,
|
"contractAddress": nil,
|
||||||
"logs": receipt.Logs,
|
"logs": receipt.Logs,
|
||||||
"logsBloom": receipt.Bloom,
|
"logsBloom": receipt.Bloom,
|
||||||
"reverted": receipt.Reverted,
|
|
||||||
}
|
}
|
||||||
if receipt.Logs == nil {
|
if receipt.Logs == nil {
|
||||||
fields["logs"] = [][]*types.Log{}
|
fields["logs"] = [][]*types.Log{}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue