diff options
author | jm <jm.huang@cobinhood.com> | 2019-01-16 17:32:29 +0800 |
---|---|---|
committer | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-03-26 17:48:21 +0800 |
commit | 1810c3af03d3da56d42f93c4521e33332156dcb6 (patch) | |
tree | 1cbcce4df7b1c5c50486c802abe4d37fb7cd70a6 | |
parent | d62272c95d13fd4928e5c14794c25f671a71bd95 (diff) | |
download | dexon-1810c3af03d3da56d42f93c4521e33332156dcb6.tar dexon-1810c3af03d3da56d42f93c4521e33332156dcb6.tar.gz dexon-1810c3af03d3da56d42f93c4521e33332156dcb6.tar.bz2 dexon-1810c3af03d3da56d42f93c4521e33332156dcb6.tar.lz dexon-1810c3af03d3da56d42f93c4521e33332156dcb6.tar.xz dexon-1810c3af03d3da56d42f93c4521e33332156dcb6.tar.zst dexon-1810c3af03d3da56d42f93c4521e33332156dcb6.zip |
core: vm: extract stateDB and contract out
Extract stateDB and contract out from core/vm/evm to core/vm,
such that other vm type can use the common modules.
31 files changed, 509 insertions, 439 deletions
diff --git a/core/evm.go b/core/evm.go index 7196cad27..ae18ee9a6 100644 --- a/core/evm.go +++ b/core/evm.go @@ -23,7 +23,7 @@ import ( "github.com/dexon-foundation/dexon/consensus" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" ) // ChainContext supports retrieving headers and consensus parameters from the diff --git a/core/state_transition.go b/core/state_transition.go index fddb187af..a9a700c2b 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -27,6 +27,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm/sqlvm" "github.com/dexon-foundation/dexon/log" "github.com/dexon-foundation/dexon/params" ) @@ -70,8 +71,9 @@ type StateTransition struct { initialGas uint64 value *big.Int data []byte - state evm.StateDB + state vm.StateDB evm *evm.EVM + sqlvm *sqlvm.SQLVM } // Message represents a message sent to a contract. @@ -246,7 +248,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo return } msg := st.msg - sender := evm.AccountRef(msg.From()) + sender := vm.AccountRef(msg.From()) homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber) contractCreation := msg.To() == nil @@ -260,14 +262,19 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo } var ( - evm = st.evm + evm = st.evm + sqlvm = st.sqlvm // vm errors do not effect consensus and are therefor // not assigned to err, except for insufficient balance // error. vmerr error ) if contractCreation { - ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) + if len(st.data) != 0 && st.data[0] == 0xed { + ret, _, st.gas, vmerr = sqlvm.Create(sender, st.data, st.gas, st.value) + } else { + ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value) + } } else { // Increment the nonce for the next transaction st.state.SetNonce(msg.From(), st.state.GetNonce(sender.Address())+1) diff --git a/core/vm/evm/contract.go b/core/vm/contract.go index a7ce2ddfd..37ec41cae 100644 --- a/core/vm/evm/contract.go +++ b/core/vm/contract.go @@ -14,12 +14,13 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package evm +package vm import ( "math/big" "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/crypto" ) // ContractRef is a reference to the contract's backing object @@ -34,7 +35,23 @@ type ContractRef interface { // proves difficult because of the cached jump destinations which // are fetched from the parent contract (i.e. the caller), which // is a ContractRef. -type AccountRef common.Address +type ( + AccountRef common.Address + Bitvec []byte +) + +func (bits *Bitvec) Set(pos uint64) { + (*bits)[pos/8] |= 0x80 >> (pos % 8) +} +func (bits *Bitvec) Set8(pos uint64) { + (*bits)[pos/8] |= 0xFF >> (pos % 8) + (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) +} + +// codeSegment checks if the position is in a code segment. +func (bits *Bitvec) CodeSegment(pos uint64) bool { + return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0 +} // Address casts AccountRef to a Address func (ar AccountRef) Address() common.Address { return (common.Address)(ar) } @@ -49,8 +66,8 @@ type Contract struct { caller ContractRef self ContractRef - jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis. - analysis bitvec // Locally cached result of JUMPDEST analysis + Jumpdests map[common.Hash]Bitvec // Aggregated result of JUMPDEST analysis. + Analysis Bitvec // Locally cached result of JUMPDEST analysis Code []byte CodeHash common.Hash @@ -58,7 +75,7 @@ type Contract struct { Input []byte Gas uint64 - value *big.Int + Value *big.Int } // NewContract returns a new contract environment for the execution of EVM. @@ -67,53 +84,20 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin if parent, ok := caller.(*Contract); ok { // Reuse JUMPDEST analysis from parent context if available. - c.jumpdests = parent.jumpdests + c.Jumpdests = parent.Jumpdests } else { - c.jumpdests = make(map[common.Hash]bitvec) + c.Jumpdests = make(map[common.Hash]Bitvec) } // Gas should be a pointer so it can safely be reduced through the run // This pointer will be off the state transition c.Gas = gas // ensures a value is set - c.value = value + c.Value = value return c } -func (c *Contract) validJumpdest(dest *big.Int) bool { - udest := dest.Uint64() - // PC cannot go beyond len(code) and certainly can't be bigger than 63bits. - // Don't bother checking for JUMPDEST in that case. - if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) { - return false - } - // Only JUMPDESTs allowed for destinations - if OpCode(c.Code[udest]) != JUMPDEST { - return false - } - // Do we have a contract hash already? - if c.CodeHash != (common.Hash{}) { - // Does parent context have the analysis? - analysis, exist := c.jumpdests[c.CodeHash] - if !exist { - // Do the analysis and save in parent context - // We do not need to store it in c.analysis - analysis = codeBitmap(c.Code) - c.jumpdests[c.CodeHash] = analysis - } - return analysis.codeSegment(udest) - } - // We don't have the code hash, most likely a piece of initcode not already - // in state trie. In that case, we do an analysis, and save it locally, so - // we don't have to recalculate it for every JUMP instruction in the execution - // However, we don't save it within the parent context - if c.analysis == nil { - c.analysis = codeBitmap(c.Code) - } - return c.analysis.codeSegment(udest) -} - // AsDelegate sets the contract to be a delegate call and returns the current // contract (for chaining calls) func (c *Contract) AsDelegate() *Contract { @@ -121,16 +105,11 @@ func (c *Contract) AsDelegate() *Contract { // that caller is something other than a Contract. parent := c.caller.(*Contract) c.CallerAddress = parent.CallerAddress - c.value = parent.value + c.Value = parent.Value return c } -// GetOp returns the n'th element in the contract's byte array -func (c *Contract) GetOp(n uint64) OpCode { - return OpCode(c.GetByte(n)) -} - // GetByte returns the n'th byte in the contract's byte array func (c *Contract) GetByte(n uint64) byte { if n < uint64(len(c.Code)) { @@ -162,11 +141,6 @@ func (c *Contract) Address() common.Address { return c.self.Address() } -// Value returns the contracts value (sent to it from it's caller) -func (c *Contract) Value() *big.Int { - return c.value -} - // SetCallCode sets the code of the contract and address of the backing data // object func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { @@ -177,8 +151,20 @@ func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []by // SetCodeOptionalHash can be used to provide code, but it's optional to provide hash. // In case hash is not provided, the jumpdest analysis will not be saved to the parent context -func (c *Contract) SetCodeOptionalHash(addr *common.Address, codeAndHash *codeAndHash) { - c.Code = codeAndHash.code - c.CodeHash = codeAndHash.hash +func (c *Contract) SetCodeOptionalHash(addr *common.Address, CodeAndHash *CodeAndHash) { + c.Code = CodeAndHash.Code + c.CodeHash = CodeAndHash.Hash() c.CodeAddr = addr } + +type CodeAndHash struct { + Code []byte + hash common.Hash +} + +func (c *CodeAndHash) Hash() common.Hash { + if c.hash == (common.Hash{}) { + c.hash = crypto.Keccak256Hash(c.Code) + } + return c.hash +} diff --git a/core/vm/evm/contracts.go b/core/vm/contracts.go index 52bb0a83b..0711c3030 100644 --- a/core/vm/evm/contracts.go +++ b/core/vm/contracts.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package evm +package vm import ( "crypto/sha256" @@ -23,7 +23,6 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/common/math" - "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/crypto/bn256" "github.com/dexon-foundation/dexon/params" @@ -66,7 +65,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contr if contract.UseGas(gas) { return p.Run(input) } - return nil, vm.ErrOutOfGas + return nil, ErrOutOfGas } // ECRECOVER implemented as a native contract. @@ -88,7 +87,7 @@ func (c *ecrecover) Run(input []byte) ([]byte, error) { v := input[63] - 27 // tighter sig s values input homestead only apply to tx sigs - if !vm.AllZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { + if !AllZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { return nil, nil } // v needs to be at the end for libsecp256k1 @@ -167,9 +166,9 @@ var ( // RequiredGas returns the gas required to execute the pre-compiled contract. func (c *bigModExp) RequiredGas(input []byte) uint64 { var ( - baseLen = new(big.Int).SetBytes(vm.GetData(input, 0, 32)) - expLen = new(big.Int).SetBytes(vm.GetData(input, 32, 32)) - modLen = new(big.Int).SetBytes(vm.GetData(input, 64, 32)) + baseLen = new(big.Int).SetBytes(GetData(input, 0, 32)) + expLen = new(big.Int).SetBytes(GetData(input, 32, 32)) + modLen = new(big.Int).SetBytes(GetData(input, 64, 32)) ) if len(input) > 96 { input = input[96:] @@ -182,9 +181,9 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { expHead = new(big.Int) } else { if expLen.Cmp(big32) > 0 { - expHead = new(big.Int).SetBytes(vm.GetData(input, baseLen.Uint64(), 32)) + expHead = new(big.Int).SetBytes(GetData(input, baseLen.Uint64(), 32)) } else { - expHead = new(big.Int).SetBytes(vm.GetData(input, baseLen.Uint64(), expLen.Uint64())) + expHead = new(big.Int).SetBytes(GetData(input, baseLen.Uint64(), expLen.Uint64())) } } // Calculate the adjusted exponent length @@ -226,9 +225,9 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { func (c *bigModExp) Run(input []byte) ([]byte, error) { var ( - baseLen = new(big.Int).SetBytes(vm.GetData(input, 0, 32)).Uint64() - expLen = new(big.Int).SetBytes(vm.GetData(input, 32, 32)).Uint64() - modLen = new(big.Int).SetBytes(vm.GetData(input, 64, 32)).Uint64() + baseLen = new(big.Int).SetBytes(GetData(input, 0, 32)).Uint64() + expLen = new(big.Int).SetBytes(GetData(input, 32, 32)).Uint64() + modLen = new(big.Int).SetBytes(GetData(input, 64, 32)).Uint64() ) if len(input) > 96 { input = input[96:] @@ -241,9 +240,9 @@ func (c *bigModExp) Run(input []byte) ([]byte, error) { } // Retrieve the operands and execute the exponentiation var ( - base = new(big.Int).SetBytes(vm.GetData(input, 0, baseLen)) - exp = new(big.Int).SetBytes(vm.GetData(input, baseLen, expLen)) - mod = new(big.Int).SetBytes(vm.GetData(input, baseLen+expLen, modLen)) + base = new(big.Int).SetBytes(GetData(input, 0, baseLen)) + exp = new(big.Int).SetBytes(GetData(input, baseLen, expLen)) + mod = new(big.Int).SetBytes(GetData(input, baseLen+expLen, modLen)) ) if mod.BitLen() == 0 { // Modulo 0 is undefined, return zero @@ -281,11 +280,11 @@ func (c *bn256Add) RequiredGas(input []byte) uint64 { } func (c *bn256Add) Run(input []byte) ([]byte, error) { - x, err := newCurvePoint(vm.GetData(input, 0, 64)) + x, err := newCurvePoint(GetData(input, 0, 64)) if err != nil { return nil, err } - y, err := newCurvePoint(vm.GetData(input, 64, 64)) + y, err := newCurvePoint(GetData(input, 64, 64)) if err != nil { return nil, err } @@ -303,12 +302,12 @@ func (c *bn256ScalarMul) RequiredGas(input []byte) uint64 { } func (c *bn256ScalarMul) Run(input []byte) ([]byte, error) { - p, err := newCurvePoint(vm.GetData(input, 0, 64)) + p, err := newCurvePoint(GetData(input, 0, 64)) if err != nil { return nil, err } res := new(bn256.G1) - res.ScalarMult(p, new(big.Int).SetBytes(vm.GetData(input, 64, 32))) + res.ScalarMult(p, new(big.Int).SetBytes(GetData(input, 64, 32))) return res.Marshal(), nil } diff --git a/core/vm/evm/contracts_test.go b/core/vm/contracts_test.go index 4b43f777b..f0090fcce 100644 --- a/core/vm/evm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Lesser General Public License // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. -package evm +package vm import ( "fmt" diff --git a/core/vm/evm/analysis.go b/core/vm/evm/analysis.go index 5e430f965..575af575e 100644 --- a/core/vm/evm/analysis.go +++ b/core/vm/evm/analysis.go @@ -16,30 +16,16 @@ package evm -// bitvec is a bit vector which maps bytes in a program. -// An unset bit means the byte is an opcode, a set bit means -// it's data (i.e. argument of PUSHxx). -type bitvec []byte - -func (bits *bitvec) set(pos uint64) { - (*bits)[pos/8] |= 0x80 >> (pos % 8) -} -func (bits *bitvec) set8(pos uint64) { - (*bits)[pos/8] |= 0xFF >> (pos % 8) - (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) -} - -// codeSegment checks if the position is in a code segment. -func (bits *bitvec) codeSegment(pos uint64) bool { - return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0 -} +import ( + "github.com/dexon-foundation/dexon/core/vm" +) // codeBitmap collects data locations in code. -func codeBitmap(code []byte) bitvec { +func codeBitmap(code []byte) vm.Bitvec { // The bitmap is 4 bytes longer than necessary, in case the code // ends with a PUSH32, the algorithm will push zeroes onto the // bitvector outside the bounds of the actual code. - bits := make(bitvec, len(code)/8+1+4) + bits := make(vm.Bitvec, len(code)/8+1+4) for pc := uint64(0); pc < uint64(len(code)); { op := OpCode(code[pc]) @@ -47,11 +33,11 @@ func codeBitmap(code []byte) bitvec { numbits := op - PUSH1 + 1 pc++ for ; numbits >= 8; numbits -= 8 { - bits.set8(pc) // 8 + bits.Set8(pc) // 8 pc += 8 } for ; numbits > 0; numbits-- { - bits.set(pc) + bits.Set(pc) pc++ } } else { diff --git a/core/vm/evm/evm.go b/core/vm/evm/evm.go index 11d25792e..28fe24574 100644 --- a/core/vm/evm/evm.go +++ b/core/vm/evm/evm.go @@ -22,7 +22,6 @@ import ( "time" "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/params" @@ -32,32 +31,18 @@ import ( // deployed contract addresses (relevant after the account abstraction). var emptyCodeHash = crypto.Keccak256Hash(nil) -type ( - // CanTransferFunc is the signature of a transfer guard function - CanTransferFunc func(StateDB, common.Address, *big.Int) bool - // TransferFunc is the signature of a transfer function - TransferFunc func(StateDB, common.Address, common.Address, *big.Int) - // GetHashFunc returns the nth block hash in the blockchain - // and is used by the BLOCKHASH EVM op code. - GetHashFunc func(uint64) common.Hash - // StateAtFunc returns the statedb given a root hash. - StateAtNumberFunc func(uint64) (*state.StateDB, error) - // GetRoundHeightFunc returns the round height. - GetRoundHeightFunc func(uint64) (uint64, bool) -) - // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. -func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, error) { +func run(evm *EVM, contract *vm.Contract, input []byte, readOnly bool) ([]byte, error) { if contract.CodeAddr != nil { if o := OracleContracts[*contract.CodeAddr]; o != nil { return RunOracleContract(o(), evm, input, contract) } - precompiles := PrecompiledContractsHomestead + precompiles := vm.PrecompiledContractsHomestead if evm.ChainConfig().IsByzantium(evm.BlockNumber) { - precompiles = PrecompiledContractsByzantium + precompiles = vm.PrecompiledContractsByzantium } if p := precompiles[*contract.CodeAddr]; p != nil { - return RunPrecompiledContract(p, input, contract) + return vm.RunPrecompiledContract(p, input, contract) } } for _, interpreter := range evm.interpreters { @@ -76,37 +61,6 @@ func run(evm *EVM, contract *Contract, input []byte, readOnly bool) ([]byte, err return nil, vm.ErrNoCompatibleInterpreter } -// Context provides the EVM with auxiliary information. Once provided -// it shouldn't be modified. -type Context struct { - // CanTransfer returns whether the account contains - // sufficient ether to transfer the value - CanTransfer CanTransferFunc - // Transfer transfers ether from one account to the other - Transfer TransferFunc - // GetHash returns the hash corresponding to n - GetHash GetHashFunc - // StateAtNumber returns the statedb given a root hash. - StateAtNumber StateAtNumberFunc - // GetRoundHeight returns the round height. - GetRoundHeight GetRoundHeightFunc - - // Message information - Origin common.Address // Provides information for ORIGIN - GasPrice *big.Int // Provides information for GASPRICE - - // Block information - Coinbase common.Address // Provides information for COINBASE - GasLimit uint64 // Provides information for GASLIMIT - BlockNumber *big.Int // Provides information for NUMBER - Time *big.Int // Provides information for TIME - Randomness []byte // Provides information for RAND - Difficulty *big.Int // Provides information for DIFFICULTY - Round *big.Int // Current round number. - - RandCallIndex uint64 // Number of times opRand is called -} - // EVM is the Ethereum Virtual Machine base object and provides // the necessary tools to run a contract on the given state with // the provided context. It should be noted that any error @@ -118,9 +72,9 @@ type Context struct { // The EVM should never be reused and is not thread safe. type EVM struct { // Context provides auxiliary blockchain related information - Context + vm.Context // StateDB gives access to the underlying state - StateDB StateDB + StateDB vm.StateDB // Depth is the current call stack depth int @@ -146,7 +100,7 @@ type EVM struct { // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { +func NewEVM(ctx vm.Context, statedb vm.StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { evm := &EVM{ Context: ctx, StateDB: statedb, @@ -195,7 +149,7 @@ func (evm *EVM) Interpreter() Interpreter { // 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, err error) { +func (evm *EVM) Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } @@ -210,13 +164,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } var ( - to = AccountRef(addr) + to = vm.AccountRef(addr) snapshot = evm.StateDB.Snapshot() ) if !evm.StateDB.Exist(addr) { - precompiles := PrecompiledContractsHomestead + precompiles := vm.PrecompiledContractsHomestead if evm.ChainConfig().IsByzantium(evm.BlockNumber) { - precompiles = PrecompiledContractsByzantium + precompiles = vm.PrecompiledContractsByzantium } if precompiles[addr] == nil && OracleContracts[addr] == nil && evm.ChainConfig().IsEIP158(evm.BlockNumber) && value.Sign() == 0 { @@ -232,7 +186,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - contract := NewContract(caller, to, value, gas) + contract := vm.NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) // Even if the account has no code, we need to continue because it might be a precompile @@ -267,7 +221,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. -func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) CallCode(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } @@ -283,12 +237,12 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, var ( snapshot = evm.StateDB.Snapshot() - to = AccountRef(caller.Address()) + to = vm.AccountRef(caller.Address()) ) // initialise a new contract and set the code that is to be used by the // EVM. The contract is a scoped environment for this execution context // only. - contract := NewContract(caller, to, value, gas) + contract := vm.NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) ret, err = run(evm, contract, input, false) @@ -306,7 +260,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, // // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. -func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) DelegateCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } @@ -317,11 +271,11 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by var ( snapshot = evm.StateDB.Snapshot() - to = AccountRef(caller.Address()) + to = vm.AccountRef(caller.Address()) ) // Initialise a new contract and make initialise the delegate values - contract := NewContract(caller, to, nil, gas).AsDelegate() + contract := vm.NewContract(caller, to, nil, gas).AsDelegate() contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) ret, err = run(evm, contract, input, false) @@ -338,7 +292,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by // as parameters while disallowing any modifications to the state during the call. // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. -func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) StaticCall(caller vm.ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } @@ -348,13 +302,13 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte } var ( - to = AccountRef(addr) + to = vm.AccountRef(addr) snapshot = evm.StateDB.Snapshot() ) // Initialise a new contract and set the code that is to be used by the // EVM. The contract is a scoped environment for this execution context // only. - contract := NewContract(caller, to, new(big.Int), gas) + contract := vm.NewContract(caller, to, new(big.Int), gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) // We do an AddBalance of zero here, just in order to trigger a touch. @@ -376,20 +330,8 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte return ret, contract.Gas, err } -type codeAndHash struct { - code []byte - hash common.Hash -} - -func (c *codeAndHash) Hash() common.Hash { - if c.hash == (common.Hash{}) { - c.hash = crypto.Keccak256Hash(c.code) - } - return c.hash -} - // create creates a new contract using code as deployment code. -func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { +func (evm *EVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas uint64, value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { // Depth check execution. Fail if we're trying to execute above the // limit. if evm.depth > int(params.CallCreateDepth) { @@ -417,7 +359,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // initialise a new contract and set the code that is to be used by the // EVM. The contract is a scoped environment for this execution context // only. - contract := NewContract(caller, AccountRef(address), value, gas) + contract := vm.NewContract(caller, vm.AccountRef(address), value, gas) contract.SetCodeOptionalHash(&address, codeAndHash) if evm.vmConfig.NoRecursion && evm.depth > 0 { @@ -425,7 +367,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } if evm.vmConfig.Debug && evm.depth == 0 { - evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value) + evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.Code, gas, value) } start := time.Now() @@ -467,17 +409,17 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, } // 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 vm.ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { contractAddr = crypto.CreateAddress(caller.Address(), evm.StateDB.GetNonce(caller.Address())) - return evm.create(caller, &codeAndHash{code: code}, gas, value, contractAddr) + return evm.create(caller, &vm.CodeAndHash{Code: code}, gas, value, contractAddr) } // Create2 creates a new contract using code as deployment code. // // The different between Create2 with Create is Create2 uses sha3(0xff ++ msg.sender ++ salt ++ sha3(init_code))[12:] // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. -func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - codeAndHash := &codeAndHash{code: code} +func (evm *EVM) Create2(caller vm.ContractRef, code []byte, gas uint64, endowment *big.Int, salt *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { + codeAndHash := &vm.CodeAndHash{Code: code} contractAddr = crypto.CreateAddress2(caller.Address(), common.BigToHash(salt), codeAndHash.Hash().Bytes()) return evm.create(caller, codeAndHash, gas, endowment, contractAddr) } diff --git a/core/vm/evm/evm_test.go b/core/vm/evm/evm_test.go index 2e382c15f..ef5e8a6b0 100644 --- a/core/vm/evm/evm_test.go +++ b/core/vm/evm/evm_test.go @@ -29,6 +29,7 @@ import ( "github.com/dexon-foundation/dexon/accounts/abi" "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" + vmlib "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" @@ -84,9 +85,9 @@ func newTestVM() *testVM { panic(err) } - context := Context{ - CanTransfer: func(StateDB, common.Address, *big.Int) bool { return true }, - Transfer: func(StateDB, common.Address, common.Address, *big.Int) {}, + context := vmlib.Context{ + CanTransfer: func(vmlib.StateDB, common.Address, *big.Int) bool { return true }, + Transfer: func(vmlib.StateDB, common.Address, common.Address, *big.Int) {}, Time: big.NewInt(time.Now().UnixNano() / 1000000000), BlockNumber: big.NewInt(0), } @@ -106,9 +107,9 @@ func (vm *testVM) create(caller string, code []byte, value *big.Int) ( ret []byte, contractAddr common.Address, err error) { callerAddr := common.HexToAddress(caller) contractAddr = crypto.CreateAddress(callerAddr, uint64(0)) - contract := NewContract(AccountRef(callerAddr), - AccountRef(contractAddr), value, math.MaxUint64) - contract.SetCodeOptionalHash(&callerAddr, &codeAndHash{code: code}) + contract := vmlib.NewContract(vmlib.AccountRef(callerAddr), + vmlib.AccountRef(contractAddr), value, math.MaxUint64) + contract.SetCodeOptionalHash(&callerAddr, &vmlib.CodeAndHash{Code: code}) ret, err = vm.interpreter.Run(contract, nil, false) if err != nil { contractAddr = common.Address{} @@ -126,17 +127,17 @@ func (vm *testVM) call( } func (vm *testVM) createContract( - caller string, addr common.Address, value *big.Int) *Contract { + caller string, addr common.Address, value *big.Int) *vmlib.Contract { callerAddr := common.HexToAddress(caller) vm.evm.StateDB.CreateAccount(callerAddr) - contract := NewContract(AccountRef(callerAddr), - AccountRef(addr), value, math.MaxUint64) + contract := vmlib.NewContract(vmlib.AccountRef(callerAddr), + vmlib.AccountRef(addr), value, math.MaxUint64) contract.SetCallCode( &addr, vm.evm.StateDB.GetCodeHash(addr), vm.evm.StateDB.GetCode(addr)) return contract } -func (vm *testVM) callContract(contract *Contract, input []byte) ( +func (vm *testVM) callContract(contract *vmlib.Contract, input []byte) ( ret []byte, err error) { if len(contract.Code) == 0 { panic(fmt.Errorf("no code")) diff --git a/core/vm/evm/gas_table.go b/core/vm/evm/gas_table.go index 0087004cf..242494537 100644 --- a/core/vm/evm/gas_table.go +++ b/core/vm/evm/gas_table.go @@ -59,12 +59,12 @@ func memoryGasCost(mem *vm.Memory, newMemSize uint64) (uint64, error) { } func constGasFunc(gas uint64) gasFunc { - return func(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { + return func(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gas, nil } } -func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -90,7 +90,7 @@ func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm return gas, nil } -func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -116,7 +116,7 @@ func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack * return gas, nil } -func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasSStore(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var ( y, x = stack.Back(1), stack.Back(0) current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) @@ -186,7 +186,7 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack } func makeGasLog(n uint64) gasFunc { - return func(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { + return func(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { requestedSize, overflow := vm.BigUint64(stack.Back(1)) if overflow { return 0, errGasUintOverflow @@ -215,7 +215,7 @@ func makeGasLog(n uint64) gasFunc { } } -func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasSha3(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -239,7 +239,7 @@ func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, return gas, nil } -func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasCodeCopy(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -263,7 +263,7 @@ func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Sta return gas, nil } -func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -289,11 +289,11 @@ func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *vm. return gas, nil } -func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gt.ExtcodeHash, nil } -func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasMLoad(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -305,7 +305,7 @@ func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, return gas, nil } -func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasMStore8(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -317,7 +317,7 @@ func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stac return gas, nil } -func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasMStore(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -329,7 +329,7 @@ func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack return gas, nil } -func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasCreate(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -341,7 +341,7 @@ func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack return gas, nil } -func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasCreate2(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var overflow bool gas, err := memoryGasCost(mem, memorySize) if err != nil { @@ -364,19 +364,19 @@ func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stac return gas, nil } -func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasBalance(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gt.Balance, nil } -func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gt.ExtcodeSize, nil } -func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasSLoad(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return gt.SLoad, nil } -func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasExp(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { expByteLen := uint64((stack.Data[stack.Len()-2].BitLen() + 7) / 8) var ( @@ -389,7 +389,7 @@ func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, m return gas, nil } -func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasCall(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var ( gas = gt.Calls transfersValue = stack.Back(2).Sign() != 0 @@ -425,7 +425,7 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, return gas, nil } -func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasCallCode(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas := gt.Calls if stack.Back(2).Sign() != 0 { gas += params.CallValueTransferGas @@ -449,15 +449,15 @@ func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Sta return gas, nil } -func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasReturn(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return memoryGasCost(mem, memorySize) } -func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasRevert(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return memoryGasCost(mem, memorySize) } -func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasSuicide(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { var gas uint64 // EIP150 homestead gas reprice fork: if evm.ChainConfig().IsEIP150(evm.BlockNumber) { @@ -483,7 +483,7 @@ func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stac return gas, nil } -func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasDelegateCall(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -503,7 +503,7 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *vm return gas, nil } -func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasStaticCall(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -523,14 +523,14 @@ func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.S return gas, nil } -func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasPush(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return GasFastestStep, nil } -func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasSwap(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return GasFastestStep, nil } -func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { +func gasDup(gt params.GasTable, evm *EVM, contract *vm.Contract, stack *vm.Stack, mem *vm.Memory, memorySize uint64) (uint64, error) { return GasFastestStep, nil } diff --git a/core/vm/evm/governance.go b/core/vm/evm/governance.go index 8b31d3a01..18e733342 100644 --- a/core/vm/evm/governance.go +++ b/core/vm/evm/governance.go @@ -86,7 +86,7 @@ func init() { } // RunGovernanceContract executes governance contract. -func RunGovernanceContract(evm *EVM, input []byte, contract *Contract) (ret []byte, err error) { +func RunGovernanceContract(evm *EVM, input []byte, contract *vm.Contract) (ret []byte, err error) { if len(input) < 4 { return nil, nil } @@ -574,7 +574,7 @@ func publicKeyToNodeID(pkBytes []byte) (Bytes32, error) { // State manipulation helper fro the governance contract. type GovernanceStateHelper struct { - StateDB StateDB + StateDB vm.StateDB } func (s *GovernanceStateHelper) getState(loc common.Hash) common.Hash { @@ -1529,10 +1529,10 @@ func (s *GovernanceStateHelper) emitFinePaid(nodeAddr common.Address, amount *bi type GovernanceContract struct { evm *EVM state GovernanceStateHelper - contract *Contract + contract *vm.Contract } -func newGovernanceContract(evm *EVM, contract *Contract) *GovernanceContract { +func newGovernanceContract(evm *EVM, contract *vm.Contract) *GovernanceContract { return &GovernanceContract{ evm: evm, state: GovernanceStateHelper{evm.StateDB}, @@ -1777,7 +1777,7 @@ func (g *GovernanceContract) delegate(nodeAddr common.Address) ([]byte, error) { } caller := g.contract.Caller() - value := g.contract.Value() + value := g.contract.Value // Can not delegate if no fund was sent. if value.Cmp(big.NewInt(0)) == 0 { @@ -1792,11 +1792,11 @@ func (g *GovernanceContract) delegate(nodeAddr common.Address) ([]byte, error) { // Add to the total staked of node. node := g.state.Node(offset) - node.Staked = new(big.Int).Add(node.Staked, g.contract.Value()) + node.Staked = new(big.Int).Add(node.Staked, g.contract.Value) g.state.UpdateNode(offset, node) // Add to network total staked. - g.state.IncTotalStaked(g.contract.Value()) + g.state.IncTotalStaked(g.contract.Value) // Push delegator record. offset = g.state.LenDelegators(nodeAddr) @@ -1855,7 +1855,7 @@ func (g *GovernanceContract) stake( } // Delegate fund to itself. - if g.contract.Value().Cmp(big.NewInt(0)) > 0 { + if g.contract.Value.Cmp(big.NewInt(0)) > 0 { if ret, err := g.delegate(caller); err != nil { return ret, err } @@ -2013,16 +2013,16 @@ func (g *GovernanceContract) payFine(nodeAddr common.Address) ([]byte, error) { } node := g.state.Node(nodeOffset) - if node.Fined.Cmp(big.NewInt(0)) <= 0 || node.Fined.Cmp(g.contract.Value()) < 0 { + if node.Fined.Cmp(big.NewInt(0)) <= 0 || node.Fined.Cmp(g.contract.Value) < 0 { return nil, errExecutionReverted } - node.Fined = new(big.Int).Sub(node.Fined, g.contract.Value()) + node.Fined = new(big.Int).Sub(node.Fined, g.contract.Value) g.state.UpdateNode(nodeOffset, node) // TODO: paid fine should be added to award pool. - g.state.emitFinePaid(nodeAddr, g.contract.Value()) + g.state.emitFinePaid(nodeAddr, g.contract.Value) return g.useGas(100000) } diff --git a/core/vm/evm/governance_test.go b/core/vm/evm/governance_test.go index 1a67516ec..5a82c7f1a 100644 --- a/core/vm/evm/governance_test.go +++ b/core/vm/evm/governance_test.go @@ -34,6 +34,7 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" + "github.com/dexon-foundation/dexon/core/vm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" @@ -149,11 +150,11 @@ func (g *GovernanceContractTestSuite) newPrefundAccount() (*ecdsa.PrivateKey, co } func (g *GovernanceContractTestSuite) call(caller common.Address, input []byte, value *big.Int) ([]byte, error) { - context := Context{ - CanTransfer: func(db StateDB, addr common.Address, amount *big.Int) bool { + context := vm.Context{ + CanTransfer: func(db vm.StateDB, addr common.Address, amount *big.Int) bool { return db.GetBalance(addr).Cmp(amount) >= 0 }, - Transfer: func(db StateDB, sender common.Address, recipient common.Address, amount *big.Int) { + Transfer: func(db vm.StateDB, sender common.Address, recipient common.Address, amount *big.Int) { db.SubBalance(sender, amount) db.AddBalance(recipient, amount) }, @@ -173,7 +174,7 @@ func (g *GovernanceContractTestSuite) call(caller common.Address, input []byte, } evm := NewEVM(context, g.stateDB, params.TestChainConfig, Config{IsBlockProposer: true}) - ret, _, err := evm.Call(AccountRef(caller), GovernanceContractAddress, input, 10000000, value) + ret, _, err := evm.Call(vm.AccountRef(caller), GovernanceContractAddress, input, 10000000, value) return ret, err } diff --git a/core/vm/evm/instructions.go b/core/vm/evm/instructions.go index d37ab5e43..10ff75b69 100644 --- a/core/vm/evm/instructions.go +++ b/core/vm/evm/instructions.go @@ -51,7 +51,7 @@ func init() { } } -func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() math.U256(y.Add(x, y)) @@ -59,7 +59,7 @@ func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSub(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() math.U256(y.Sub(x, y)) @@ -67,7 +67,7 @@ func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opMul(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Pop() stack.Push(math.U256(x.Mul(x, y))) @@ -76,7 +76,7 @@ func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() if y.Sign() != 0 { math.U256(y.Div(x, y)) @@ -87,7 +87,7 @@ func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := math.S256(stack.Pop()), math.S256(stack.Pop()) res := interpreter.intPool.GetZero() @@ -106,7 +106,7 @@ func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } -func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opMod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Pop() if y.Sign() == 0 { stack.Push(x.SetUint64(0)) @@ -117,7 +117,7 @@ func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := math.S256(stack.Pop()), math.S256(stack.Pop()) res := interpreter.intPool.GetZero() @@ -136,7 +136,7 @@ func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } -func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opExp(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { base, exponent := stack.Pop(), stack.Pop() if base.Cmp(big2) == 0 && exponent.Cmp(big256) == -1 { exp := exponent.Int64() @@ -150,7 +150,7 @@ func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { back := stack.Pop() if back.Cmp(big.NewInt(31)) < 0 { bit := uint(back.Uint64()*8 + 7) @@ -170,13 +170,13 @@ func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, m return nil, nil } -func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opNot(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x := stack.Peek() math.U256(x.Not(x)) return nil, nil } -func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opLt(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() if x.Cmp(y) < 0 { y.SetUint64(1) @@ -187,7 +187,7 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *v return nil, nil } -func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opGt(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() if x.Cmp(y) > 0 { y.SetUint64(1) @@ -198,7 +198,7 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *v return nil, nil } -func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() xSign := x.Cmp(tt255) @@ -222,7 +222,7 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() xSign := x.Cmp(tt255) @@ -246,7 +246,7 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opEq(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() if x.Cmp(y) == 0 { y.SetUint64(1) @@ -257,7 +257,7 @@ func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *v return nil, nil } -func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x := stack.Peek() if x.Sign() > 0 { x.SetUint64(0) @@ -267,7 +267,7 @@ func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return nil, nil } -func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Pop() stack.Push(x.And(x, y)) @@ -275,7 +275,7 @@ func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opOr(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() y.Or(x, y) @@ -283,7 +283,7 @@ func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *v return nil, nil } -func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opXor(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y := stack.Pop(), stack.Peek() y.Xor(x, y) @@ -291,7 +291,7 @@ func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opByte(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { th, val := stack.Pop(), stack.Peek() if th.Cmp(common.Big32) < 0 { b := math.Byte(val, 32, int(th.Int64())) @@ -303,7 +303,7 @@ func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } -func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y, z := stack.Pop(), stack.Pop(), stack.Pop() if z.Cmp(bigZero) > 0 { x.Add(x, y) @@ -316,7 +316,7 @@ func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return nil, nil } -func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { x, y, z := stack.Pop(), stack.Pop(), stack.Pop() if z.Cmp(bigZero) > 0 { x.Mul(x, y) @@ -332,7 +332,7 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor // opSHL implements Shift Left // The SHL instruction (shift left) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the left by arg1 number of bits. -func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := math.U256(stack.Pop()), math.U256(stack.Peek()) defer interpreter.intPool.Put(shift) // First operand back into the pool @@ -350,7 +350,7 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * // opSHR implements Logical Shift Right // The SHR instruction (logical shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill. -func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards shift, value := math.U256(stack.Pop()), math.U256(stack.Peek()) defer interpreter.intPool.Put(shift) // First operand back into the pool @@ -368,7 +368,7 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * // opSAR implements Arithmetic Shift Right // The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2, // and pushes on the stack arg2 shifted to the right by arg1 number of bits with sign extension. -func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one shift, value := math.U256(stack.Pop()), math.S256(stack.Pop()) defer interpreter.intPool.Put(shift) // First operand back into the pool @@ -389,7 +389,7 @@ func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory * return nil, nil } -func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { offset, size := stack.Pop(), stack.Pop() data := memory.Get(offset.Int64(), size.Int64()) @@ -411,7 +411,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } -func opRand(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opRand(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { evm := interpreter.evm nonce := evm.StateDB.GetNonce(evm.Origin) @@ -433,43 +433,43 @@ func opRand(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } -func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(contract.Address().Big()) return nil, nil } -func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { slot := stack.Peek() slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot))) return nil, nil } -func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opOrigin(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(interpreter.evm.Origin.Big()) return nil, nil } -func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(contract.Caller().Big()) return nil, nil } -func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { - stack.Push(interpreter.intPool.Get().Set(contract.value)) +func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + stack.Push(interpreter.intPool.Get().Set(contract.Value)) return nil, nil } -func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(interpreter.intPool.Get().SetBytes(vm.GetDataBig(contract.Input, stack.Pop(), big32))) return nil, nil } -func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(interpreter.intPool.Get().SetInt64(int64(len(contract.Input)))) return nil, nil } -func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( memOffset = stack.Pop() dataOffset = stack.Pop() @@ -481,12 +481,12 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, return nil, nil } -func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opReturnDataSize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(interpreter.intPool.Get().SetUint64(uint64(len(interpreter.returnData)))) return nil, nil } -func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( memOffset = stack.Pop() dataOffset = stack.Pop() @@ -504,21 +504,21 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac return nil, nil } -func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { slot := stack.Peek() slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot)))) return nil, nil } -func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { l := interpreter.intPool.Get().SetInt64(int64(len(contract.Code))) stack.Push(l) return nil, nil } -func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( memOffset = stack.Pop() codeOffset = stack.Pop() @@ -531,7 +531,7 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem return nil, nil } -func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( addr = common.BigToAddress(stack.Pop()) memOffset = stack.Pop() @@ -571,7 +571,7 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, // // (6) Caller tries to get the code hash for an account which is marked as deleted, // this account should be regarded as a non-existent account and zero should be returned. -func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { slot := stack.Peek() address := common.BigToAddress(slot) if interpreter.evm.StateDB.Empty(address) { @@ -582,12 +582,12 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, return nil, nil } -func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(interpreter.intPool.Get().Set(interpreter.evm.GasPrice)) return nil, nil } -func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { num := stack.Pop() n := interpreter.intPool.Get().Sub(interpreter.evm.BlockNumber, common.Big257) @@ -600,37 +600,37 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, me return nil, nil } -func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(interpreter.evm.Coinbase.Big()) return nil, nil } -func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(math.U256(interpreter.intPool.Get().Set(interpreter.evm.Time))) return nil, nil } -func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(math.U256(interpreter.intPool.Get().Set(interpreter.evm.BlockNumber))) return nil, nil } -func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(math.U256(interpreter.intPool.Get().Set(interpreter.evm.Difficulty))) return nil, nil } -func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(math.U256(interpreter.intPool.Get().SetUint64(interpreter.evm.GasLimit))) return nil, nil } -func opPop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opPop(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { interpreter.intPool.Put(stack.Pop()) return nil, nil } -func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opMload(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { offset := stack.Pop() val := interpreter.intPool.Get().SetBytes(memory.Get(offset.Int64(), 32)) stack.Push(val) @@ -639,7 +639,7 @@ func opMload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } -func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // pop value of the stack mStart, val := stack.Pop(), stack.Pop() memory.Set32(mStart.Uint64(), val) @@ -648,21 +648,21 @@ func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return nil, nil } -func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { off, val := stack.Pop().Int64(), stack.Pop().Int64() memory.Store[off] = byte(val & 0xff) return nil, nil } -func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSload(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { loc := stack.Peek() val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc)) loc.SetBytes(val.Bytes()) return nil, nil } -func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { loc := common.BigToHash(stack.Pop()) val := stack.Pop() interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) @@ -671,10 +671,10 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return nil, nil } -func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opJump(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { pos := stack.Pop() - if !contract.validJumpdest(pos) { - nop := contract.GetOp(pos.Uint64()) + if !validJumpdest(pos, contract) { + nop := OpCode(contract.GetByte(pos.Uint64())) return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) } *pc = pos.Uint64() @@ -683,11 +683,11 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } -func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { pos, cond := stack.Pop(), stack.Pop() if cond.Sign() != 0 { - if !contract.validJumpdest(pos) { - nop := contract.GetOp(pos.Uint64()) + if !validJumpdest(pos, contract) { + nop := OpCode(contract.GetByte(pos.Uint64())) return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) } *pc = pos.Uint64() @@ -699,26 +699,26 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return nil, nil } -func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opJumpdest(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { return nil, nil } -func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opPc(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(interpreter.intPool.Get().SetUint64(*pc)) return nil, nil } -func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(interpreter.intPool.Get().SetInt64(int64(memory.Len()))) return nil, nil } -func opGas(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opGas(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Push(interpreter.intPool.Get().SetUint64(contract.Gas)) return nil, nil } -func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( value = stack.Pop() offset, size = stack.Pop(), stack.Pop() @@ -751,7 +751,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return nil, nil } -func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { var ( endowment = stack.Pop() offset, size = stack.Pop(), stack.Pop() @@ -779,7 +779,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo return nil, nil } -func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Pop gas. The actual gas in interpreter.evm.callGasTemp. interpreter.intPool.Put(stack.Pop()) gas := interpreter.evm.callGasTemp @@ -808,7 +808,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory return ret, nil } -func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Pop gas. The actual gas is in interpreter.evm.callGasTemp. interpreter.intPool.Put(stack.Pop()) gas := interpreter.evm.callGasTemp @@ -837,7 +837,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem return ret, nil } -func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Pop gas. The actual gas is in interpreter.evm.callGasTemp. interpreter.intPool.Put(stack.Pop()) gas := interpreter.evm.callGasTemp @@ -862,7 +862,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, return ret, nil } -func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { // Pop gas. The actual gas is in interpreter.evm.callGasTemp. interpreter.intPool.Put(stack.Pop()) gas := interpreter.evm.callGasTemp @@ -887,7 +887,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, m return ret, nil } -func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { offset, size := stack.Pop(), stack.Pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) @@ -895,7 +895,7 @@ func opReturn(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return ret, nil } -func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { offset, size := stack.Pop(), stack.Pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) @@ -903,11 +903,11 @@ func opRevert(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor return ret, nil } -func opStop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opStop(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { return nil, nil } -func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { +func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { balance := interpreter.evm.StateDB.GetBalance(contract.Address()) interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.Pop()), balance) @@ -919,7 +919,7 @@ func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo // make log instruction function func makeLog(size int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + return func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { topics := make([]common.Hash, size) mStart, mSize := stack.Pop(), stack.Pop() for i := 0; i < size; i++ { @@ -943,7 +943,7 @@ func makeLog(size int) executionFunc { // make push instruction function func makePush(size uint64, pushByteSize int) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + return func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { codeLen := len(contract.Code) startMin := codeLen @@ -966,7 +966,7 @@ func makePush(size uint64, pushByteSize int) executionFunc { // make dup instruction function func makeDup(size int64) executionFunc { - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + return func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Dup(interpreter.intPool, int(size)) return nil, nil } @@ -976,8 +976,40 @@ func makeDup(size int64) executionFunc { func makeSwap(size int64) executionFunc { // switch n + 1 otherwise n would be swapped with n size++ - return func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { + return func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) { stack.Swap(int(size)) return nil, nil } } +func validJumpdest(dest *big.Int, c *vm.Contract) bool { + udest := dest.Uint64() + // PC cannot go beyond len(code) and certainly can't be bigger than 63bits. + // Don't bother checking for JUMPDEST in that case. + if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) { + return false + } + // Only JUMPDESTs allowed for destinations + if OpCode(c.Code[udest]) != JUMPDEST { + return false + } + // Do we have a contract hash already? + if c.CodeHash != (common.Hash{}) { + // Does parent context have the analysis? + analysis, exist := c.Jumpdests[c.CodeHash] + if !exist { + // Do the analysis and save in parent context + // We do not need to store it in c.analysis + analysis = codeBitmap(c.Code) + c.Jumpdests[c.CodeHash] = analysis + } + return analysis.CodeSegment(udest) + } + // We don't have the code hash, most likely a piece of initcode not already + // in state trie. In that case, we do an analysis, and save it locally, so + // we don't have to recalculate it for every JUMP instruction in the execution + // However, we don't save it within the parent context + if c.Analysis == nil { + c.Analysis = codeBitmap(c.Code) + } + return c.Analysis.CodeSegment(udest) +} diff --git a/core/vm/evm/instructions_test.go b/core/vm/evm/instructions_test.go index 9e677dde3..bd3df271d 100644 --- a/core/vm/evm/instructions_test.go +++ b/core/vm/evm/instructions_test.go @@ -33,9 +33,9 @@ type twoOperandTest struct { expected string } -func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error)) { +func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error)) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) stack = NewStack() pc = uint64(0) evmInterpreter = NewEVMInterpreter(env, env.vmConfig) @@ -76,7 +76,7 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64 func TestByteOp(t *testing.T) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) stack = NewStack() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) @@ -209,9 +209,9 @@ func TestSLT(t *testing.T) { testTwoOperandOp(t, tests, opSlt) } -func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error), args ...string) { +func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error), args ...string) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) stack = NewStack() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) @@ -446,7 +446,7 @@ func BenchmarkOpIsZero(b *testing.B) { func TestOpMstore(t *testing.T) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) stack = NewStack() mem = vm.NewMemory() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) @@ -472,7 +472,7 @@ func TestOpMstore(t *testing.T) { func BenchmarkOpMstore(bench *testing.B) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) stack = NewStack() mem = vm.NewMemory() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) @@ -495,7 +495,7 @@ func BenchmarkOpMstore(bench *testing.B) { func BenchmarkOpSHA3(bench *testing.B) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + env = NewEVM(vm.Context{}, nil, params.TestChainConfig, Config{}) stack = NewStack() mem = vm.NewMemory() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) diff --git a/core/vm/evm/interface.go b/core/vm/evm/interface.go index 20e5f34a9..2e751597a 100644 --- a/core/vm/evm/interface.go +++ b/core/vm/evm/interface.go @@ -20,61 +20,18 @@ import ( "math/big" "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/core/types" + "github.com/dexon-foundation/dexon/core/vm" ) -// StateDB is an EVM database for full state querying. -type StateDB interface { - CreateAccount(common.Address) - - SubBalance(common.Address, *big.Int) - AddBalance(common.Address, *big.Int) - GetBalance(common.Address) *big.Int - - GetNonce(common.Address) uint64 - SetNonce(common.Address, uint64) - - GetCodeHash(common.Address) common.Hash - GetCode(common.Address) []byte - SetCode(common.Address, []byte) - GetCodeSize(common.Address) int - - AddRefund(uint64) - SubRefund(uint64) - GetRefund() uint64 - - GetCommittedState(common.Address, common.Hash) common.Hash - GetState(common.Address, common.Hash) common.Hash - SetState(common.Address, common.Hash, common.Hash) - - Suicide(common.Address) bool - HasSuicided(common.Address) bool - - // Exist reports whether the given account exists in state. - // Notably this should also return true for suicided accounts. - Exist(common.Address) bool - // Empty returns whether the given account is empty. Empty - // is defined according to EIP161 (balance = nonce = code = 0). - Empty(common.Address) bool - - RevertToSnapshot(int) - Snapshot() int - - AddLog(*types.Log) - AddPreimage(common.Hash, []byte) - - ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) -} - // CallContext provides a basic interface for the EVM calling conventions. The EVM // depends on this context being implemented for doing subcalls and initialising new EVM contracts. type CallContext interface { // Call another contract - Call(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) + Call(env *EVM, me vm.ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) // Take another's contract code and execute within our own context - CallCode(env *EVM, me ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) + CallCode(env *EVM, me vm.ContractRef, addr common.Address, data []byte, gas, value *big.Int) ([]byte, error) // Same as CallCode except sender and value is propagated from parent to child scope - DelegateCall(env *EVM, me ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) + DelegateCall(env *EVM, me vm.ContractRef, addr common.Address, data []byte, gas *big.Int) ([]byte, error) // Create a new contract - Create(env *EVM, me ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) + Create(env *EVM, me vm.ContractRef, data []byte, gas, value *big.Int) ([]byte, common.Address, error) } diff --git a/core/vm/evm/interpreter.go b/core/vm/evm/interpreter.go index ca3ddd05a..867e72ee1 100644 --- a/core/vm/evm/interpreter.go +++ b/core/vm/evm/interpreter.go @@ -59,7 +59,7 @@ type Config struct { type Interpreter interface { // Run loops and evaluates the contract's code with the given input data and returns // the return byte-slice and an error if one occurred. - Run(contract *Contract, input []byte, static bool) ([]byte, error) + Run(contract *vm.Contract, input []byte, static bool) ([]byte, error) // CanRun tells if the contract, passed as an argument, can be // run by the current interpreter. This is meant so that the // caller can do something like: @@ -144,7 +144,7 @@ func (in *EVMInterpreter) enforceRestrictions(op OpCode, operation operation, st // It's important to note that any errors returned by the interpreter should be // considered a revert-and-consume-all-gas operation except for // errExecutionReverted which means revert-and-keep-gas-left. -func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) { +func (in *EVMInterpreter) Run(contract *vm.Contract, input []byte, readOnly bool) (ret []byte, err error) { if in.intPool == nil { in.intPool = vm.PoolOfIntPools.Get() defer func() { @@ -218,7 +218,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // Get the operation from the jump table and validate the stack to ensure there are // enough stack items available to perform the operation. - op = contract.GetOp(pc) + op = OpCode(contract.GetByte(pc)) operation := in.cfg.JumpTable[op] if !operation.valid { return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) diff --git a/core/vm/evm/jump_table.go b/core/vm/evm/jump_table.go index da2f50c5a..da7cbfd04 100644 --- a/core/vm/evm/jump_table.go +++ b/core/vm/evm/jump_table.go @@ -25,8 +25,8 @@ import ( ) type ( - executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) - gasFunc func(params.GasTable, *EVM, *Contract, *vm.Stack, *vm.Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 + executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *vm.Contract, memory *vm.Memory, stack *vm.Stack) ([]byte, error) + gasFunc func(params.GasTable, *EVM, *vm.Contract, *vm.Stack, *vm.Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 memorySizeFunc func(*vm.Stack) *big.Int ) diff --git a/core/vm/evm/logger.go b/core/vm/evm/logger.go index f51943b14..d9ccfed03 100644 --- a/core/vm/evm/logger.go +++ b/core/vm/evm/logger.go @@ -100,8 +100,8 @@ func (s *StructLog) ErrorString() string { // if you need to retain them beyond the current call. type Tracer interface { CaptureStart(from common.Address, to common.Address, call bool, input []byte, gas uint64, value *big.Int) error - CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error - CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error + CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error + CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error } @@ -138,7 +138,7 @@ func (l *StructLogger) CaptureStart(from common.Address, to common.Address, crea // CaptureState logs a new structured log message and pushes it out to the environment // // CaptureState also tracks SSTORE ops to track dirty values. -func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error { +func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { // check if already accumulated the specified number of logs if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) { return vm.ErrTraceLimitReached @@ -187,7 +187,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui // CaptureFault implements the Tracer interface to trace an execution fault // while running an opcode. -func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error { +func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { return nil } diff --git a/core/vm/evm/logger_json.go b/core/vm/evm/logger_json.go index e96e435b3..b8c628684 100644 --- a/core/vm/evm/logger_json.go +++ b/core/vm/evm/logger_json.go @@ -47,7 +47,7 @@ func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create } // CaptureState outputs state information on the logger. -func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error { +func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { log := StructLog{ Pc: pc, Op: op, @@ -69,7 +69,7 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint } // CaptureFault outputs state information on the logger. -func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *Contract, depth int, err error) error { +func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { return nil } diff --git a/core/vm/evm/logger_test.go b/core/vm/evm/logger_test.go index a8e0e9044..3a293675b 100644 --- a/core/vm/evm/logger_test.go +++ b/core/vm/evm/logger_test.go @@ -51,11 +51,11 @@ func (*dummyStatedb) GetRefund() uint64 { return 1337 } func TestStoreCapture(t *testing.T) { var ( - env = NewEVM(Context{}, &dummyStatedb{}, params.TestChainConfig, Config{}) + env = NewEVM(vm.Context{}, &dummyStatedb{}, params.TestChainConfig, Config{}) logger = NewStructLogger(nil) mem = vm.NewMemory() stack = NewStack() - contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0) + contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0) ) stack.Push(big.NewInt(1)) stack.Push(big.NewInt(0)) diff --git a/core/vm/evm/memory_table.go b/core/vm/evm/memory_table.go index c27e95a4a..f13cb6e81 100644 --- a/core/vm/evm/memory_table.go +++ b/core/vm/evm/memory_table.go @@ -23,6 +23,11 @@ import ( "github.com/dexon-foundation/dexon/core/vm" ) +var ( + big1 = big.NewInt(1) + big32 = big.NewInt(32) +) + func memorySha3(stack *vm.Stack) *big.Int { return vm.CalcMemSize(stack.Back(0), stack.Back(1)) } diff --git a/core/vm/evm/runtime/env.go b/core/vm/evm/runtime/env.go index c46580140..92cc8681c 100644 --- a/core/vm/evm/runtime/env.go +++ b/core/vm/evm/runtime/env.go @@ -19,10 +19,11 @@ package runtime import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" ) -func NewEnv(cfg *Config) *vm.EVM { +func NewEnv(cfg *Config) *evm.EVM { context := vm.Context{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -37,5 +38,5 @@ func NewEnv(cfg *Config) *vm.EVM { GasPrice: cfg.GasPrice, } - return vm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) + return evm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) } diff --git a/core/vm/evm/runtime/runtime.go b/core/vm/evm/runtime/runtime.go index 93e6322f4..c89f9dd11 100644 --- a/core/vm/evm/runtime/runtime.go +++ b/core/vm/evm/runtime/runtime.go @@ -23,7 +23,8 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" @@ -42,7 +43,7 @@ type Config struct { GasPrice *big.Int Value *big.Int Debug bool - EVMConfig vm.Config + EVMConfig evm.Config State *state.StateDB GetHashFn func(n uint64) common.Hash diff --git a/core/vm/sqlvm/sqlvm.go b/core/vm/sqlvm/sqlvm.go new file mode 100644 index 000000000..258a65d01 --- /dev/null +++ b/core/vm/sqlvm/sqlvm.go @@ -0,0 +1,50 @@ +package sqlvm + +import ( + "math/big" + + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/crypto" + "github.com/dexon-foundation/dexon/params" +) + +type SQLVM struct { + // Context provides auxiliary blockchain related information + vm.Context + // StateDB gives access to the underlying state + StateDB vm.StateDB + // Depth is the current call stack + depth int + + // chainConfig contains information about the current chain + chainConfig *params.ChainConfig + // chain rules contains the chain rules for the current epoch + chainRules params.Rules + // abort is used to abort the SQLVM calling operations + // NOTE: must be set atomically + abort int32 + // callGasTemp holds the gas available for the current call. This is needed because the + // available gas is calculated in gasCall* according to the 63/64 rule and later + // applied in opCall*. + callGasTemp uint64 +} + +func (sqlvm *SQLVM) Create(caller vm.ContractRef, code []byte, gas uint64, + value *big.Int) (ret []byte, contractAddr common.Address, + leftOverGas uint64, err error) { + + contractAddr = crypto.CreateAddress(caller.Address(), sqlvm.StateDB.GetNonce(caller.Address())) + return sqlvm.create(caller, &vm.CodeAndHash{Code: code}, gas, value, contractAddr) +} + +// create creates a new contract using code as deployment code. +func (sqlvm *SQLVM) create(caller vm.ContractRef, codeAndHash *vm.CodeAndHash, gas uint64, + value *big.Int, address common.Address) ([]byte, common.Address, uint64, error) { + // Depth check execution. Fail if we're trying to execute above the + if sqlvm.depth > int(params.CallCreateDepth) { + return nil, common.Address{}, gas, vm.ErrDepth + } + // TODO (JM) implement create database contract function + return nil, common.Address{}, gas, nil +} diff --git a/core/vm/stateDB.go b/core/vm/stateDB.go new file mode 100644 index 000000000..753b04247 --- /dev/null +++ b/core/vm/stateDB.go @@ -0,0 +1,97 @@ +package vm + +import ( + "math/big" + + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/core/state" + "github.com/dexon-foundation/dexon/core/types" +) + +type ( + // CanTransferFunc is the signature of a transfer guard function + CanTransferFunc func(StateDB, common.Address, *big.Int) bool + // TransferFunc is the signature of a transfer function + TransferFunc func(StateDB, common.Address, common.Address, *big.Int) + // GetHashFunc returns the nth block hash in the blockchain + // and is used by the BLOCKHASH EVM op code. + GetHashFunc func(uint64) common.Hash + // StateAtFunc returns the statedb given a root hash. + StateAtNumberFunc func(uint64) (*state.StateDB, error) + // GetRoundHeightFunc returns the round height. + GetRoundHeightFunc func(uint64) (uint64, bool) +) + +// Context provides the EVM with auxiliary information. Once provided +// it shouldn't be modified. +type Context struct { + // CanTransfer returns whether the account contains + // sufficient ether to transfer the value + CanTransfer CanTransferFunc + // Transfer transfers ether from one account to the other + Transfer TransferFunc + // GetHash returns the hash corresponding to n + GetHash GetHashFunc + // StateAtNumber returns the statedb given a root hash. + StateAtNumber StateAtNumberFunc + // GetRoundHeight returns the round height. + GetRoundHeight GetRoundHeightFunc + + // Message information + Origin common.Address // Provides information for ORIGIN + GasPrice *big.Int // Provides information for GASPRICE + + // Block information + Coinbase common.Address // Provides information for COINBASE + GasLimit uint64 // Provides information for GASLIMIT + BlockNumber *big.Int // Provides information for NUMBER + Time *big.Int // Provides information for TIME + Randomness []byte // Provides information for RAND + Difficulty *big.Int // Provides information for DIFFICULTY + Round *big.Int // Current round number. + + RandCallIndex uint64 // Number of times opRand is called +} + +// StateDB is an EVM database for full state querying. +type StateDB interface { + CreateAccount(common.Address) + + SubBalance(common.Address, *big.Int) + AddBalance(common.Address, *big.Int) + GetBalance(common.Address) *big.Int + + GetNonce(common.Address) uint64 + SetNonce(common.Address, uint64) + + GetCodeHash(common.Address) common.Hash + GetCode(common.Address) []byte + SetCode(common.Address, []byte) + GetCodeSize(common.Address) int + + AddRefund(uint64) + SubRefund(uint64) + GetRefund() uint64 + + GetCommittedState(common.Address, common.Hash) common.Hash + GetState(common.Address, common.Hash) common.Hash + SetState(common.Address, common.Hash, common.Hash) + + Suicide(common.Address) bool + HasSuicided(common.Address) bool + + // Exist reports whether the given account exists in state. + // Notably this should also return true for suicided accounts. + Exist(common.Address) bool + // Empty returns whether the given account is empty. Empty + // is defined according to EIP161 (balance = nonce = code = 0). + Empty(common.Address) bool + + RevertToSnapshot(int) + Snapshot() int + + AddLog(*types.Log) + AddPreimage(common.Hash, []byte) + + ForEachStorage(common.Address, func(common.Hash, common.Hash) bool) +} diff --git a/dex/api_tracer.go b/dex/api_tracer.go index 450f0bfab..c4dbf78a5 100644 --- a/dex/api_tracer.go +++ b/dex/api_tracer.go @@ -32,7 +32,8 @@ import ( "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/eth/tracers" "github.com/dexon-foundation/dexon/internal/ethapi" "github.com/dexon-foundation/dexon/log" @@ -54,7 +55,7 @@ const ( // TraceConfig holds extra parameters to trace functions. type TraceConfig struct { - *vm.LogConfig + *evm.LogConfig Tracer *string Timeout *string Reexec *uint64 @@ -275,7 +276,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl traced += uint64(len(txs)) } // Generate the next state snapshot fast without tracing - _, _, _, err := api.dex.blockchain.Processor().Process(block, statedb, vm.Config{}) + _, _, _, err := api.dex.blockchain.Processor().Process(block, statedb, evm.Config{}) if err != nil { failed = err break @@ -448,7 +449,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, msg, _ := tx.AsMessage(signer) vmctx := core.NewEVMContext(msg, block.Header(), api.dex.blockchain, nil) - vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{}) + vmenv := evm.NewEVM(vmctx, statedb, api.config, evm.Config{}) if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { failed = err break @@ -512,7 +513,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (* if block = api.dex.blockchain.GetBlockByNumber(block.NumberU64() + 1); block == nil { return nil, fmt.Errorf("block #%d not found", block.NumberU64()+1) } - _, _, _, err := api.dex.blockchain.Processor().Process(block, statedb, vm.Config{}) + _, _, _, err := api.dex.blockchain.Processor().Process(block, statedb, evm.Config{}) if err != nil { return nil, err } @@ -561,7 +562,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, vmctx vm.Context, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { // Assemble the structured logger or the JavaScript tracer var ( - tracer vm.Tracer + tracer evm.Tracer err error ) switch { @@ -586,13 +587,13 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v defer cancel() case config == nil: - tracer = vm.NewStructLogger(nil) + tracer = evm.NewStructLogger(nil) default: - tracer = vm.NewStructLogger(config.LogConfig) + tracer = evm.NewStructLogger(config.LogConfig) } // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer}) + vmenv := evm.NewEVM(vmctx, statedb, api.config, evm.Config{Debug: true, Tracer: tracer}) ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) if err != nil { @@ -600,7 +601,7 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v } // Depending on the tracer type, format and return the output switch tracer := tracer.(type) { - case *vm.StructLogger: + case *evm.StructLogger: return ðapi.ExecutionResult{ Gas: gas, Failed: failed, @@ -642,7 +643,7 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree return msg, context, statedb, nil } // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{}) + vmenv := evm.NewEVM(context, statedb, api.config, evm.Config{}) if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err) } diff --git a/dex/transactions.rlp b/dex/transactions.rlp new file mode 100755 index 000000000..e69de29bb --- /dev/null +++ b/dex/transactions.rlp diff --git a/eth/api_tracer.go b/eth/api_tracer.go index c3523b8bc..e05bbe0a2 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -34,7 +34,8 @@ import ( "github.com/dexon-foundation/dexon/core/rawdb" "github.com/dexon-foundation/dexon/core/state" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/eth/tracers" "github.com/dexon-foundation/dexon/internal/ethapi" "github.com/dexon-foundation/dexon/log" @@ -56,7 +57,7 @@ const ( // TraceConfig holds extra parameters to trace functions. type TraceConfig struct { - *vm.LogConfig + *evm.LogConfig Tracer *string Timeout *string Reexec *uint64 @@ -64,7 +65,7 @@ type TraceConfig struct { // StdTraceConfig holds extra parameters to standard-json trace functions. type StdTraceConfig struct { - *vm.LogConfig + *evm.LogConfig Reexec *uint64 TxHash common.Hash } @@ -289,7 +290,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl traced += uint64(len(txs)) } // Generate the next state snapshot fast without tracing - _, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, vm.Config{}) + _, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, evm.Config{}) if err != nil { failed = err break @@ -501,7 +502,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, msg, _ := tx.AsMessage(signer) vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) - vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{}) + vmenv := evm.NewEVM(vmctx, statedb, api.config, evm.Config{}) if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { failed = err break @@ -554,7 +555,7 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block } // Retrieve the tracing configurations, or use default values var ( - logConfig vm.LogConfig + logConfig evm.LogConfig txHash common.Hash ) if config != nil { @@ -576,7 +577,7 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block msg, _ = tx.AsMessage(signer) vmctx = core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) - vmConf vm.Config + vmConf evm.Config dump *os.File err error ) @@ -592,14 +593,14 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block dumps = append(dumps, dump.Name()) // Swap out the noop logger to the standard tracer - vmConf = vm.Config{ + vmConf = evm.Config{ Debug: true, - Tracer: vm.NewJSONLogger(&logConfig, bufio.NewWriter(dump)), + Tracer: evm.NewJSONLogger(&logConfig, bufio.NewWriter(dump)), EnablePreimageRecording: true, } } // Execute the transaction and flush any traces to disk - vmenv := vm.NewEVM(vmctx, statedb, api.config, vmConf) + vmenv := evm.NewEVM(vmctx, statedb, api.config, vmConf) _, _, _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) if dump != nil { @@ -667,7 +668,7 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (* if block = api.eth.blockchain.GetBlockByNumber(block.NumberU64() + 1); block == nil { return nil, fmt.Errorf("block #%d not found", block.NumberU64()+1) } - _, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, vm.Config{}) + _, _, _, err := api.eth.blockchain.Processor().Process(block, statedb, evm.Config{}) if err != nil { return nil, fmt.Errorf("processing block %d failed: %v", block.NumberU64(), err) } @@ -716,7 +717,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, vmctx vm.Context, statedb *state.StateDB, config *TraceConfig) (interface{}, error) { // Assemble the structured logger or the JavaScript tracer var ( - tracer vm.Tracer + tracer evm.Tracer err error ) switch { @@ -741,13 +742,13 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v defer cancel() case config == nil: - tracer = vm.NewStructLogger(nil) + tracer = evm.NewStructLogger(nil) default: - tracer = vm.NewStructLogger(config.LogConfig) + tracer = evm.NewStructLogger(config.LogConfig) } // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer}) + vmenv := evm.NewEVM(vmctx, statedb, api.config, evm.Config{Debug: true, Tracer: tracer}) ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) if err != nil { @@ -755,7 +756,7 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v } // Depending on the tracer type, format and return the output switch tracer := tracer.(type) { - case *vm.StructLogger: + case *evm.StructLogger: return ðapi.ExecutionResult{ Gas: gas, Failed: failed, @@ -797,7 +798,7 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree return msg, context, statedb, nil } // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{}) + vmenv := evm.NewEVM(context, statedb, api.config, evm.Config{}) if _, _, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.Context{}, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } diff --git a/eth/tracers/tracer.go b/eth/tracers/tracer.go index f232df49e..d26cc1fae 100644 --- a/eth/tracers/tracer.go +++ b/eth/tracers/tracer.go @@ -178,7 +178,7 @@ func (sw *stackWrapper) pushObject(vm *duktape.Context) { // dbWrapper provides a JavaScript wrapper around evm.Database. type dbWrapper struct { - db evm.StateDB + db vm.StateDB } // pushObject assembles a JSVM object wrapping a swappable database and pushes it @@ -233,7 +233,7 @@ func (dw *dbWrapper) pushObject(vm *duktape.Context) { // contractWrapper provides a JavaScript wrapper around evm.Contract type contractWrapper struct { - contract *evm.Contract + contract *vm.Contract } // pushObject assembles a JSVM object wrapping a swappable contract and pushes it @@ -259,7 +259,7 @@ func (cw *contractWrapper) pushObject(vm *duktape.Context) { // Push the wrapper for contract.Value vm.PushGoFunction(func(ctx *duktape.Context) int { - pushBigInt(cw.contract.Value(), ctx) + pushBigInt(cw.contract.Value, ctx) return 1 }) vm.PutPropString(obj, "getValue") @@ -391,7 +391,7 @@ func New(code string) (*Tracer, error) { return 1 }) tracer.vm.PushGlobalGoFunction("isPrecompiled", func(ctx *duktape.Context) int { - _, ok := evm.PrecompiledContractsByzantium[common.BytesToAddress(popSlice(ctx))] + _, ok := vm.PrecompiledContractsByzantium[common.BytesToAddress(popSlice(ctx))] ctx.PushBoolean(ok) return 1 }) @@ -533,7 +533,7 @@ func (jst *Tracer) CaptureStart(from common.Address, to common.Address, create b } // CaptureState implements the Tracer interface to trace a single step of VM execution. -func (jst *Tracer) CaptureState(env *evm.EVM, pc uint64, op evm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *evm.Contract, depth int, err error) error { +func (jst *Tracer) CaptureState(env *evm.EVM, pc uint64, op evm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { if jst.err == nil { // Initialize the context if it wasn't done yet if !jst.inited { @@ -572,7 +572,7 @@ func (jst *Tracer) CaptureState(env *evm.EVM, pc uint64, op evm.OpCode, gas, cos // CaptureFault implements the Tracer interface to trace an execution fault // while running an opcode. -func (jst *Tracer) CaptureFault(env *evm.EVM, pc uint64, op evm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *evm.Contract, depth int, err error) error { +func (jst *Tracer) CaptureFault(env *evm.EVM, pc uint64, op evm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { if jst.err == nil { // Apart from the error, everything matches the previous invocation jst.errorValue = new(string) diff --git a/eth/tracers/tracer_test.go b/eth/tracers/tracer_test.go index eacc9a591..42343f91a 100644 --- a/eth/tracers/tracer_test.go +++ b/eth/tracers/tracer_test.go @@ -26,7 +26,8 @@ import ( "github.com/dexon-foundation/dexon/common" "github.com/dexon-foundation/dexon/core/state" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/params" ) @@ -51,10 +52,10 @@ type dummyStatedb struct { func (*dummyStatedb) GetRefund() uint64 { return 1337 } func runTrace(tracer *Tracer) (json.RawMessage, error) { - env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) + env := evm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, evm.Config{Debug: true, Tracer: tracer}) contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000) - contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} + contract.Code = []byte{byte(evm.PUSH1), 0x1, byte(evm.PUSH1), 0x1, 0x0} _, err := env.Interpreter().Run(contract, []byte{}, false) if err != nil { @@ -133,7 +134,7 @@ func TestHaltBetweenSteps(t *testing.T) { t.Fatal(err) } - env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) + env := evm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, evm.Config{Debug: true, Tracer: tracer}) contract := vm.NewContract(&account{}, &account{}, big.NewInt(0), 0) tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, contract, 0, nil) diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 0b8f75ab3..783c41b7a 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -32,7 +32,8 @@ import ( "github.com/dexon-foundation/dexon/common/math" "github.com/dexon-foundation/dexon/core" "github.com/dexon-foundation/dexon/core/types" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" @@ -248,7 +249,7 @@ func TestCallTracer(t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(context, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := evm.NewEVM(context, statedb, test.Genesis.Config, evm.Config{Debug: true, Tracer: tracer}) msg, err := tx.AsMessage(signer) if err != nil { diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index 316213ea5..09b30d19b 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -27,7 +27,8 @@ import ( "github.com/dexon-foundation/dexon/common/math" "github.com/dexon-foundation/dexon/core" "github.com/dexon-foundation/dexon/core/state" - vm "github.com/dexon-foundation/dexon/core/vm/evm" + "github.com/dexon-foundation/dexon/core/vm" + "github.com/dexon-foundation/dexon/core/vm/evm" "github.com/dexon-foundation/dexon/crypto" "github.com/dexon-foundation/dexon/ethdb" "github.com/dexon-foundation/dexon/params" @@ -78,7 +79,7 @@ type vmExecMarshaling struct { GasPrice *math.HexOrDecimal256 } -func (t *VMTest) Run(vmconfig vm.Config) error { +func (t *VMTest) Run(vmconfig evm.Config) error { statedb := MakePreState(ethdb.NewMemDatabase(), t.json.Pre) ret, gasRemaining, err := t.exec(statedb, vmconfig) @@ -114,13 +115,13 @@ func (t *VMTest) Run(vmconfig vm.Config) error { return nil } -func (t *VMTest) exec(statedb *state.StateDB, vmconfig vm.Config) ([]byte, uint64, error) { +func (t *VMTest) exec(statedb *state.StateDB, vmconfig evm.Config) ([]byte, uint64, error) { evm := t.newEVM(statedb, vmconfig) e := t.json.Exec return evm.Call(vm.AccountRef(e.Caller), e.Address, e.Data, e.GasLimit, e.Value) } -func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM { +func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig evm.Config) *evm.EVM { initialCall := true canTransfer := func(db vm.StateDB, address common.Address, amount *big.Int) bool { if initialCall { @@ -143,7 +144,7 @@ func (t *VMTest) newEVM(statedb *state.StateDB, vmconfig vm.Config) *vm.EVM { GasPrice: t.json.Exec.GasPrice, } vmconfig.NoRecursion = true - return vm.NewEVM(context, statedb, params.EthereumMainnetChainConfig, vmconfig) + return evm.NewEVM(context, statedb, params.EthereumMainnetChainConfig, vmconfig) } func vmTestBlockHash(n uint64) common.Hash { |