diff --git a/cmd/evm/main.go b/cmd/evm/main.go index dc441fabb..468b8b043 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -292,6 +292,10 @@ func (self *VMEnv) DelegateCall(caller vm.ContractRef, addr common.Address, data return core.DelegateCall(self, caller, addr, data, gas, price) } +func (self *VMEnv) StaticCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { + return core.StaticCall(self, caller, addr, data, gas, price) +} + func (self *VMEnv) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { return core.Create(self, caller, data, gas, price, value) } diff --git a/core/execution.go b/core/execution.go index 7dbe6421c..31bc2c03d 100644 --- a/core/execution.go +++ b/core/execution.go @@ -35,14 +35,14 @@ var ( // Call executes within the given contract func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { - ret, _, err = exec(env, caller, &addr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value) + ret, _, err = exec(env, caller, &addr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value, false) return ret, err } // CallCode executes the given address' code as the given contract address func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) { callerAddr := caller.Address() - ret, _, err = exec(env, caller, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value) + ret, _, err = exec(env, caller, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value, false) return ret, err } @@ -55,9 +55,15 @@ func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address return ret, err } +// StaticCall executes within the given contract and throws exception if state is attempted to be changed +func StaticCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) { + ret, _, err = exec(env, caller, &addr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, new(big.Int), true) + return ret, err +} + // Create creates a new contract with the given code func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) { - ret, address, err = exec(env, caller, nil, nil, crypto.Keccak256Hash(code), nil, code, gas, gasPrice, value) + ret, address, err = exec(env, caller, nil, nil, crypto.Keccak256Hash(code), nil, code, gas, gasPrice, value, false) // Here we get an error if we run into maximum stack depth, // See: https://github.com/ethereum/yellowpaper/pull/131 // and YP definitions for CREATE @@ -69,7 +75,7 @@ func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPric return ret, address, err } -func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) { +func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int, readOnly bool) (ret []byte, addr common.Address, err error) { evm := env.Vm() // Depth check execution. Fail if we're trying to execute above the // limit. @@ -129,7 +135,7 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A contract.SetCallCode(codeAddr, codeHash, code) defer contract.Finalise() - ret, err = evm.Run(contract, input) + ret, err = evm.Run(contract, input, readOnly) maxCodeSizeExceeded := len(ret) > maxCodeSize && env.RuleSet().IsAtlantis(env.BlockNumber()) // if the contract creation ran successfully and no errors were returned @@ -188,7 +194,7 @@ func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toA contract.SetCallCode(codeAddr, codeHash, code) defer contract.Finalise() - ret, err = evm.Run(contract, input) + ret, err = evm.Run(contract, input, false) if err != nil { env.RevertToSnapshot(snapshot) diff --git a/core/vm/environment.go b/core/vm/environment.go index 5dd452a28..0c9722778 100644 --- a/core/vm/environment.go +++ b/core/vm/environment.go @@ -79,6 +79,8 @@ type Environment interface { CallCode(me ContractRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) // Same as CallCode except sender and value is propagated from parent to child scope DelegateCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) + // Call another contract and disallow any state changing operations + StaticCall(me ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) // Create a new contract Create(me ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) } @@ -88,7 +90,7 @@ type Vm interface { // Run should execute the given contract with the input given in in // and return the contract execution return bytes or an error if it // failed. - Run(c *Contract, in []byte) ([]byte, error) + Run(c *Contract, in []byte, readOnly bool) ([]byte, error) } // Database is a EVM database for full state querying. diff --git a/core/vm/gas.go b/core/vm/gas.go index 8e2d37f84..647b67144 100644 --- a/core/vm/gas.go +++ b/core/vm/gas.go @@ -182,6 +182,7 @@ var _baseCheck = map[OpCode]req{ CALL: {7, new(big.Int), 1}, CALLCODE: {7, new(big.Int), 1}, DELEGATECALL: {6, new(big.Int), 1}, + STATICCALL: {6, new(big.Int), 1}, REVERT: {2, new(big.Int), 0}, RETURNDATACOPY: {3, new(big.Int), 0}, SUICIDE: {1, new(big.Int), 0}, diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 81e2ecabb..6340709f9 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -42,6 +42,7 @@ type instruction struct { } var ( + errWriteProtection = errors.New("evm: write protection") errReturnDataOutOfBounds = errors.New("evm: return data out of bounds") errInvalidJump = errors.New("evm: invalid jump destination") ) @@ -605,6 +606,23 @@ func opDelegateCall(pc *uint64, env Environment, contract *Contract, memory *Mem return ret, nil } +func opStaticCall(pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) ([]byte, error) { + gas, addr, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + + toAddr := common.BigToAddress(addr) + args := memory.Get(inOffset.Int64(), inSize.Int64()) + ret, err := env.StaticCall(contract, toAddr, args, gas, contract.Price) + if err != nil { + stack.push(new(big.Int)) + } else { + stack.push(big.NewInt(1)) + } + if err == nil || err == ErrRevert { + memory.Set(outOffset.Uint64(), outSize.Uint64(), ret) + } + return ret, nil +} + func opReturn(pc *uint64, env Environment, contract *Contract, memory *Memory, stack *stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index ae060a362..7b0c35a31 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -26,6 +26,7 @@ type jumpPtr struct { halts bool // indicates whether the operation should halt further execution reverts bool // determines whether the operation reverts state (implicitly halts) returns bool // Indicates whether return data should be overwritten + writes bool // determines whether this a state modifying operation } type vmJumpTable [256]jumpPtr @@ -58,6 +59,11 @@ func newJumpTable(ruleset RuleSet, blockNumber *big.Int) vmJumpTable { fn: opReturnDataCopy, valid: true, } + jumpTable[STATICCALL] = jumpPtr{ + fn: opStaticCall, + valid: true, + returns: true, + } } return jumpTable @@ -254,8 +260,9 @@ func newFrontierInstructionSet() vmJumpTable { valid: true, }, SSTORE: { - fn: opSstore, - valid: true, + fn: opSstore, + valid: true, + writes: true, }, JUMPDEST: { fn: opJumpdest, @@ -276,6 +283,7 @@ func newFrontierInstructionSet() vmJumpTable { CREATE: { fn: opCreate, valid: true, + writes: true, returns: true, }, CALL: { @@ -289,24 +297,29 @@ func newFrontierInstructionSet() vmJumpTable { returns: true, }, LOG0: { - fn: makeLog(0), - valid: true, + fn: makeLog(0), + valid: true, + writes: true, }, LOG1: { - fn: makeLog(1), - valid: true, + fn: makeLog(1), + valid: true, + writes: true, }, LOG2: { - fn: makeLog(2), - valid: true, + fn: makeLog(2), + valid: true, + writes: true, }, LOG3: { - fn: makeLog(3), - valid: true, + fn: makeLog(3), + valid: true, + writes: true, }, LOG4: { - fn: makeLog(4), - valid: true, + fn: makeLog(4), + valid: true, + writes: true, }, SWAP1: { fn: makeSwap(1), @@ -570,9 +583,10 @@ func newFrontierInstructionSet() vmJumpTable { halts: true, }, SUICIDE: { - fn: opSuicide, - valid: true, - halts: true, + fn: opSuicide, + valid: true, + halts: true, + writes: true, }, JUMP: { fn: opJump, diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 68e258074..d24de1e34 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -203,6 +203,7 @@ const ( CALLCODE RETURN DELEGATECALL + STATICCALL = 0xfa REVERT = 0xfd SUICIDE = 0xff @@ -360,6 +361,7 @@ var opCodeToString = map[OpCode]string{ RETURN: "RETURN", CALLCODE: "CALLCODE", DELEGATECALL: "DELEGATECALL", + STATICCALL: "STATICCALL", REVERT: "REVERT", SUICIDE: "SUICIDE", @@ -509,6 +511,7 @@ var stringToOp = map[string]OpCode{ "CALL": CALL, "RETURN": RETURN, "CALLCODE": CALLCODE, + "STATICCALL": STATICCALL, "REVERT": REVERT, "SUICIDE": SUICIDE, } diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 604091077..0db154f64 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -108,6 +108,10 @@ func (self *Env) DelegateCall(me vm.ContractRef, addr common.Address, data []byt return core.DelegateCall(self, me, addr, data, gas, price) } +func (self *Env) StaticCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { + return core.StaticCall(self, me, addr, data, gas, price) +} + func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { return core.Create(self, caller, data, gas, price, value) } diff --git a/core/vm/vm.go b/core/vm/vm.go index dd21e78ee..0c7fae6f1 100644 --- a/core/vm/vm.go +++ b/core/vm/vm.go @@ -47,6 +47,7 @@ type EVM struct { env Environment jumpTable vmJumpTable gasTable GasTable + readOnly bool } // New returns a new instance of the EVM. @@ -59,10 +60,17 @@ func New(env Environment) *EVM { } // Run loops and evaluates the contract's code with the given input data -func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { +func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { evm.env.SetDepth(evm.env.Depth() + 1) defer evm.env.SetDepth(evm.env.Depth() - 1) + // Make sure the readOnly is only set if we aren't in readOnly yet. + // This makes also sure that the readOnly flag isn't removed for child calls. + if readOnly && !evm.readOnly { + evm.readOnly = true + defer func() { evm.readOnly = false }() + } + // Reset the previous call's return data. It's unimportant to preserve the old buffer // as every returning call will return new data anyway. evm.env.SetReturnData(nil) @@ -94,6 +102,8 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { caller = contract.caller instrCount = 0 + isAtlantis = evm.env.RuleSet().IsAtlantis(evm.env.BlockNumber()) + op OpCode // current opcode mem = NewMemory() // bound memory stack = newstack() // local stack @@ -118,12 +128,25 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { for ; ; instrCount++ { // Get the memory location of pc op = contract.GetOp(pc) + operation := evm.jumpTable[op] // calculate the new memory size and gas price for the current executing opcode newMemSize, cost, err = calculateGasAndSize(&evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack) if err != nil { return nil, err } + // If the operation is valid, enforce and write restrictions + if evm.readOnly && isAtlantis { + // If the interpreter is operating in readonly mode, make sure no + // state-modifying operation is performed. The 3rd stack item + // for a call operation is the value. Transferring value from one + // account to the others means the state is modified and should also + // return with an error. + if operation.writes || (op == CALL && stack.back(2).Sign() != 0) { + return nil, errWriteProtection + } + } + // Use the calculated gas. When insufficient gas is present, use all gas and return an // Out Of Gas error if !contract.UseGas(cost) { @@ -132,7 +155,6 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) { // Resize the memory calculated previously mem.Resize(newMemSize.Uint64()) - operation := evm.jumpTable[op] if !operation.valid { return nil, fmt.Errorf("Invalid opcode %x", op) } @@ -365,7 +387,24 @@ func calculateGasAndSize(gasTable *GasTable, env Environment, contract *Contract // called. stack.data[stack.len()-1] = cg gas.Add(gas, cg) + case STATICCALL: + gas.Set(gasTable.Calls) + + x := calcMemSize(stack.back(4), stack.back(5)) + y := calcMemSize(stack.back(2), stack.back(3)) + newMemSize = common.BigMax(x, y) + + quadMemGas(mem, newMemSize, gas) + + cg := callGas(gasTable, contract.Gas, gas, stack.back(0)) + // Replace the stack item with the new gas calculation. This means that + // either the original item is left on the stack or the item is replaced by: + // (availableGas - gas) * 63 / 64 + // We replace the stack item so that it's available when the opCall instruction is + // called. + stack.data[stack.len()-1] = cg + gas.Add(gas, cg) } return newMemSize, gas, nil diff --git a/core/vm_env.go b/core/vm_env.go index 8b1a9eefe..295633008 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -115,6 +115,10 @@ func (self *VMEnv) DelegateCall(me vm.ContractRef, addr common.Address, data []b return DelegateCall(self, me, addr, data, gas, price) } +func (self *VMEnv) StaticCall(me vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { + return StaticCall(self, me, addr, data, gas, price) +} + func (self *VMEnv) Create(me vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { return Create(self, me, data, gas, price, value) } diff --git a/go.sum b/go.sum index aad61204b..f8f22ac4b 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/eth-classic/benchmark v0.0.0-20190401191651-0f5bf26f7cd8/go.mod h1:/H github.com/eth-classic/ethash v0.0.0-20190401191819-b3fdb17512de h1:pITmUG7+V+zKZuytaz1p92qJafw5tQDOdp5ir5L9Eic= github.com/eth-classic/ethash v0.0.0-20190401191819-b3fdb17512de/go.mod h1:W/nJfwtfsIfe4wL6cn4/MB251HfunQ+2YspZFvQ1lXA= github.com/eth-classic/go-ethereum v0.0.0-20190521151733-61b178b4deeb/go.mod h1:SE2Tm8M3TSoN2s9L1cJvCNQoY0mzUxV3Do8/nsNbrWQ= -github.com/eth-classic/go-ethereum/accounts/abi/bind v0.0.0-20190521151733-aaaa9d2e032a h1:YW6bRzag/8DZo3gNlpbhcpbUuZ77WdcOfvZl5SBYkRw= -github.com/eth-classic/go-ethereum/accounts/abi/bind v0.0.0-20190521151733-aaaa9d2e032a/go.mod h1:N45ToIEdDjjzHVQq1I7qeyg+X3Mz76sA5FdIaPwquGU= +github.com/eth-classic/go-ethereum/accounts/abi/bind v0.0.0-20190521151733-fe17e9e1e2ce h1:s4NMPGFYsBRX+LGJAFZP4HG6DzZMhvQ++H0/Y712pFw= +github.com/eth-classic/go-ethereum/accounts/abi/bind v0.0.0-20190521151733-fe17e9e1e2ce/go.mod h1:N45ToIEdDjjzHVQq1I7qeyg+X3Mz76sA5FdIaPwquGU= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -40,11 +40,13 @@ github.com/maruel/panicparse v1.1.1 h1:k62YPcEoLncEEpjMt92GtG5ugb8WL/510Ys3/h5Ik github.com/maruel/panicparse v1.1.1/go.mod h1:nty42YY5QByNC5MM7q/nj938VbgPU7avs45z6NClpxI= github.com/maruel/panicparse v1.2.0 h1:lcFfc3+EidyWRSHT1OPIIQYzCmZ30u0Z+qio+IL9KFQ= github.com/maruel/panicparse v1.2.0/go.mod h1:vszMjr5QQ4F5FSRfraldcIA/BCw5xrdLL+zEcU2nRBs= -github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc= github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4= github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= diff --git a/tests/state_test.go b/tests/state_test.go index a68a1aebb..eda6a652f 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -675,7 +675,7 @@ func TestAllETH(t *testing.T) { skipTests := make(map[string]string) - // Bugs in these tests (Always skip) + // Edge case consensus related tests (expect failure on these) skipTests["RevertPrecompiledTouch.json/Byzantium/0"] = "Bug in Test" skipTests["RevertPrecompiledTouch.json/Byzantium/3"] = "Bug in Test" skipTests["RevertPrecompiledTouch.json/Constantinople/0"] = "Bug in Test" @@ -698,42 +698,10 @@ func TestAllETH(t *testing.T) { skipTests["createJS_ExampleContract.json"] = "Not Implemented" skipTests["RevertDepthCreateAddressCollision.json"] = "Not Implemented" - // StaticCall implementations - skipTests["staticcall_createfails.json"] = "STATICCALL Not Implemented" - skipTests["RevertInStaticCall.json"] = "STATICCALL Not Implemented" - skipTests["returndatasize_after_successful_staticcall.json"] = "STATICCALL Not Implemented" - skipTests["returndatacopy_after_revert_in_staticcall.json"] = "STATICCALL Not Implemented" - skipTests["returndatacopy_after_successful_staticcall.json"] = "STATICCALL Not Implemented" - skipTests["returndatasize_after_failing_staticcall.json"] = "STATICCALL Not Implemented" - - // EIP 211 Implementations - // skipTests["CreateOOGafterInitCodeReturndataSize.json"] = "REVERT Not Implemented" - // skipTests["CreateOOGafterInitCodeReturndata2.json"] = "REVERT Not Implemented" - - // EIP 214 Implementations - skipTests["RevertOpcodeInCallsOnNonEmptyReturnData.json"] = "EIP214 Not Implemented" - skipTests["RevertInCallCode.json"] = "EIP214 Not Implemented" - skipTests["RevertInCreateInInit.json"] = "EIP214 Not Implemented" - skipTests["RevertInDelegateCall.json"] = "EIP214 Not Implemented" - skipTests["RevertOpcodeInCreateReturns.json"] = "EIP214 Not Implemented" - skipTests["PythonRevertTestTue201814-1430.json"] = "EIP214 Not Implemented" - // Random Test failures (REVISIT) skipTests["randomStatetest642.json"] = "random unimplemented" skipTests["randomStatetest644.json"] = "random unimplemented" skipTests["randomStatetest645.json"] = "random unimplemented" - skipTests["Opcodes_TransactionInit.json/Byzantium/37"] = "random unimplemented" - skipTests["Opcodes_TransactionInit.json/Byzantium/38"] = "random unimplemented" - skipTests["Opcodes_TransactionInit.json/Byzantium/125"] = "random unimplemented" - skipTests["Opcodes_TransactionInit.json/Byzantium/126"] = "random unimplemented" - skipTests["CREATE_ContractRETURNBigOffset.json"] = "random unimplemented" - - skipTests["RevertPrecompiledTouch.json"] = "precompiled unimplemented" - skipTests["RevertPrecompiledTouch_nonce.json"] = "precompiled unimplemented" - skipTests["RevertPrecompiledTouch_storage.json"] = "precompiled unimplemented" - skipTests["RevertPrecompiledTouch_noncestorage.json"] = "precompiled unimplemented" - skipTests["create_callprecompile_returndatasize.json"] = "precompiled unimplemented" - skipTests["modexp_modsize0_returndatasize.json"] = "precompiled unimplemented" // EIP 158/161 skipped tests skipTests["RevertPrefoundEmptyOOG.json"] = "State trie clearing unimplemented" @@ -744,10 +712,8 @@ func TestAllETH(t *testing.T) { "stZeroKnowledge": true, "stZeroKnowledge2": true, "stReturnDataTest": true, - //"stPreCompiledContracts": true, - //"stPreCompiledContracts2": true, - "stCodeSizeLimit": true, - "stCreate2": true, + "stCodeSizeLimit": true, + "stCreate2": true, } for _, dn := range dirNames { diff --git a/tests/util.go b/tests/util.go index 762a89427..ec3ef0833 100644 --- a/tests/util.go +++ b/tests/util.go @@ -375,6 +375,15 @@ func (self *Env) DelegateCall(caller vm.ContractRef, addr common.Address, data [ return core.DelegateCall(self, caller, addr, data, gas, price) } +func (self *Env) StaticCall(caller vm.ContractRef, addr common.Address, data []byte, gas, price *big.Int) ([]byte, error) { + if self.vmTest && self.depth > 0 { + caller.ReturnGas(gas, price) + + return nil, nil + } + return core.StaticCall(self, caller, addr, data, gas, price) +} + func (self *Env) Create(caller vm.ContractRef, data []byte, gas, price, value *big.Int) ([]byte, common.Address, error) { if self.vmTest { caller.ReturnGas(gas, price)