diff options
author | Jeffrey Wilcke <jeffrey@ethereum.org> | 2017-01-05 03:17:24 +0800 |
---|---|---|
committer | Jeffrey Wilcke <jeffrey@ethereum.org> | 2017-02-14 04:44:25 +0800 |
commit | c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057 (patch) | |
tree | da94063644627d9da853a91c28bc37f2df341dd1 /core/vm/instructions.go | |
parent | 72dcd3c58bec0a281280d5d42ed53b6e429ce4af (diff) | |
download | go-tangerine-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar go-tangerine-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.gz go-tangerine-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.bz2 go-tangerine-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.lz go-tangerine-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.xz go-tangerine-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.tar.zst go-tangerine-c12f4df910e2da1cc5dd28c5c4bbe2d8721e1057.zip |
params: core, core/vm, miner: 64bit gas instructions
Reworked the EVM gas instructions to use 64bit integers rather than
arbitrary size big ints. All gas operations, be it additions,
multiplications or divisions, are checked and guarded against 64 bit
integer overflows.
In additon, most of the protocol paramaters in the params package have
been converted to uint64 and are now constants rather than variables.
* common/math: added overflow check ops
* core: vmenv, env renamed to evm
* eth, internal/ethapi, les: unmetered eth_call and cancel methods
* core/vm: implemented big.Int pool for evm instructions
* core/vm: unexported intPool methods & verification methods
* core/vm: added memoryGasCost overflow check and test
Diffstat (limited to 'core/vm/instructions.go')
-rw-r--r-- | core/vm/instructions.go | 338 |
1 files changed, 211 insertions, 127 deletions
diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 3b1b06cca..39e5c0587 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -27,42 +27,56 @@ import ( "github.com/ethereum/go-ethereum/params" ) -func opAdd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +var bigZero = new(big.Int) + +func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(U256(x.Add(x, y))) + + evm.interpreter.intPool.put(y) + return nil, nil } -func opSub(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(U256(x.Sub(x, y))) + + evm.interpreter.intPool.put(y) + return nil, nil } -func opMul(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(U256(x.Mul(x, y))) + + evm.interpreter.intPool.put(y) + return nil, nil } -func opDiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if y.Cmp(common.Big0) != 0 { stack.push(U256(x.Div(x, y))) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(y) + return nil, nil } -func opSdiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := S256(stack.pop()), S256(stack.pop()) if y.Cmp(common.Big0) == 0 { stack.push(new(big.Int)) return nil, nil } else { n := new(big.Int) - if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 { + if evm.interpreter.intPool.get().Mul(x, y).Cmp(common.Big0) < 0 { n.SetInt64(-1) } else { n.SetInt64(1) @@ -73,20 +87,22 @@ func opSdiv(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Sta stack.push(U256(res)) } + evm.interpreter.intPool.put(y) return nil, nil } -func opMod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if y.Cmp(common.Big0) == 0 { stack.push(new(big.Int)) } else { stack.push(U256(x.Mod(x, y))) } + evm.interpreter.intPool.put(y) return nil, nil } -func opSmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := S256(stack.pop()), S256(stack.pop()) if y.Cmp(common.Big0) == 0 { @@ -104,16 +120,20 @@ func opSmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Sta stack.push(U256(res)) } + evm.interpreter.intPool.put(y) return nil, nil } -func opExp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opExp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { base, exponent := stack.pop(), stack.pop() stack.push(math.Exp(base, exponent)) + + evm.interpreter.intPool.put(base, exponent) + return nil, nil } -func opSignExtend(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { back := stack.pop() if back.Cmp(big.NewInt(31)) < 0 { bit := uint(back.Uint64()*8 + 7) @@ -128,198 +148,231 @@ func opSignExtend(pc *uint64, env *EVM, contract *Contract, memory *Memory, stac stack.push(U256(num)) } + + evm.interpreter.intPool.put(back) return nil, nil } -func opNot(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x := stack.pop() stack.push(U256(x.Not(x))) return nil, nil } -func opLt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if x.Cmp(y) < 0 { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(x, y) return nil, nil } -func opGt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if x.Cmp(y) > 0 { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(x, y) return nil, nil } -func opSlt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := S256(stack.pop()), S256(stack.pop()) if x.Cmp(S256(y)) < 0 { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(x, y) return nil, nil } -func opSgt(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := S256(stack.pop()), S256(stack.pop()) if x.Cmp(y) > 0 { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(x, y) return nil, nil } -func opEq(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() if x.Cmp(y) == 0 { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(x, y) return nil, nil } -func opIszero(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x := stack.pop() if x.Cmp(common.Big0) > 0 { stack.push(new(big.Int)) } else { - stack.push(big.NewInt(1)) + stack.push(evm.interpreter.intPool.get().SetUint64(1)) } + + evm.interpreter.intPool.put(x) return nil, nil } -func opAnd(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.And(x, y)) + + evm.interpreter.intPool.put(y) return nil, nil } -func opOr(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.Or(x, y)) + + evm.interpreter.intPool.put(y) return nil, nil } -func opXor(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() stack.push(x.Xor(x, y)) + + evm.interpreter.intPool.put(y) return nil, nil } -func opByte(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { th, val := stack.pop(), stack.pop() if th.Cmp(big.NewInt(32)) < 0 { - byte := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()])) + byte := evm.interpreter.intPool.get().SetInt64(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()])) stack.push(byte) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(th, val) return nil, nil } -func opAddmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() - if z.Cmp(Zero) > 0 { + if z.Cmp(bigZero) > 0 { add := x.Add(x, y) add.Mod(add, z) stack.push(U256(add)) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(y, z) return nil, nil } -func opMulmod(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y, z := stack.pop(), stack.pop(), stack.pop() - if z.Cmp(Zero) > 0 { + if z.Cmp(bigZero) > 0 { mul := x.Mul(x, y) mul.Mod(mul, z) stack.push(U256(mul)) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(y, z) return nil, nil } -func opSha3(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() data := memory.Get(offset.Int64(), size.Int64()) hash := crypto.Keccak256(data) - if env.vmConfig.EnablePreimageRecording { - env.StateDB.AddPreimage(common.BytesToHash(hash), data) + if evm.vmConfig.EnablePreimageRecording { + evm.StateDB.AddPreimage(common.BytesToHash(hash), data) } stack.push(common.BytesToBig(hash)) + + evm.interpreter.intPool.put(offset, size) return nil, nil } -func opAddress(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(common.Bytes2Big(contract.Address().Bytes())) return nil, nil } -func opBalance(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { addr := common.BigToAddress(stack.pop()) - balance := env.StateDB.GetBalance(addr) + balance := evm.StateDB.GetBalance(addr) stack.push(new(big.Int).Set(balance)) return nil, nil } -func opOrigin(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(env.Origin.Big()) +func opOrigin(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.Origin.Big()) return nil, nil } -func opCaller(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCaller(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(contract.Caller().Big()) return nil, nil } -func opCallValue(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(big.Int).Set(contract.value)) +func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.interpreter.intPool.get().Set(contract.value)) return nil, nil } -func opCalldataLoad(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCalldataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.push(common.Bytes2Big(getData(contract.Input, stack.pop(), common.Big32))) return nil, nil } -func opCalldataSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(big.NewInt(int64(len(contract.Input)))) +func opCalldataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.interpreter.intPool.get().SetInt64(int64(len(contract.Input)))) return nil, nil } -func opCalldataCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCalldataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( mOff = stack.pop() cOff = stack.pop() l = stack.pop() ) memory.Set(mOff.Uint64(), l.Uint64(), getData(contract.Input, cOff, l)) + + evm.interpreter.intPool.put(mOff, cOff, l) return nil, nil } -func opExtCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - addr := common.BigToAddress(stack.pop()) - l := big.NewInt(int64(env.StateDB.GetCodeSize(addr))) - stack.push(l) +func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + a := stack.pop() + + addr := common.BigToAddress(a) + a.SetInt64(int64(evm.StateDB.GetCodeSize(addr))) + stack.push(a) + return nil, nil } -func opCodeSize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - l := big.NewInt(int64(len(contract.Code))) +func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code))) stack.push(l) return nil, nil } -func opCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( mOff = stack.pop() cOff = stack.pop() @@ -328,113 +381,129 @@ func opCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack codeCopy := getData(contract.Code, cOff, l) memory.Set(mOff.Uint64(), l.Uint64(), codeCopy) + + evm.interpreter.intPool.put(mOff, cOff, l) return nil, nil } -func opExtCodeCopy(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( addr = common.BigToAddress(stack.pop()) mOff = stack.pop() cOff = stack.pop() l = stack.pop() ) - codeCopy := getData(env.StateDB.GetCode(addr), cOff, l) + codeCopy := getData(evm.StateDB.GetCode(addr), cOff, l) memory.Set(mOff.Uint64(), l.Uint64(), codeCopy) + + evm.interpreter.intPool.put(mOff, cOff, l) + return nil, nil } -func opGasprice(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(big.Int).Set(env.GasPrice)) +func opGasprice(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.interpreter.intPool.get().Set(evm.GasPrice)) return nil, nil } -func opBlockhash(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { num := stack.pop() - n := new(big.Int).Sub(env.BlockNumber, common.Big257) - if num.Cmp(n) > 0 && num.Cmp(env.BlockNumber) < 0 { - stack.push(env.GetHash(num.Uint64()).Big()) + n := evm.interpreter.intPool.get().Sub(evm.BlockNumber, common.Big257) + if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 { + stack.push(evm.GetHash(num.Uint64()).Big()) } else { stack.push(new(big.Int)) } + + evm.interpreter.intPool.put(num, n) return nil, nil } -func opCoinbase(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(env.Coinbase.Big()) +func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.Coinbase.Big()) return nil, nil } -func opTimestamp(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(U256(new(big.Int).Set(env.Time))) +func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(U256(new(big.Int).Set(evm.Time))) return nil, nil } -func opNumber(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(U256(new(big.Int).Set(env.BlockNumber))) +func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(U256(new(big.Int).Set(evm.BlockNumber))) return nil, nil } -func opDifficulty(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(U256(new(big.Int).Set(env.Difficulty))) +func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(U256(new(big.Int).Set(evm.Difficulty))) return nil, nil } -func opGasLimit(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(U256(new(big.Int).Set(env.GasLimit))) +func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(U256(new(big.Int).Set(evm.GasLimit))) return nil, nil } -func opPop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.pop() +func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + evm.interpreter.intPool.put(stack.pop()) return nil, nil } -func opMload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset := stack.pop() val := common.BigD(memory.Get(offset.Int64(), 32)) stack.push(val) + + evm.interpreter.intPool.put(offset) return nil, nil } -func opMstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // pop value of the stack mStart, val := stack.pop(), stack.pop() memory.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256)) + + evm.interpreter.intPool.put(mStart, val) return nil, nil } -func opMstore8(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { off, val := stack.pop().Int64(), stack.pop().Int64() memory.store[off] = byte(val & 0xff) + return nil, nil } -func opSload(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { loc := common.BigToHash(stack.pop()) - val := env.StateDB.GetState(contract.Address(), loc).Big() + val := evm.StateDB.GetState(contract.Address(), loc).Big() stack.push(val) return nil, nil } -func opSstore(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opSstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { loc := common.BigToHash(stack.pop()) val := stack.pop() - env.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) + evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) + + evm.interpreter.intPool.put(val) return nil, nil } -func opJump(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { pos := stack.pop() if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) { nop := contract.GetOp(pos.Uint64()) return nil, fmt.Errorf("invalid jump destination (%v) %v", nop, pos) } *pc = pos.Uint64() + + evm.interpreter.intPool.put(pos) return nil, nil } -func opJumpi(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { pos, cond := stack.pop(), stack.pop() if cond.Cmp(common.BigTrue) >= 0 { if !contract.jumpdests.has(contract.CodeHash, contract.Code, pos) { @@ -445,57 +514,62 @@ func opJumpi(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *St } else { *pc++ } + + evm.interpreter.intPool.put(pos, cond) return nil, nil } -func opJumpdest(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opJumpdest(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return nil, nil } -func opPc(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(big.Int).SetUint64(*pc)) +func opPc(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.interpreter.intPool.get().SetUint64(*pc)) return nil, nil } -func opMsize(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(big.NewInt(int64(memory.Len()))) +func opMsize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.interpreter.intPool.get().SetInt64(int64(memory.Len()))) return nil, nil } -func opGas(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(new(big.Int).Set(contract.Gas)) +func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + stack.push(evm.interpreter.intPool.get().SetUint64(contract.Gas)) return nil, nil } -func opCreate(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { var ( value = stack.pop() offset, size = stack.pop(), stack.pop() input = memory.Get(offset.Int64(), size.Int64()) - gas = new(big.Int).Set(contract.Gas) + gas = contract.Gas ) - if env.ChainConfig().IsEIP150(env.BlockNumber) { - gas.Div(gas, n64) - gas = gas.Sub(contract.Gas, gas) + if evm.ChainConfig().IsEIP150(evm.BlockNumber) { + gas -= gas / 64 } contract.UseGas(gas) - _, addr, suberr := env.Create(contract, input, gas, value) + _, addr, returnGas, suberr := evm.Create(contract, input, gas, value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must // ignore this error and pretend the operation was successful. - if env.ChainConfig().IsHomestead(env.BlockNumber) && suberr == ErrCodeStoreOutOfGas { + if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas { stack.push(new(big.Int)) } else if suberr != nil && suberr != ErrCodeStoreOutOfGas { stack.push(new(big.Int)) } else { stack.push(addr.Big()) } + contract.Gas += returnGas + + evm.interpreter.intPool.put(value, offset, size) + return nil, nil } -func opCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - gas := stack.pop() +func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + gas := stack.pop().Uint64() // pop gas and value of the stack. addr, value := stack.pop(), stack.pop() value = U256(value) @@ -509,25 +583,26 @@ func opCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Sta // Get the arguments from the memory args := memory.Get(inOffset.Int64(), inSize.Int64()) - if len(value.Bytes()) > 0 { - gas.Add(gas, params.CallStipend) + if value.BitLen() > 0 { + gas += params.CallStipend } - ret, err := env.Call(contract, address, args, gas, value) - + ret, returnGas, err := evm.Call(contract, address, args, gas, value) if err != nil { stack.push(new(big.Int)) - } else { stack.push(big.NewInt(1)) memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } + contract.Gas += returnGas + + evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) return nil, nil } -func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - gas := stack.pop() +func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + gas := stack.pop().Uint64() // pop gas and value of the stack. addr, value := stack.pop(), stack.pop() value = U256(value) @@ -541,12 +616,11 @@ func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack // Get the arguments from the memory args := memory.Get(inOffset.Int64(), inSize.Int64()) - if len(value.Bytes()) > 0 { - gas.Add(gas, params.CallStipend) + if value.BitLen() > 0 { + gas += params.CallStipend } - ret, err := env.CallCode(contract, address, args, gas, value) - + ret, returnGas, err := evm.CallCode(contract, address, args, gas, value) if err != nil { stack.push(new(big.Int)) @@ -555,46 +629,54 @@ func opCallCode(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } + contract.Gas += returnGas + + evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) return nil, nil } -func opDelegateCall(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { // if not homestead return an error. DELEGATECALL is not supported // during pre-homestead. - if !env.ChainConfig().IsHomestead(env.BlockNumber) { + if !evm.ChainConfig().IsHomestead(evm.BlockNumber) { return nil, fmt.Errorf("invalid opcode %x", DELEGATECALL) } - gas, to, inOffset, inSize, outOffset, outSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() + gas, to, inOffset, inSize, outOffset, outSize := stack.pop().Uint64(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(to) args := memory.Get(inOffset.Int64(), inSize.Int64()) - ret, err := env.DelegateCall(contract, toAddr, args, gas) + + ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas) if err != nil { stack.push(new(big.Int)) } else { stack.push(big.NewInt(1)) memory.Set(outOffset.Uint64(), outSize.Uint64(), ret) } + contract.Gas += returnGas + + evm.interpreter.intPool.put(to, inOffset, inSize, outOffset, outSize) return nil, nil } -func opReturn(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { offset, size := stack.pop(), stack.pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) + evm.interpreter.intPool.put(offset, size) return ret, nil } -func opStop(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { +func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return nil, nil } -func opSuicide(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - balance := env.StateDB.GetBalance(contract.Address()) - env.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) +func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + balance := evm.StateDB.GetBalance(contract.Address()) + evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) - env.StateDB.Suicide(contract.Address()) + evm.StateDB.Suicide(contract.Address()) return nil, nil } @@ -603,7 +685,7 @@ func opSuicide(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack * // make log instruction function func makeLog(size int) executionFunc { - return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { topics := make([]common.Hash, size) mStart, mSize := stack.pop(), stack.pop() for i := 0; i < size; i++ { @@ -611,22 +693,24 @@ func makeLog(size int) executionFunc { } d := memory.Get(mStart.Int64(), mSize.Int64()) - env.StateDB.AddLog(&types.Log{ + evm.StateDB.AddLog(&types.Log{ Address: contract.Address(), Topics: topics, Data: d, // This is a non-consensus field, but assigned here because // core/state doesn't know the current block number. - BlockNumber: env.BlockNumber.Uint64(), + BlockNumber: evm.BlockNumber.Uint64(), }) + + evm.interpreter.intPool.put(mStart, mSize) return nil, nil } } // make push instruction function func makePush(size uint64, bsize *big.Int) executionFunc { - return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - byts := getData(contract.Code, new(big.Int).SetUint64(*pc+1), bsize) + return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + byts := getData(contract.Code, evm.interpreter.intPool.get().SetUint64(*pc+1), bsize) stack.push(common.Bytes2Big(byts)) *pc += size return nil, nil @@ -635,7 +719,7 @@ func makePush(size uint64, bsize *big.Int) executionFunc { // make push instruction function func makeDup(size int64) executionFunc { - return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.dup(int(size)) return nil, nil } @@ -645,7 +729,7 @@ func makeDup(size int64) executionFunc { func makeSwap(size int64) executionFunc { // switch n + 1 otherwise n would be swapped with n size += 1 - return func(pc *uint64, env *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + return func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { stack.swap(int(size)) return nil, nil } |