mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
Merge ceede2b6e9 into 431cf2a1e4
This commit is contained in:
commit
1e9a6cfefd
19 changed files with 227 additions and 57 deletions
|
|
@ -253,7 +253,7 @@ 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, _, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||||
return ret, gasUsed, err
|
return ret, gasUsed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -174,12 +174,12 @@ func runCmd(ctx *cli.Context) error {
|
||||||
var leftOverGas uint64
|
var leftOverGas uint64
|
||||||
if ctx.GlobalBool(CreateFlag.Name) {
|
if ctx.GlobalBool(CreateFlag.Name) {
|
||||||
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
|
input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...)
|
||||||
ret, _, leftOverGas, err = runtime.Create(input, &runtimeConfig)
|
ret, _, leftOverGas, _, err = runtime.Create(input, &runtimeConfig)
|
||||||
} else {
|
} else {
|
||||||
receiver := common.StringToAddress("receiver")
|
receiver := common.StringToAddress("receiver")
|
||||||
statedb.SetCode(receiver, code)
|
statedb.SetCode(receiver, code)
|
||||||
|
|
||||||
ret, leftOverGas, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig)
|
ret, leftOverGas, _, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtimeConfig)
|
||||||
}
|
}
|
||||||
execTime := time.Since(tstart)
|
execTime := time.Since(tstart)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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, err := ApplyMessage(vmenv, msg, gp)
|
_, gas, reverted, err := ApplyMessage(vmenv, msg, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -111,6 +111,7 @@ 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())
|
||||||
|
|
|
||||||
|
|
@ -127,11 +127,11 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
||||||
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
||||||
// indicates a core error meaning that the message would always fail for that particular
|
// indicates a core error meaning that the message would always fail for that particular
|
||||||
// state and would never be accepted within a block.
|
// state and would never be accepted within a block.
|
||||||
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, 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, err := st.TransitionDb()
|
ret, _, gasUsed, reverted, err := st.TransitionDb()
|
||||||
return ret, gasUsed, err
|
return ret, gasUsed, reverted, 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, err error) {
|
func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, reverted bool, err error) {
|
||||||
if err = st.preCheck(); err != nil {
|
if err = st.preCheck(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -222,10 +222,10 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
||||||
// TODO convert to uint64
|
// TODO convert to uint64
|
||||||
intrinsicGas := IntrinsicGas(st.data, contractCreation, homestead)
|
intrinsicGas := IntrinsicGas(st.data, contractCreation, homestead)
|
||||||
if intrinsicGas.BitLen() > 64 {
|
if intrinsicGas.BitLen() > 64 {
|
||||||
return nil, nil, nil, vm.ErrOutOfGas
|
return nil, nil, nil, false, vm.ErrOutOfGas
|
||||||
}
|
}
|
||||||
if err = st.useGas(intrinsicGas.Uint64()); err != nil {
|
if err = st.useGas(intrinsicGas.Uint64()); err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -236,11 +236,11 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
||||||
vmerr error
|
vmerr error
|
||||||
)
|
)
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value)
|
ret, _, st.gas, reverted, 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, vmerr = evm.Call(sender, st.to().Address(), st.data, st.gas, st.value)
|
ret, st.gas, reverted, 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)
|
||||||
|
|
@ -248,7 +248,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
||||||
// sufficient balance to make the transfer happen. The first
|
// sufficient balance to make the transfer happen. The first
|
||||||
// balance transfer may never fail.
|
// balance transfer may never fail.
|
||||||
if vmerr == vm.ErrInsufficientBalance {
|
if vmerr == vm.ErrInsufficientBalance {
|
||||||
return nil, nil, nil, vmerr
|
return nil, nil, nil, false, vmerr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requiredGas = new(big.Int).Set(st.gasUsed())
|
requiredGas = new(big.Int).Set(st.gasUsed())
|
||||||
|
|
@ -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(), err
|
return ret, requiredGas, st.gasUsed(), reverted, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) refundGas() {
|
func (st *StateTransition) refundGas() {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ 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
|
||||||
|
|
@ -29,6 +30,7 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,6 +43,7 @@ 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 {
|
||||||
|
|
@ -73,5 +76,8 @@ 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,6 +40,10 @@ 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 {
|
||||||
|
|
@ -91,7 +95,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})
|
return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed, r.Reverted})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
|
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
|
||||||
|
|
@ -105,6 +109,7 @@ 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
|
||||||
|
|
@ -116,7 +121,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 = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed
|
r.TxHash, r.ContractAddress, r.GasUsed, r.Reverted = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed, receipt.Reverted
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ type Contract struct {
|
||||||
Args []byte
|
Args []byte
|
||||||
|
|
||||||
DelegateCall bool
|
DelegateCall bool
|
||||||
|
Reverted bool // use to represent whether transaction is reverted during state transition
|
||||||
|
// 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.
|
||||||
|
|
@ -151,3 +153,12 @@ func (self *Contract) SetCallCode(addr *common.Address, hash common.Hash, code [
|
||||||
self.CodeHash = hash
|
self.CodeHash = hash
|
||||||
self.CodeAddr = addr
|
self.CodeAddr = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkReverted mark current transaction's execution has meet revert.
|
||||||
|
func (self *Contract) MarkReverted() {
|
||||||
|
self.Reverted = true
|
||||||
|
// affect parent recursively
|
||||||
|
if parent, ok := self.caller.(*Contract); ok {
|
||||||
|
parent.MarkReverted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,18 +124,18 @@ 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, err error) {
|
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, reverted bool, err error) {
|
||||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
return nil, gas, nil
|
return nil, gas, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, gas, ErrDepth
|
return nil, gas, false, ErrDepth
|
||||||
}
|
}
|
||||||
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
return nil, gas, ErrInsufficientBalance
|
return nil, gas, false, ErrInsufficientBalance
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -144,7 +144,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
||||||
)
|
)
|
||||||
if !evm.StateDB.Exist(addr) {
|
if !evm.StateDB.Exist(addr) {
|
||||||
if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
|
if PrecompiledContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 {
|
||||||
return nil, gas, nil
|
return nil, gas, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
evm.StateDB.CreateAccount(addr)
|
evm.StateDB.CreateAccount(addr)
|
||||||
|
|
@ -163,9 +163,9 @@ 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.StateDB.RevertToSnapshot(snapshot)
|
evm.Revert(snapshot, contract)
|
||||||
}
|
}
|
||||||
return ret, contract.Gas, err
|
return ret, contract.Gas, contract.Reverted, 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 +200,7 @@ 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.StateDB.RevertToSnapshot(snapshot)
|
evm.Revert(snapshot, contract)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, contract.Gas, err
|
return ret, contract.Gas, err
|
||||||
|
|
@ -234,25 +234,25 @@ 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.StateDB.RevertToSnapshot(snapshot)
|
evm.Revert(snapshot, contract)
|
||||||
}
|
}
|
||||||
|
|
||||||
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, err error) {
|
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, reverted bool, err error) {
|
||||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
return nil, common.Address{}, gas, nil
|
return nil, common.Address{}, gas, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if evm.depth > int(params.CallCreateDepth) {
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
return nil, common.Address{}, gas, ErrDepth
|
return nil, common.Address{}, gas, false, ErrDepth
|
||||||
}
|
}
|
||||||
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
|
if !evm.CanTransfer(evm.StateDB, caller.Address(), value) {
|
||||||
return nil, common.Address{}, gas, ErrInsufficientBalance
|
return nil, common.Address{}, gas, false, ErrInsufficientBalance
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new account on the state
|
// Create a new account on the state
|
||||||
|
|
@ -295,7 +295,7 @@ 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.StateDB.RevertToSnapshot(snapshot)
|
evm.Revert(snapshot, contract)
|
||||||
}
|
}
|
||||||
// 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 +304,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||||
ret = nil
|
ret = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, contractAddr, contract.Gas, err
|
return ret, contractAddr, contract.Gas, contract.Reverted, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChainConfig returns the evmironment's chain configuration
|
// ChainConfig returns the evmironment's chain configuration
|
||||||
|
|
@ -312,3 +312,10 @@ 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,8 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
||||||
}
|
}
|
||||||
|
|
||||||
contract.UseGas(gas)
|
contract.UseGas(gas)
|
||||||
_, addr, returnGas, suberr := evm.Create(contract, input, gas, value)
|
// ignore reverted here since it is only useful in vm entry.
|
||||||
|
_, 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
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
|
|
@ -588,8 +589,8 @@ 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.
|
||||||
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))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ package runtime
|
||||||
// This returns 1 for valid parsable/runable code, 0
|
// This returns 1 for valid parsable/runable code, 0
|
||||||
// for invalid opcode.
|
// for invalid opcode.
|
||||||
func Fuzz(input []byte) int {
|
func Fuzz(input []byte) int {
|
||||||
_, _, err := Execute(input, input, &Config{
|
_, _, _, err := Execute(input, input, &Config{
|
||||||
GasLimit: 3000000,
|
GasLimit: 3000000,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ func setDefaults(cfg *Config) {
|
||||||
// Executes sets up a in memory, temporarily, environment for the execution of
|
// Executes sets up a in memory, temporarily, environment for the execution of
|
||||||
// the given code. It enabled the JIT by default and make sure that it's restored
|
// the given code. It enabled the JIT by default and make sure that it's restored
|
||||||
// to it's original state afterwards.
|
// to it's original state afterwards.
|
||||||
func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, bool, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
cfg = new(Config)
|
cfg = new(Config)
|
||||||
}
|
}
|
||||||
|
|
@ -113,7 +113,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
||||||
// 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, _, err := vmenv.Call(
|
ret, _, reverted, err := vmenv.Call(
|
||||||
sender,
|
sender,
|
||||||
common.StringToAddress("contract"),
|
common.StringToAddress("contract"),
|
||||||
input,
|
input,
|
||||||
|
|
@ -121,11 +121,11 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
||||||
cfg.Value,
|
cfg.Value,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ret, cfg.State, err
|
return ret, cfg.State, reverted, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create executes the code using the EVM create method
|
// Create executes the code using the EVM create method
|
||||||
func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, bool, error) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
cfg = new(Config)
|
cfg = new(Config)
|
||||||
}
|
}
|
||||||
|
|
@ -141,13 +141,13 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Call the code with the given configuration.
|
// Call the code with the given configuration.
|
||||||
code, address, leftOverGas, err := vmenv.Create(
|
code, address, leftOverGas, reverted, err := vmenv.Create(
|
||||||
sender,
|
sender,
|
||||||
input,
|
input,
|
||||||
cfg.GasLimit,
|
cfg.GasLimit,
|
||||||
cfg.Value,
|
cfg.Value,
|
||||||
)
|
)
|
||||||
return code, address, leftOverGas, err
|
return code, address, leftOverGas, reverted, 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
|
||||||
|
|
@ -155,14 +155,14 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
||||||
//
|
//
|
||||||
// Call, unlike Execute, requires a config and also requires the State field to
|
// Call, unlike Execute, requires a config and also requires the State field to
|
||||||
// be set.
|
// be set.
|
||||||
func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {
|
func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, bool, error) {
|
||||||
setDefaults(cfg)
|
setDefaults(cfg)
|
||||||
|
|
||||||
vmenv := NewEnv(cfg, cfg.State)
|
vmenv := NewEnv(cfg, cfg.State)
|
||||||
|
|
||||||
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, err := vmenv.Call(
|
ret, leftOverGas, reverted, err := vmenv.Call(
|
||||||
sender,
|
sender,
|
||||||
address,
|
address,
|
||||||
input,
|
input,
|
||||||
|
|
@ -170,5 +170,5 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
|
||||||
cfg.Value,
|
cfg.Value,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ret, leftOverGas, err
|
return ret, leftOverGas, reverted, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ExampleExecute() {
|
func ExampleExecute() {
|
||||||
ret, _, err := runtime.Execute(common.Hex2Bytes("6060604052600a8060106000396000f360606040526008565b00"), nil, nil)
|
ret, _, _, err := runtime.Execute(common.Hex2Bytes("6060604052600a8060106000396000f360606040526008565b00"), nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ func TestEVM(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExecute(t *testing.T) {
|
func TestExecute(t *testing.T) {
|
||||||
ret, _, err := Execute([]byte{
|
ret, _, _, err := Execute([]byte{
|
||||||
byte(vm.PUSH1), 10,
|
byte(vm.PUSH1), 10,
|
||||||
byte(vm.PUSH1), 0,
|
byte(vm.PUSH1), 0,
|
||||||
byte(vm.MSTORE),
|
byte(vm.MSTORE),
|
||||||
|
|
@ -106,7 +106,7 @@ func TestCall(t *testing.T) {
|
||||||
byte(vm.RETURN),
|
byte(vm.RETURN),
|
||||||
})
|
})
|
||||||
|
|
||||||
ret, _, err := Call(address, nil, &Config{State: state})
|
ret, _, _, err := Call(address, nil, &Config{State: state})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("didn't expect error", err)
|
t.Fatal("didn't expect error", err)
|
||||||
}
|
}
|
||||||
|
|
@ -117,6 +117,143 @@ 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
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")
|
||||||
|
|
||||||
|
abi, err := abi.JSON(strings.NewReader(definition))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
legalDivision, err := abi.Pack("LegalDivision")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
illegalDivision, err := abi.Pack("IllegalDivision")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var reverted bool
|
||||||
|
// deploy
|
||||||
|
cfg := &Config{
|
||||||
|
Origin: common.HexToAddress("sender"),
|
||||||
|
}
|
||||||
|
code, _, _, _, err := Create(rawcode, cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, _, reverted, _ = Execute(code, legalDivision, cfg)
|
||||||
|
if reverted != false {
|
||||||
|
t.Fatal("Expect false, got true")
|
||||||
|
}
|
||||||
|
_, _, reverted, _ = Execute(code, illegalDivision, cfg)
|
||||||
|
if reverted != true {
|
||||||
|
t.Fatal("Expect true, got false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelegateReverted(t *testing.T) {
|
||||||
|
/*
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
abi, err := abi.JSON(strings.NewReader(definition))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
legalDivision, err := abi.Pack("LegalDivision")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
illegalDivision, err := abi.Pack("IllegalDivision")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var reverted bool
|
||||||
|
// deploy
|
||||||
|
cfg := &Config{
|
||||||
|
Origin: common.HexToAddress("sender"),
|
||||||
|
}
|
||||||
|
_, addr, _, _, err := Create(rawcode1, cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, addr2, _, _, err := Create(append(rawcode2, common.LeftPadBytes(addr.Bytes(), 32)...), cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, _, reverted, _ = Call(addr2, legalDivision, cfg)
|
||||||
|
if reverted != false {
|
||||||
|
t.Fatal("Expect false, got true")
|
||||||
|
}
|
||||||
|
_, _, reverted, _ = Call(addr2, illegalDivision, cfg)
|
||||||
|
if reverted != true {
|
||||||
|
t.Fatal("Expect true, got false")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkCall(b *testing.B) {
|
func BenchmarkCall(b *testing.B) {
|
||||||
var definition = `[{"constant":true,"inputs":[],"name":"seller","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"abort","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"buyer","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmReceived","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmPurchase","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[],"name":"Aborted","type":"event"},{"anonymous":false,"inputs":[],"name":"PurchaseConfirmed","type":"event"},{"anonymous":false,"inputs":[],"name":"ItemReceived","type":"event"},{"anonymous":false,"inputs":[],"name":"Refunded","type":"event"}]`
|
var definition = `[{"constant":true,"inputs":[],"name":"seller","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"abort","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"type":"function"},{"constant":false,"inputs":[],"name":"refund","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"buyer","outputs":[{"name":"","type":"address"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmReceived","outputs":[],"type":"function"},{"constant":true,"inputs":[],"name":"state","outputs":[{"name":"","type":"uint8"}],"type":"function"},{"constant":false,"inputs":[],"name":"confirmPurchase","outputs":[],"type":"function"},{"inputs":[],"type":"constructor"},{"anonymous":false,"inputs":[],"name":"Aborted","type":"event"},{"anonymous":false,"inputs":[],"name":"PurchaseConfirmed","type":"event"},{"anonymous":false,"inputs":[],"name":"ItemReceived","type":"event"},{"anonymous":false,"inputs":[],"name":"Refunded","type":"event"}]`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
|
ret, gas, reverted, 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,6 +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,
|
||||||
}, nil
|
}, nil
|
||||||
case *ethapi.JavascriptTracer:
|
case *ethapi.JavascriptTracer:
|
||||||
return tracer.GetResult()
|
return tracer.GetResult()
|
||||||
|
|
@ -590,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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -643,7 +643,7 @@ 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, _, 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, err
|
||||||
}
|
}
|
||||||
|
|
@ -696,6 +696,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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
||||||
|
|
@ -1089,6 +1090,7 @@ 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{}
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
||||||
|
|
||||||
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
|
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
res = append(res, ret...)
|
res = append(res, ret...)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -146,7 +146,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
||||||
|
|
||||||
//vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{})
|
//vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
if vmstate.Error() == nil {
|
if vmstate.Error() == nil {
|
||||||
res = append(res, ret...)
|
res = append(res, ret...)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
||||||
vmenv := vm.NewEVM(context, statedb, config, vm.Config{})
|
vmenv := vm.NewEVM(context, statedb, config, vm.Config{})
|
||||||
|
|
||||||
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
res = append(res, ret...)
|
res = append(res, ret...)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -194,7 +194,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
||||||
context := core.NewEVMContext(msg, header, lc, nil)
|
context := core.NewEVMContext(msg, header, lc, nil)
|
||||||
vmenv := vm.NewEVM(context, vmstate, config, vm.Config{})
|
vmenv := vm.NewEVM(context, vmstate, config, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
if vmstate.Error() == nil {
|
if vmstate.Error() == nil {
|
||||||
res = append(res, ret...)
|
res = append(res, ret...)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,8 +212,7 @@ func RunState(chainConfig *params.ChainConfig, statedb *state.StateDB, env, tx m
|
||||||
statedb.Reset(root)
|
statedb.Reset(root)
|
||||||
|
|
||||||
snapshot := statedb.Snapshot()
|
snapshot := statedb.Snapshot()
|
||||||
|
ret, gasUsed, _, err := core.ApplyMessage(environment, msg, gaspool)
|
||||||
ret, gasUsed, err := core.ApplyMessage(environment, msg, gaspool)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,6 @@ func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*type
|
||||||
vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
|
vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract)
|
||||||
|
|
||||||
environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec)
|
environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec)
|
||||||
ret, g, err := environment.Call(caller, to, data, gas.Uint64(), value)
|
ret, g, _, err := environment.Call(caller, to, data, gas.Uint64(), value)
|
||||||
return ret, statedb.Logs(), new(big.Int).SetUint64(g), err
|
return ret, statedb.Logs(), new(big.Int).SetUint64(g), err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue