From 65a6cc2f1e87304cce49c1ab08dee2b9eb87adef Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 28 Jun 2017 10:32:31 +0800 Subject: [PATCH] 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. --- accounts/abi/bind/backends/simulated.go | 16 +-- core/state_processor.go | 3 +- core/state_transition.go | 12 +-- core/types/gen_receipt_json.go | 6 -- core/types/receipt.go | 9 +- core/vm/contract.go | 11 +-- core/vm/evm.go | 31 +++--- core/vm/instructions.go | 4 +- core/vm/runtime/runtime.go | 12 +-- core/vm/runtime/runtime_test.go | 126 ++++++++++++------------ eth/api.go | 6 +- internal/ethapi/api.go | 23 +++-- 12 files changed, 123 insertions(+), 136 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index de238be6c2..f0b5920420 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -167,7 +167,7 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM if err != nil { 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 } @@ -177,7 +177,7 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereu defer b.mu.Unlock() 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 } @@ -215,11 +215,11 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs call.Gas = new(big.Int).SetUint64(mid) 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) - // If the transaction became invalid or used all the gas (failed), raise the gas limit - if err != nil || gas.Cmp(call.Gas) == 0 { + // If the transaction became invalid or failed, raise the gas limit + if err != nil || failed { lo = mid 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. // 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. if call.GasPrice == nil { 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. vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) gaspool := new(core.GasPool).AddGas(math.MaxBig256) - ret, gasUsed, _, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() - return ret, gasUsed, err + ret, gasUsed, _, failed, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() + return ret, gasUsed, failed, err } // SendTransaction updates the pending block to include the given transaction. diff --git a/core/state_processor.go b/core/state_processor.go index e09771b8f7..9c6b69adf7 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -98,7 +98,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common // about the transaction and calling mechanisms. vmenv := vm.NewEVM(context, statedb, config, cfg) // 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 { return nil, nil, err } @@ -111,7 +111,6 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common receipt := types.NewReceipt(root.Bytes(), usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) - receipt.Reverted = reverted // if the transaction created a contract, store the creation address in the receipt. if msg.To() == nil { receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) diff --git a/core/state_transition.go b/core/state_transition.go index f64a0ca014..d8ed410403 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -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) { st := NewStateTransition(evm, msg, gp) - ret, _, gasUsed, reverted, err := st.TransitionDb() - return ret, gasUsed, reverted, err + ret, _, gasUsed, failed, err := st.TransitionDb() + return ret, gasUsed, failed, err } 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 // 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. -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 { return } @@ -236,11 +236,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big vmerr error ) 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 { // Increment the nonce for the next transaction 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 { log.Debug("VM returned with error", "err", vmerr) @@ -256,7 +256,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big st.refundGas() 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() { diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index ce6cc0e7a1..edbd64ba4e 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -20,7 +20,6 @@ func (r Receipt) MarshalJSON() ([]byte, error) { TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"` - Reverted bool `json:"reverted" gencode:"required"` } var enc Receipt enc.PostState = r.PostState @@ -30,7 +29,6 @@ func (r Receipt) MarshalJSON() ([]byte, error) { enc.TxHash = r.TxHash enc.ContractAddress = r.ContractAddress enc.GasUsed = (*hexutil.Big)(r.GasUsed) - enc.Reverted = r.Reverted return json.Marshal(&enc) } @@ -43,7 +41,6 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { TxHash *common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress *common.Address `json:"contractAddress"` GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"` - Reverted *bool `json:"reverted" gencode:"required"` } var dec Receipt 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") } r.GasUsed = (*big.Int)(dec.GasUsed) - if dec.Reverted != nil { - r.Reverted = *dec.Reverted - } return nil } diff --git a/core/types/receipt.go b/core/types/receipt.go index 598a37bdd9..ef6f6a2bb2 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -40,10 +40,6 @@ type Receipt struct { TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` 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 { @@ -95,7 +91,7 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { for i, log := range r.Logs { 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 @@ -109,7 +105,6 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { ContractAddress common.Address Logs []*LogForStorage GasUsed *big.Int - Reverted bool } if err := s.Decode(&receipt); err != nil { return err @@ -121,7 +116,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { r.Logs[i] = (*Log)(log) } // 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 } diff --git a/core/vm/contract.go b/core/vm/contract.go index 810a1a8b46..bfd62fa751 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -62,8 +62,7 @@ type Contract struct { Args []byte DelegateCall bool - Reverted bool // use to represent whether transaction is reverted during state transition - // child's reverted field changed will also affect parent. + Failed bool // Used to identify the execution status of the current transaction } // 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 } -// MarkReverted mark current transaction's execution has meet revert. -func (self *Contract) MarkReverted() { - self.Reverted = true +// MarkFailed mark current transaction's execution failed. +func (self *Contract) MarkFailed() { + self.Failed = true // affect parent recursively if parent, ok := self.caller.(*Contract); ok { - parent.MarkReverted() + parent.MarkFailed() } } diff --git a/core/vm/evm.go b/core/vm/evm.go index cdd916c1f1..3873d2d29c 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -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 // 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. -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 { 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. if err != nil { 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 @@ -200,7 +201,8 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, ret, err = run(evm, snapshot, contract, input) if err != nil { contract.UseGas(contract.Gas) - evm.Revert(snapshot, contract) + evm.StateDB.RevertToSnapshot(snapshot) + contract.MarkFailed() } 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) if err != nil { contract.UseGas(contract.Gas) - evm.Revert(snapshot, contract) + evm.StateDB.RevertToSnapshot(snapshot) + contract.MarkFailed() } return ret, contract.Gas, err } // 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 { 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 || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { 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. // 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 } - return ret, contractAddr, contract.Gas, contract.Reverted, err + return ret, contractAddr, contract.Gas, contract.Failed, err } // 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 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() -} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 12e43e83d0..6babf600c4 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -551,7 +551,7 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S } 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) // Push item on the stack based on the returned error. If the ruleset is // 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 { 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) if err != nil { stack.push(new(big.Int)) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 64409f53e7..b69df4d617 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -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. cfg.State.SetCode(address, code) // Call the code with the given configuration. - ret, _, reverted, err := vmenv.Call( + ret, _, failed, err := vmenv.Call( sender, common.StringToAddress("contract"), input, @@ -121,7 +121,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, bool, err cfg.Value, ) - return ret, cfg.State, reverted, err + return ret, cfg.State, failed, err } // 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. - code, address, leftOverGas, reverted, err := vmenv.Create( + code, address, leftOverGas, failed, err := vmenv.Create( sender, input, cfg.GasLimit, 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 @@ -162,7 +162,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, bo sender := cfg.State.GetOrNewStateObject(cfg.Origin) // Call the code with the given configuration. - ret, leftOverGas, reverted, err := vmenv.Call( + ret, leftOverGas, failed, err := vmenv.Call( sender, address, input, @@ -170,5 +170,5 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, bo cfg.Value, ) - return ret, leftOverGas, reverted, err + return ret, leftOverGas, failed, err } diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index dd6b658564..fbaad6c7cb 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -119,21 +119,21 @@ func TestCall(t *testing.T) { func TestTransactionReverted(t *testing.T) { /* - Contract Source Code - ``` - contract Demo { - function Demo() {} - function IllegalDivision() returns(int) { - var dividend = 0; - return 1 / dividend; - } - function LegalDivision() returns(int) { - var dividend = 1; - return 1 / dividend; - } - } - ``` - */ + Contract Source Code + ``` + contract Demo { + function Demo() {} + function IllegalDivision() returns(int) { + var dividend = 0; + return 1 / dividend; + } + function LegalDivision() returns(int) { + var dividend = 1; + 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 rawcode = common.Hex2Bytes("6060604052341561000c57fe5b5b5b5b60f88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632d256662146044578063522de105146067575bfe5b3415604b57fe5b6051608a565b6040518082815260200191505060405180910390f35b3415606e57fe5b607460ab565b6040518082815260200191505060405180910390f35b60006000600190508060ff16600181151560a057fe5b0460ff1691505b5090565b60006000600090508060ff16600181151560c157fe5b0460ff1691505b50905600a165627a7a7230582091585859014c4644d0427bf34abc65433b5874993ddea00cac57bcb87ee4cb6b0029") @@ -151,7 +151,7 @@ func TestTransactionReverted(t *testing.T) { if err != nil { t.Fatal(err) } - var reverted bool + var failed bool // deploy cfg := &Config{ Origin: common.HexToAddress("sender"), @@ -160,58 +160,58 @@ func TestTransactionReverted(t *testing.T) { if err != nil { t.Fatal(err) } - _, _, reverted, _ = Execute(code, legalDivision, cfg) - if reverted != false { + _, _, failed, _ = Execute(code, legalDivision, cfg) + if failed != false { t.Fatal("Expect false, got true") } - _, _, reverted, _ = Execute(code, illegalDivision, cfg) - if reverted != true { + _, _, failed, _ = Execute(code, illegalDivision, cfg) + if failed != true { t.Fatal("Expect true, got false") } } func TestDelegateReverted(t *testing.T) { /* - Contract Source Code - ``` - contract Relay { - address public currentVersion; - address public owner; + Contract Source Code + ``` + contract Relay { + address public currentVersion; + address public owner; - modifier onlyOwner() { - if (msg.sender != owner) { - throw; - } - _; - } - function Relay(address _address) { - currentVersion = _address; - owner = msg.sender; - } - function changeContract(address newVersion) public - onlyOwner() - { - currentVersion = newVersion; - } - function() { - if(!currentVersion.delegatecall(msg.data)) throw; - } - } + modifier onlyOwner() { + if (msg.sender != owner) { + throw; + } + _; + } + function Relay(address _address) { + currentVersion = _address; + owner = msg.sender; + } + function changeContract(address newVersion) public + onlyOwner() + { + currentVersion = newVersion; + } + function() { + if(!currentVersion.delegatecall(msg.data)) throw; + } + } - contract Demo { - function Demo() { - } - function IllegalDivision() returns(int) { - var dividend = 0; - return 1 / dividend; - } - function LegalDivision() returns(int) { - var dividend = 1; - return 1 / dividend; - } - } - ``` - */ + contract Demo { + function Demo() { + } + function IllegalDivision() returns(int) { + var dividend = 0; + return 1 / dividend; + } + function LegalDivision() returns(int) { + var dividend = 1; + 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 rawcode1 = common.Hex2Bytes("6060604052341561000c57fe5b5b5b5b60f88061001d6000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680632d256662146044578063522de105146067575bfe5b3415604b57fe5b6051608a565b6040518082815260200191505060405180910390f35b3415606e57fe5b607460ab565b6040518082815260200191505060405180910390f35b60006000600190508060ff16600181151560a057fe5b0460ff1691505b5090565b60006000600090508060ff16600181151560c157fe5b0460ff1691505b50905600a165627a7a7230582091585859014c4644d0427bf34abc65433b5874993ddea00cac57bcb87ee4cb6b0029") var rawcode2 = common.Hex2Bytes("6060604052341561000c57fe5b60405160208061039c833981016040528080519060200190919050505b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555033600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b505b6102df806100bd6000396000f30060606040523615610055576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633d71c3af146100ea5780638da5cb5b146101205780639d888e8614610172575b341561005d57fe5b6100e85b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600036600060405160200152604051808383808284378201915050925050506020604051808303818560325a03f415156100d057fe5b50506040518051905015156100e55760006000fd5b5b565b005b34156100f257fe5b61011e600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919050506101c4565b005b341561012857fe5b610130610267565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561017a57fe5b61018261028d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156102215760006000fd5b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b50565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a723058208496aa0ef6d67e2e0423b76e8fd61b92e0047fe2e20ad20f887caf2b378dfa300029") @@ -230,7 +230,7 @@ func TestDelegateReverted(t *testing.T) { if err != nil { t.Fatal(err) } - var reverted bool + var failed bool // deploy cfg := &Config{ Origin: common.HexToAddress("sender"), @@ -244,12 +244,12 @@ func TestDelegateReverted(t *testing.T) { if err != nil { t.Fatal(err) } - _, _, reverted, _ = Call(addr2, legalDivision, cfg) - if reverted != false { + _, _, failed, _ = Call(addr2, legalDivision, cfg) + if failed != false { t.Fatal("Expect false, got true") } - _, _, reverted, _ = Call(addr2, illegalDivision, cfg) - if reverted != true { + _, _, failed, _ = Call(addr2, illegalDivision, cfg) + if failed != true { t.Fatal("Expect true, got false") } } diff --git a/eth/api.go b/eth/api.go index d146e04335..145a4f4823 100644 --- a/eth/api.go +++ b/eth/api.go @@ -543,7 +543,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common. // Run the transaction with tracing enabled. 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 { return nil, fmt.Errorf("tracing failed: %v", err) } @@ -553,7 +553,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common. Gas: gas, ReturnValue: fmt.Sprintf("%x", ret), StructLogs: ethapi.FormatLogs(tracer.StructLogs()), - Reverted: reverted, + Failed: failed, }, nil case *ethapi.JavascriptTracer: 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{}) gp := new(core.GasPool).AddGas(tx.Gas()) - _, _, _,err := core.ApplyMessage(vmenv, msg, gp) + _, _, _, err := core.ApplyMessage(vmenv, msg, gp) if err != nil { return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 16347f35fd..c4de6d8b1d 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -580,12 +580,12 @@ type CallArgs struct { 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()) state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr) 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 addr := args.From @@ -623,7 +623,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // Get a new instance of the EVM. evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg) 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 // 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) // and apply the message. 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 { - 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. // 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) { - 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 } @@ -670,10 +670,10 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (* mid := (hi + lo) / 2 (*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 err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 { + // If the transaction became invalid or failed, raise the gas limit + if err != nil || failed { lo = mid continue } @@ -690,7 +690,7 @@ type ExecutionResult struct { Gas *big.Int `json:"gas"` ReturnValue string `json:"returnValue"` StructLogs []StructLogRes `json:"structLogs"` - Reverted bool `json:"reverted"` + Failed bool `json:"failed"` } // 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, "logs": receipt.Logs, "logsBloom": receipt.Bloom, - "reverted": receipt.Reverted, } if receipt.Logs == nil { fields["logs"] = [][]*types.Log{}