mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core/vm: use fixed uint256 library instead of big
This commit is contained in:
parent
44c365c3e2
commit
fc287d7645
17 changed files with 338 additions and 366 deletions
|
|
@ -17,15 +17,14 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// calcMemSize64 calculates the required memory size, and returns
|
// calcMemSize64 calculates the required memory size, and returns
|
||||||
// the size and whether the result overflowed uint64
|
// the size and whether the result overflowed uint64
|
||||||
func calcMemSize64(off, l *big.Int) (uint64, bool) {
|
func calcMemSize64(off, l *uint256.Int) (uint64, bool) {
|
||||||
if !l.IsUint64() {
|
if !l.IsUint64() {
|
||||||
return 0, true
|
return 0, true
|
||||||
}
|
}
|
||||||
|
|
@ -35,16 +34,16 @@ func calcMemSize64(off, l *big.Int) (uint64, bool) {
|
||||||
// calcMemSize64WithUint calculates the required memory size, and returns
|
// calcMemSize64WithUint calculates the required memory size, and returns
|
||||||
// the size and whether the result overflowed uint64
|
// the size and whether the result overflowed uint64
|
||||||
// Identical to calcMemSize64, but length is a uint64
|
// Identical to calcMemSize64, but length is a uint64
|
||||||
func calcMemSize64WithUint(off *big.Int, length64 uint64) (uint64, bool) {
|
func calcMemSize64WithUint(off *uint256.Int, length64 uint64) (uint64, bool) {
|
||||||
// if length is zero, memsize is always zero, regardless of offset
|
// if length is zero, memsize is always zero, regardless of offset
|
||||||
if length64 == 0 {
|
if length64 == 0 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
// Check that offset doesn't overflow
|
// Check that offset doesn't overflow
|
||||||
if !off.IsUint64() {
|
offset64, overflow := off.Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
return 0, true
|
return 0, true
|
||||||
}
|
}
|
||||||
offset64 := off.Uint64()
|
|
||||||
val := offset64 + length64
|
val := offset64 + length64
|
||||||
// if value < either of it's parts, then it overflowed
|
// if value < either of it's parts, then it overflowed
|
||||||
return val, val < offset64
|
return val, val < offset64
|
||||||
|
|
@ -64,22 +63,6 @@ func getData(data []byte, start uint64, size uint64) []byte {
|
||||||
return common.RightPadBytes(data[start:end], int(size))
|
return common.RightPadBytes(data[start:end], int(size))
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDataBig returns a slice from the data based on the start and size and pads
|
|
||||||
// up to size with zero's. This function is overflow safe.
|
|
||||||
func getDataBig(data []byte, start *big.Int, size *big.Int) []byte {
|
|
||||||
dlen := big.NewInt(int64(len(data)))
|
|
||||||
|
|
||||||
s := math.BigMin(start, dlen)
|
|
||||||
e := math.BigMin(new(big.Int).Add(s, size), dlen)
|
|
||||||
return common.RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// bigUint64 returns the integer casted to a uint64 and returns whether it
|
|
||||||
// overflowed in the process.
|
|
||||||
func bigUint64(v *big.Int) (uint64, bool) {
|
|
||||||
return v.Uint64(), !v.IsUint64()
|
|
||||||
}
|
|
||||||
|
|
||||||
// toWordSize returns the ceiled word size required for memory expansion.
|
// toWordSize returns the ceiled word size required for memory expansion.
|
||||||
func toWordSize(size uint64) uint64 {
|
func toWordSize(size uint64) uint64 {
|
||||||
if size > math.MaxUint64-31 {
|
if size > math.MaxUint64-31 {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContractRef is a reference to the contract's backing object
|
// ContractRef is a reference to the contract's backing object
|
||||||
|
|
@ -81,11 +82,11 @@ func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uin
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Contract) validJumpdest(dest *big.Int) bool {
|
func (c *Contract) validJumpdest(dest *uint256.Int) bool {
|
||||||
udest := dest.Uint64()
|
udest, overflow := dest.Uint64WithOverflow()
|
||||||
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
|
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
|
||||||
// Don't bother checking for JUMPDEST in that case.
|
// Don't bother checking for JUMPDEST in that case.
|
||||||
if dest.BitLen() >= 63 || udest >= uint64(len(c.Code)) {
|
if overflow || udest >= uint64(len(c.Code)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Only JUMPDESTs allowed for destinations
|
// Only JUMPDESTs allowed for destinations
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,8 @@ func enable1884(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
balance := interpreter.intPool.get().Set(interpreter.evm.StateDB.GetBalance(contract.Address()))
|
balance := interpreter.intPool.get()
|
||||||
|
balance.SetFromBig(interpreter.evm.StateDB.GetBalance(contract.Address()))
|
||||||
stack.push(balance)
|
stack.push(balance)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +82,8 @@ func enable1344(jt *JumpTable) {
|
||||||
|
|
||||||
// opChainID implements CHAINID opcode
|
// opChainID implements CHAINID opcode
|
||||||
func opChainID(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opChainID(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
chainId := interpreter.intPool.get().Set(interpreter.evm.chainConfig.ChainID)
|
chainId := interpreter.intPool.get()
|
||||||
|
chainId.SetFromBig(interpreter.evm.chainConfig.ChainID)
|
||||||
stack.push(chainId)
|
stack.push(chainId)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
|
||||||
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
|
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
|
||||||
// but is the correct thing to do and matters on other networks, in tests, and potential
|
// but is the correct thing to do and matters on other networks, in tests, and potential
|
||||||
// future scenarios
|
// future scenarios
|
||||||
evm.StateDB.AddBalance(addr, bigZero)
|
evm.StateDB.AddBalance(addr, big.NewInt(0))
|
||||||
|
|
||||||
// When an error was returned by the EVM or when setting the creation code
|
// When an error was returned by the EVM or when setting the creation code
|
||||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Gas costs
|
// Gas costs
|
||||||
|
|
@ -34,7 +34,7 @@ const (
|
||||||
//
|
//
|
||||||
// The cost of gas was changed during the homestead price change HF.
|
// The cost of gas was changed during the homestead price change HF.
|
||||||
// As part of EIP 150 (TangerineWhistle), the returned gas is gas - base * 63 / 64.
|
// As part of EIP 150 (TangerineWhistle), the returned gas is gas - base * 63 / 64.
|
||||||
func callGas(isEip150 bool, availableGas, base uint64, callCost *big.Int) (uint64, error) {
|
func callGas(isEip150 bool, availableGas, base uint64, callCost *uint256.Int) (uint64, error) {
|
||||||
if isEip150 {
|
if isEip150 {
|
||||||
availableGas = availableGas - base
|
availableGas = availableGas - base
|
||||||
gas := availableGas - availableGas/64
|
gas := availableGas - availableGas/64
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ func memoryCopierGas(stackpos int) gasFunc {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
// And gas for copying data, charged per word at param.CopyGas
|
// And gas for copying data, charged per word at param.CopyGas
|
||||||
words, overflow := bigUint64(stack.Back(stackpos))
|
words, overflow := stack.Back(stackpos).Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, errGasUintOverflow
|
return 0, errGasUintOverflow
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +96,7 @@ var (
|
||||||
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
y, x = stack.Back(1), stack.Back(0)
|
y, x = stack.Back(1), stack.Back(0)
|
||||||
current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
current = evm.StateDB.GetState(contract.Address(), common.Hash(x.Bytes32()))
|
||||||
)
|
)
|
||||||
// The legacy gas metering only takes into consideration the current state
|
// The legacy gas metering only takes into consideration the current state
|
||||||
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
|
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
|
||||||
|
|
@ -131,11 +131,11 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi
|
||||||
// 2.2.2. If original value equals new value (this storage slot is reset)
|
// 2.2.2. If original value equals new value (this storage slot is reset)
|
||||||
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
|
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
|
||||||
// 2.2.2.2. Otherwise, add 4800 gas to refund counter.
|
// 2.2.2.2. Otherwise, add 4800 gas to refund counter.
|
||||||
value := common.BigToHash(y)
|
value := common.Hash(y.Bytes32())
|
||||||
if current == value { // noop (1)
|
if current == value { // noop (1)
|
||||||
return params.NetSstoreNoopGas, nil
|
return params.NetSstoreNoopGas, nil
|
||||||
}
|
}
|
||||||
original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
|
original := evm.StateDB.GetCommittedState(contract.Address(), common.Hash(x.Bytes32()))
|
||||||
if original == current {
|
if original == current {
|
||||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||||
return params.NetSstoreInitGas, nil
|
return params.NetSstoreInitGas, nil
|
||||||
|
|
@ -183,14 +183,14 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
||||||
// Gas sentry honoured, do the actual gas calculation based on the stored value
|
// Gas sentry honoured, do the actual gas calculation based on the stored value
|
||||||
var (
|
var (
|
||||||
y, x = stack.Back(1), stack.Back(0)
|
y, x = stack.Back(1), stack.Back(0)
|
||||||
current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
current = evm.StateDB.GetState(contract.Address(), common.Hash(x.Bytes32()))
|
||||||
)
|
)
|
||||||
value := common.BigToHash(y)
|
value := common.Hash(y.Bytes32())
|
||||||
|
|
||||||
if current == value { // noop (1)
|
if current == value { // noop (1)
|
||||||
return params.SstoreNoopGasEIP2200, nil
|
return params.SstoreNoopGasEIP2200, nil
|
||||||
}
|
}
|
||||||
original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
|
original := evm.StateDB.GetCommittedState(contract.Address(), common.Hash(x.Bytes32()))
|
||||||
if original == current {
|
if original == current {
|
||||||
if original == (common.Hash{}) { // create slot (2.1.1)
|
if original == (common.Hash{}) { // create slot (2.1.1)
|
||||||
return params.SstoreInitGasEIP2200, nil
|
return params.SstoreInitGasEIP2200, nil
|
||||||
|
|
@ -219,7 +219,7 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m
|
||||||
|
|
||||||
func makeGasLog(n uint64) gasFunc {
|
func makeGasLog(n uint64) gasFunc {
|
||||||
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
requestedSize, overflow := bigUint64(stack.Back(1))
|
requestedSize, overflow := stack.Back(1).Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, errGasUintOverflow
|
return 0, errGasUintOverflow
|
||||||
}
|
}
|
||||||
|
|
@ -252,7 +252,7 @@ func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
wordGas, overflow := bigUint64(stack.Back(1))
|
wordGas, overflow := stack.Back(1).Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, errGasUintOverflow
|
return 0, errGasUintOverflow
|
||||||
}
|
}
|
||||||
|
|
@ -286,7 +286,7 @@ func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memoryS
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
wordGas, overflow := bigUint64(stack.Back(2))
|
wordGas, overflow := stack.Back(2).Uint64WithOverflow()
|
||||||
if overflow {
|
if overflow {
|
||||||
return 0, errGasUintOverflow
|
return 0, errGasUintOverflow
|
||||||
}
|
}
|
||||||
|
|
@ -328,8 +328,8 @@ func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor
|
||||||
func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
gas uint64
|
gas uint64
|
||||||
transfersValue = stack.Back(2).Sign() != 0
|
transfersValue = !stack.Back(2).IsZero()
|
||||||
address = common.BigToAddress(stack.Back(1))
|
address = common.Address(stack.Back(1).Bytes20())
|
||||||
)
|
)
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.IsEIP158 {
|
||||||
if transfersValue && evm.StateDB.Empty(address) {
|
if transfersValue && evm.StateDB.Empty(address) {
|
||||||
|
|
@ -422,7 +422,7 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me
|
||||||
// EIP150 homestead gas reprice fork:
|
// EIP150 homestead gas reprice fork:
|
||||||
if evm.chainRules.IsEIP150 {
|
if evm.chainRules.IsEIP150 {
|
||||||
gas = params.SelfdestructGasEIP150
|
gas = params.SelfdestructGasEIP150
|
||||||
var address = common.BigToAddress(stack.Back(0))
|
var address = common.Address(stack.Back(0).Bytes20())
|
||||||
|
|
||||||
if evm.chainRules.IsEIP158 {
|
if evm.chainRules.IsEIP158 {
|
||||||
// if empty and transfers value
|
// if empty and transfers value
|
||||||
|
|
|
||||||
|
|
@ -18,18 +18,14 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bigZero = new(big.Int)
|
|
||||||
tt255 = math.BigPow(2, 255)
|
|
||||||
errWriteProtection = errors.New("evm: write protection")
|
errWriteProtection = errors.New("evm: write protection")
|
||||||
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
||||||
errExecutionReverted = errors.New("evm: execution reverted")
|
errExecutionReverted = errors.New("evm: execution reverted")
|
||||||
|
|
@ -39,142 +35,78 @@ var (
|
||||||
|
|
||||||
func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opAdd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
math.U256(y.Add(x, y))
|
y.Add(x, y)
|
||||||
|
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSub(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
math.U256(y.Sub(x, y))
|
y.Sub(x, y)
|
||||||
|
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opMul(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
stack.push(math.U256(x.Mul(x, y)))
|
y.Mul(x, y)
|
||||||
|
interpreter.intPool.put(x)
|
||||||
interpreter.intPool.put(y)
|
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opDiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
if y.Sign() != 0 {
|
y.Div(x, y)
|
||||||
math.U256(y.Div(x, y))
|
|
||||||
} else {
|
|
||||||
y.SetUint64(0)
|
|
||||||
}
|
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSdiv(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
x, y := stack.pop(), stack.peek()
|
||||||
res := interpreter.intPool.getZero()
|
y.Sdiv(x, y)
|
||||||
|
interpreter.intPool.put(x)
|
||||||
if y.Sign() == 0 || x.Sign() == 0 {
|
|
||||||
stack.push(res)
|
|
||||||
} else {
|
|
||||||
if x.Sign() != y.Sign() {
|
|
||||||
res.Div(x.Abs(x), y.Abs(y))
|
|
||||||
res.Neg(res)
|
|
||||||
} else {
|
|
||||||
res.Div(x.Abs(x), y.Abs(y))
|
|
||||||
}
|
|
||||||
stack.push(math.U256(res))
|
|
||||||
}
|
|
||||||
interpreter.intPool.put(x, y)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opMod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
if y.Sign() == 0 {
|
y.Mod(x, y)
|
||||||
stack.push(x.SetUint64(0))
|
interpreter.intPool.put(x)
|
||||||
} else {
|
|
||||||
stack.push(math.U256(x.Mod(x, y)))
|
|
||||||
}
|
|
||||||
interpreter.intPool.put(y)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := math.S256(stack.pop()), math.S256(stack.pop())
|
x, y := stack.pop(), stack.peek()
|
||||||
res := interpreter.intPool.getZero()
|
y.Smod(x, y)
|
||||||
|
interpreter.intPool.put(x)
|
||||||
if y.Sign() == 0 {
|
|
||||||
stack.push(res)
|
|
||||||
} else {
|
|
||||||
if x.Sign() < 0 {
|
|
||||||
res.Mod(x.Abs(x), y.Abs(y))
|
|
||||||
res.Neg(res)
|
|
||||||
} else {
|
|
||||||
res.Mod(x.Abs(x), y.Abs(y))
|
|
||||||
}
|
|
||||||
stack.push(math.U256(res))
|
|
||||||
}
|
|
||||||
interpreter.intPool.put(x, y)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opExp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
base, exponent := stack.pop(), stack.pop()
|
base, exponent := stack.pop(), stack.peek()
|
||||||
// some shortcuts
|
exponent.Exp(base, exponent)
|
||||||
cmpToOne := exponent.Cmp(big1)
|
interpreter.intPool.put(base)
|
||||||
if cmpToOne < 0 { // Exponent is zero
|
|
||||||
// x ^ 0 == 1
|
|
||||||
stack.push(base.SetUint64(1))
|
|
||||||
} else if base.Sign() == 0 {
|
|
||||||
// 0 ^ y, if y != 0, == 0
|
|
||||||
stack.push(base.SetUint64(0))
|
|
||||||
} else if cmpToOne == 0 { // Exponent is one
|
|
||||||
// x ^ 1 == x
|
|
||||||
stack.push(base)
|
|
||||||
} else {
|
|
||||||
stack.push(math.Exp(base, exponent))
|
|
||||||
interpreter.intPool.put(base)
|
|
||||||
}
|
|
||||||
interpreter.intPool.put(exponent)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSignExtend(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
back := stack.pop()
|
back, num := stack.pop(), stack.peek()
|
||||||
if back.Cmp(big.NewInt(31)) < 0 {
|
num.SignExtend(back, num)
|
||||||
bit := uint(back.Uint64()*8 + 7)
|
|
||||||
num := stack.pop()
|
|
||||||
mask := back.Lsh(common.Big1, bit)
|
|
||||||
mask.Sub(mask, common.Big1)
|
|
||||||
if num.Bit(int(bit)) > 0 {
|
|
||||||
num.Or(num, mask.Not(mask))
|
|
||||||
} else {
|
|
||||||
num.And(num, mask)
|
|
||||||
}
|
|
||||||
|
|
||||||
stack.push(math.U256(num))
|
|
||||||
}
|
|
||||||
|
|
||||||
interpreter.intPool.put(back)
|
interpreter.intPool.put(back)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opNot(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x := stack.peek()
|
stack.peek().Not()
|
||||||
math.U256(x.Not(x))
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(y) < 0 {
|
if x.Lt(y) {
|
||||||
y.SetUint64(1)
|
y.SetOne()
|
||||||
} else {
|
} else {
|
||||||
y.SetUint64(0)
|
y.Clear()
|
||||||
}
|
}
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -182,10 +114,10 @@ func opLt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *M
|
||||||
|
|
||||||
func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(y) > 0 {
|
if x.Gt(y) {
|
||||||
y.SetUint64(1)
|
y.SetOne()
|
||||||
} else {
|
} else {
|
||||||
y.SetUint64(0)
|
y.Clear()
|
||||||
}
|
}
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -193,23 +125,10 @@ func opGt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *M
|
||||||
|
|
||||||
func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
|
if x.Slt(y) {
|
||||||
xSign := x.Cmp(tt255)
|
y.SetOne()
|
||||||
ySign := y.Cmp(tt255)
|
} else {
|
||||||
|
y.Clear()
|
||||||
switch {
|
|
||||||
case xSign >= 0 && ySign < 0:
|
|
||||||
y.SetUint64(1)
|
|
||||||
|
|
||||||
case xSign < 0 && ySign >= 0:
|
|
||||||
y.SetUint64(0)
|
|
||||||
|
|
||||||
default:
|
|
||||||
if x.Cmp(y) < 0 {
|
|
||||||
y.SetUint64(1)
|
|
||||||
} else {
|
|
||||||
y.SetUint64(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -217,23 +136,10 @@ func opSlt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
|
||||||
|
|
||||||
func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
|
if x.Sgt(y) {
|
||||||
xSign := x.Cmp(tt255)
|
y.SetOne()
|
||||||
ySign := y.Cmp(tt255)
|
} else {
|
||||||
|
y.Clear()
|
||||||
switch {
|
|
||||||
case xSign >= 0 && ySign < 0:
|
|
||||||
y.SetUint64(0)
|
|
||||||
|
|
||||||
case xSign < 0 && ySign >= 0:
|
|
||||||
y.SetUint64(1)
|
|
||||||
|
|
||||||
default:
|
|
||||||
if x.Cmp(y) > 0 {
|
|
||||||
y.SetUint64(1)
|
|
||||||
} else {
|
|
||||||
y.SetUint64(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -241,37 +147,31 @@ func opSgt(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
|
||||||
|
|
||||||
func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opEq(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
if x.Cmp(y) == 0 {
|
y.SetIfEq(x)
|
||||||
y.SetUint64(1)
|
|
||||||
} else {
|
|
||||||
y.SetUint64(0)
|
|
||||||
}
|
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opIszero(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x := stack.peek()
|
x := stack.peek()
|
||||||
if x.Sign() > 0 {
|
if x.IsZero() {
|
||||||
x.SetUint64(0)
|
x.SetOne()
|
||||||
} else {
|
} else {
|
||||||
x.SetUint64(1)
|
x.Clear()
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opAnd(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.pop()
|
x, y := stack.pop(), stack.peek()
|
||||||
stack.push(x.And(x, y))
|
y.And(x, y)
|
||||||
|
interpreter.intPool.put(x)
|
||||||
interpreter.intPool.put(y)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
y.Or(x, y)
|
y.Or(x, y)
|
||||||
|
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -279,46 +179,32 @@ func opOr(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *M
|
||||||
func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opXor(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y := stack.pop(), stack.peek()
|
x, y := stack.pop(), stack.peek()
|
||||||
y.Xor(x, y)
|
y.Xor(x, y)
|
||||||
|
|
||||||
interpreter.intPool.put(x)
|
interpreter.intPool.put(x)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opByte(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
th, val := stack.pop(), stack.peek()
|
th, val := stack.pop(), stack.peek()
|
||||||
if th.Cmp(common.Big32) < 0 {
|
val.Byte(th)
|
||||||
b := math.Byte(val, 32, int(th.Int64()))
|
|
||||||
val.SetUint64(uint64(b))
|
|
||||||
} else {
|
|
||||||
val.SetUint64(0)
|
|
||||||
}
|
|
||||||
interpreter.intPool.put(th)
|
interpreter.intPool.put(th)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opAddmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
x, y, z := stack.pop(), stack.pop(), stack.peek()
|
||||||
if z.Cmp(bigZero) > 0 {
|
if z.IsZero() {
|
||||||
x.Add(x, y)
|
z.Clear()
|
||||||
x.Mod(x, z)
|
|
||||||
stack.push(math.U256(x))
|
|
||||||
} else {
|
} else {
|
||||||
stack.push(x.SetUint64(0))
|
z.AddMod(x, y, z)
|
||||||
}
|
}
|
||||||
interpreter.intPool.put(y, z)
|
interpreter.intPool.put(x, y)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
x, y, z := stack.pop(), stack.pop(), stack.pop()
|
x, y, z := stack.pop(), stack.pop(), stack.peek()
|
||||||
if z.Cmp(bigZero) > 0 {
|
z.MulMod(x, y, z)
|
||||||
x.Mul(x, y)
|
interpreter.intPool.put(x, y)
|
||||||
x.Mod(x, z)
|
|
||||||
stack.push(math.U256(x))
|
|
||||||
} else {
|
|
||||||
stack.push(x.SetUint64(0))
|
|
||||||
}
|
|
||||||
interpreter.intPool.put(y, z)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,16 +213,13 @@ func opMulmod(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
|
||||||
// and pushes on the stack arg2 shifted to the left by arg1 number of bits.
|
// and pushes on the stack arg2 shifted to the left by arg1 number of bits.
|
||||||
func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
|
// 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())
|
shift, value := stack.pop(), stack.peek()
|
||||||
defer interpreter.intPool.put(shift) // First operand back into the pool
|
if shift.LtUint64(256) {
|
||||||
|
value.Lsh(value, uint(shift.Uint64()))
|
||||||
if shift.Cmp(common.Big256) >= 0 {
|
} else {
|
||||||
value.SetUint64(0)
|
value.Clear()
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
n := uint(shift.Uint64())
|
interpreter.intPool.put(shift) // First operand back into the pool
|
||||||
math.U256(value.Lsh(value, n))
|
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -345,16 +228,13 @@ func opSHL(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
|
||||||
// and pushes on the stack arg2 shifted to the right by arg1 number of bits with zero fill.
|
// 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 *Memory, stack *Stack) ([]byte, error) {
|
func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// Note, second operand is left in the stack; accumulate result into it, and no need to push it afterwards
|
// 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())
|
shift, value := stack.pop(), stack.peek()
|
||||||
defer interpreter.intPool.put(shift) // First operand back into the pool
|
if shift.LtUint64(256) {
|
||||||
|
value.Rsh(value, uint(shift.Uint64()))
|
||||||
if shift.Cmp(common.Big256) >= 0 {
|
} else {
|
||||||
value.SetUint64(0)
|
value.Clear()
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
n := uint(shift.Uint64())
|
interpreter.intPool.put(shift) // First operand back into the pool
|
||||||
math.U256(value.Rsh(value, n))
|
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -362,28 +242,23 @@ func opSHR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *
|
||||||
// The SAR instruction (arithmetic shift right) pops 2 values from the stack, first arg1 and then arg2,
|
// 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.
|
// 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 *Memory, stack *Stack) ([]byte, error) {
|
func opSAR(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// Note, S256 returns (potentially) a new bigint, so we're popping, not peeking this one
|
shift, value := stack.pop(), stack.peek()
|
||||||
shift, value := math.U256(stack.pop()), math.S256(stack.pop())
|
if shift.GtUint64(256) {
|
||||||
defer interpreter.intPool.put(shift) // First operand back into the pool
|
|
||||||
|
|
||||||
if shift.Cmp(common.Big256) >= 0 {
|
|
||||||
if value.Sign() >= 0 {
|
if value.Sign() >= 0 {
|
||||||
value.SetUint64(0)
|
value.Clear()
|
||||||
} else {
|
} else {
|
||||||
value.SetInt64(-1)
|
// Max negative shift: all bits set
|
||||||
|
value.SetAllOne()
|
||||||
}
|
}
|
||||||
stack.push(math.U256(value))
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
n := uint(shift.Uint64())
|
n := uint(shift.Uint64())
|
||||||
value.Rsh(value, n)
|
value.Srsh(value, n)
|
||||||
stack.push(math.U256(value))
|
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
offset, size := stack.pop(), stack.pop()
|
offset, size := stack.pop(), stack.peek()
|
||||||
data := memory.GetPtr(offset.Int64(), size.Int64())
|
data := memory.GetPtr(offset.Int64(), size.Int64())
|
||||||
|
|
||||||
if interpreter.hasher == nil {
|
if interpreter.hasher == nil {
|
||||||
|
|
@ -398,9 +273,8 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
|
||||||
if evm.vmConfig.EnablePreimageRecording {
|
if evm.vmConfig.EnablePreimageRecording {
|
||||||
evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
|
evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
|
||||||
}
|
}
|
||||||
stack.push(interpreter.intPool.get().SetBytes(interpreter.hasherBuf[:]))
|
size.SetBytes(interpreter.hasherBuf[:])
|
||||||
|
interpreter.intPool.put(offset)
|
||||||
interpreter.intPool.put(offset, size)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -411,7 +285,8 @@ func opAddress(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
|
||||||
|
|
||||||
func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opBalance(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
slot := stack.peek()
|
slot := stack.peek()
|
||||||
slot.Set(interpreter.evm.StateDB.GetBalance(common.BigToAddress(slot)))
|
address := common.Address(slot.Bytes20())
|
||||||
|
slot.SetFromBig(interpreter.evm.StateDB.GetBalance(address))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -426,17 +301,25 @@ func opCaller(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCallValue(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(interpreter.intPool.get().Set(contract.value))
|
v := interpreter.intPool.get()
|
||||||
|
v.SetFromBig(contract.value)
|
||||||
|
stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCallDataLoad(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
|
x := stack.peek()
|
||||||
|
if offset, overflow := x.Uint64WithOverflow(); !overflow {
|
||||||
|
data := getData(contract.Input, offset, 32)
|
||||||
|
x.SetBytes(data)
|
||||||
|
} else {
|
||||||
|
x.Clear()
|
||||||
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCallDataSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(interpreter.intPool.get().SetInt64(int64(len(contract.Input))))
|
stack.push(interpreter.intPool.get().SetUint64(uint64(len(contract.Input))))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -446,7 +329,14 @@ func opCallDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
|
||||||
dataOffset = stack.pop()
|
dataOffset = stack.pop()
|
||||||
length = stack.pop()
|
length = stack.pop()
|
||||||
)
|
)
|
||||||
memory.Set(memOffset.Uint64(), length.Uint64(), getDataBig(contract.Input, dataOffset, length))
|
dataOffset64, overflow := dataOffset.Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
|
dataOffset64 = 0xffffffffffffffff
|
||||||
|
}
|
||||||
|
// These values are checked for overflow during gas cost calculation
|
||||||
|
memOffset64 := memOffset.Uint64()
|
||||||
|
length64 := length.Uint64()
|
||||||
|
memory.Set(memOffset64, length64, getData(contract.Input, dataOffset64, length64))
|
||||||
|
|
||||||
interpreter.intPool.put(memOffset, dataOffset, length)
|
interpreter.intPool.put(memOffset, dataOffset, length)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -462,28 +352,34 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contrac
|
||||||
memOffset = stack.pop()
|
memOffset = stack.pop()
|
||||||
dataOffset = stack.pop()
|
dataOffset = stack.pop()
|
||||||
length = stack.pop()
|
length = stack.pop()
|
||||||
|
end = interpreter.intPool.get()
|
||||||
end = interpreter.intPool.get().Add(dataOffset, length)
|
|
||||||
)
|
)
|
||||||
defer interpreter.intPool.put(memOffset, dataOffset, length, end)
|
defer interpreter.intPool.put(memOffset, dataOffset, length, end)
|
||||||
|
|
||||||
if !end.IsUint64() || uint64(len(interpreter.returnData)) < end.Uint64() {
|
offset64, overflow := dataOffset.Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
return nil, errReturnDataOutOfBounds
|
return nil, errReturnDataOutOfBounds
|
||||||
}
|
}
|
||||||
memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[dataOffset.Uint64():end.Uint64()])
|
end.Add(dataOffset, length)
|
||||||
|
end64, overflow := end.Uint64WithOverflow()
|
||||||
|
if overflow || uint64(len(interpreter.returnData)) < end64 {
|
||||||
|
return nil, errReturnDataOutOfBounds
|
||||||
|
}
|
||||||
|
memory.Set(memOffset.Uint64(), length.Uint64(), interpreter.returnData[offset64:end64])
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opExtCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
slot := stack.peek()
|
slot := stack.peek()
|
||||||
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.BigToAddress(slot))))
|
slot.SetUint64(uint64(interpreter.evm.StateDB.GetCodeSize(common.Address(slot.Bytes20()))))
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCodeSize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
l := interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
|
l := interpreter.intPool.get()
|
||||||
|
l.SetUint64(uint64(len(contract.Code)))
|
||||||
stack.push(l)
|
stack.push(l)
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -495,7 +391,11 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem
|
||||||
codeOffset = stack.pop()
|
codeOffset = stack.pop()
|
||||||
length = stack.pop()
|
length = stack.pop()
|
||||||
)
|
)
|
||||||
codeCopy := getDataBig(contract.Code, codeOffset, length)
|
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
|
uint64CodeOffset = 0xffffffffffffffff
|
||||||
|
}
|
||||||
|
codeCopy := getData(contract.Code, uint64CodeOffset, length.Uint64())
|
||||||
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||||
|
|
||||||
interpreter.intPool.put(memOffset, codeOffset, length)
|
interpreter.intPool.put(memOffset, codeOffset, length)
|
||||||
|
|
@ -504,15 +404,20 @@ func opCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem
|
||||||
|
|
||||||
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
addr = common.BigToAddress(stack.pop())
|
a = stack.pop()
|
||||||
memOffset = stack.pop()
|
memOffset = stack.pop()
|
||||||
codeOffset = stack.pop()
|
codeOffset = stack.pop()
|
||||||
length = stack.pop()
|
length = stack.pop()
|
||||||
)
|
)
|
||||||
codeCopy := getDataBig(interpreter.evm.StateDB.GetCode(addr), codeOffset, length)
|
uint64CodeOffset, overflow := codeOffset.Uint64WithOverflow()
|
||||||
|
if overflow {
|
||||||
|
uint64CodeOffset = 0xffffffffffffffff
|
||||||
|
}
|
||||||
|
addr := common.Address(a.Bytes20())
|
||||||
|
codeCopy := getData(interpreter.evm.StateDB.GetCode(addr), uint64CodeOffset, length.Uint64())
|
||||||
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy)
|
||||||
|
|
||||||
interpreter.intPool.put(memOffset, codeOffset, length)
|
interpreter.intPool.put(a, memOffset, codeOffset, length)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -544,9 +449,9 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
|
||||||
// this account should be regarded as a non-existent account and zero should be returned.
|
// this account should be regarded as a non-existent account and zero should be returned.
|
||||||
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
slot := stack.peek()
|
slot := stack.peek()
|
||||||
address := common.BigToAddress(slot)
|
address := common.Address(slot.Bytes20())
|
||||||
if interpreter.evm.StateDB.Empty(address) {
|
if interpreter.evm.StateDB.Empty(address) {
|
||||||
slot.SetUint64(0)
|
slot.Clear()
|
||||||
} else {
|
} else {
|
||||||
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes())
|
slot.SetBytes(interpreter.evm.StateDB.GetCodeHash(address).Bytes())
|
||||||
}
|
}
|
||||||
|
|
@ -554,20 +459,31 @@ func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opGasprice(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(interpreter.intPool.get().Set(interpreter.evm.GasPrice))
|
v := interpreter.intPool.get()
|
||||||
|
v.SetFromBig(interpreter.evm.GasPrice)
|
||||||
|
stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opBlockhash(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
num := stack.pop()
|
num := stack.peek()
|
||||||
|
num64, overflow := num.Uint64WithOverflow()
|
||||||
n := interpreter.intPool.get().Sub(interpreter.evm.BlockNumber, common.Big257)
|
if overflow {
|
||||||
if num.Cmp(n) > 0 && num.Cmp(interpreter.evm.BlockNumber) < 0 {
|
num.Clear()
|
||||||
stack.push(interpreter.evm.GetHash(num.Uint64()).Big())
|
return nil, nil
|
||||||
} else {
|
}
|
||||||
stack.push(interpreter.intPool.getZero())
|
var upper, lower uint64
|
||||||
|
upper = interpreter.evm.BlockNumber.Uint64()
|
||||||
|
if upper < 257 {
|
||||||
|
lower = 0
|
||||||
|
} else {
|
||||||
|
lower = upper - 256
|
||||||
|
}
|
||||||
|
if num64 >= lower && num64 < upper {
|
||||||
|
num.SetBytes(interpreter.evm.GetHash(num64).Bytes())
|
||||||
|
} else {
|
||||||
|
num.Clear()
|
||||||
}
|
}
|
||||||
interpreter.intPool.put(num, n)
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -577,22 +493,28 @@ func opCoinbase(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem
|
||||||
}
|
}
|
||||||
|
|
||||||
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opTimestamp(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Time)))
|
v := interpreter.intPool.get()
|
||||||
|
v.SetFromBig(interpreter.evm.Time)
|
||||||
|
stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opNumber(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.BlockNumber)))
|
v := interpreter.intPool.get()
|
||||||
|
v.SetFromBig(interpreter.evm.BlockNumber)
|
||||||
|
stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opDifficulty(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(math.U256(interpreter.intPool.get().Set(interpreter.evm.Difficulty)))
|
v := interpreter.intPool.get()
|
||||||
|
v.SetFromBig(interpreter.evm.Difficulty)
|
||||||
|
stack.push(v)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(math.U256(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit)))
|
stack.push(interpreter.intPool.get().SetUint64(interpreter.evm.GasLimit))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -618,25 +540,27 @@ func opMstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opMstore8(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
off, val := stack.pop().Int64(), stack.pop().Int64()
|
off, val := stack.pop(), stack.pop()
|
||||||
memory.store[off] = byte(val & 0xff)
|
memory.store[off.Int64()] = byte(val.Int64() & 0xff)
|
||||||
|
interpreter.intPool.put(off, val)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSload(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
loc := stack.peek()
|
loc := stack.peek()
|
||||||
val := interpreter.evm.StateDB.GetState(contract.Address(), common.BigToHash(loc))
|
hash := common.Hash(loc.Bytes32())
|
||||||
|
val := interpreter.evm.StateDB.GetState(contract.Address(), hash)
|
||||||
loc.SetBytes(val.Bytes())
|
loc.SetBytes(val.Bytes())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSstore(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
loc := common.BigToHash(stack.pop())
|
loc := stack.pop()
|
||||||
val := stack.pop()
|
val := stack.pop()
|
||||||
interpreter.evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val))
|
interpreter.evm.StateDB.SetState(contract.Address(),
|
||||||
|
common.Hash(loc.Bytes32()), common.Hash(val.Bytes32()))
|
||||||
|
|
||||||
interpreter.intPool.put(val)
|
interpreter.intPool.put(val, loc)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -653,7 +577,7 @@ func opJump(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
|
||||||
|
|
||||||
func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
pos, cond := stack.pop(), stack.pop()
|
pos, cond := stack.pop(), stack.pop()
|
||||||
if cond.Sign() != 0 {
|
if !cond.IsZero() {
|
||||||
if !contract.validJumpdest(pos) {
|
if !contract.validJumpdest(pos) {
|
||||||
return nil, errInvalidJump
|
return nil, errInvalidJump
|
||||||
}
|
}
|
||||||
|
|
@ -661,7 +585,6 @@ func opJumpi(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
|
||||||
} else {
|
} else {
|
||||||
*pc++
|
*pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
interpreter.intPool.put(pos, cond)
|
interpreter.intPool.put(pos, cond)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -676,7 +599,7 @@ func opPc(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *M
|
||||||
}
|
}
|
||||||
|
|
||||||
func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opMsize(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
stack.push(interpreter.intPool.get().SetInt64(int64(memory.Len())))
|
stack.push(interpreter.intPool.get().SetUint64(uint64(memory.Len())))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -695,22 +618,25 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memor
|
||||||
if interpreter.evm.chainRules.IsEIP150 {
|
if interpreter.evm.chainRules.IsEIP150 {
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
}
|
}
|
||||||
|
// reuse size int for stackvalue
|
||||||
|
stackvalue := size
|
||||||
|
|
||||||
contract.UseGas(gas)
|
contract.UseGas(gas)
|
||||||
res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value)
|
res, addr, returnGas, suberr := interpreter.evm.Create(contract, input, gas, value.ToBig())
|
||||||
// Push item on the stack based on the returned error. If the ruleset is
|
// Push item on the stack based on the returned error. If the ruleset is
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
// ignore this error and pretend the operation was successful.
|
// ignore this error and pretend the operation was successful.
|
||||||
if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
|
if interpreter.evm.chainRules.IsHomestead && suberr == ErrCodeStoreOutOfGas {
|
||||||
stack.push(interpreter.intPool.getZero())
|
stackvalue.Clear()
|
||||||
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||||
stack.push(interpreter.intPool.getZero())
|
stackvalue.Clear()
|
||||||
} else {
|
} else {
|
||||||
stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
|
stackvalue.SetBytes(addr.Bytes())
|
||||||
}
|
}
|
||||||
|
stack.push(stackvalue)
|
||||||
contract.Gas += returnGas
|
contract.Gas += returnGas
|
||||||
interpreter.intPool.put(value, offset, size)
|
interpreter.intPool.put(value, offset)
|
||||||
|
|
||||||
if suberr == errExecutionReverted {
|
if suberr == errExecutionReverted {
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
@ -730,15 +656,19 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
|
||||||
// Apply EIP150
|
// Apply EIP150
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
contract.UseGas(gas)
|
contract.UseGas(gas)
|
||||||
res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas, endowment, salt)
|
// reuse size int for stackvalue
|
||||||
|
stackvalue := size
|
||||||
|
res, addr, returnGas, suberr := interpreter.evm.Create2(contract, input, gas,
|
||||||
|
endowment.ToBig(), salt.ToBig())
|
||||||
// Push item on the stack based on the returned error.
|
// Push item on the stack based on the returned error.
|
||||||
if suberr != nil {
|
if suberr != nil {
|
||||||
stack.push(interpreter.intPool.getZero())
|
stackvalue.Clear()
|
||||||
} else {
|
} else {
|
||||||
stack.push(interpreter.intPool.get().SetBytes(addr.Bytes()))
|
stackvalue.SetBytes(addr.Bytes())
|
||||||
}
|
}
|
||||||
|
stack.push(stackvalue)
|
||||||
contract.Gas += returnGas
|
contract.Gas += returnGas
|
||||||
interpreter.intPool.put(endowment, offset, size, salt)
|
interpreter.intPool.put(endowment, offset, salt)
|
||||||
|
|
||||||
if suberr == errExecutionReverted {
|
if suberr == errExecutionReverted {
|
||||||
return res, nil
|
return res, nil
|
||||||
|
|
@ -748,24 +678,25 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memo
|
||||||
|
|
||||||
func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// Pop gas. The actual gas in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas in interpreter.evm.callGasTemp.
|
||||||
interpreter.intPool.put(stack.pop())
|
// We can use this as a temporary value
|
||||||
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := interpreter.evm.callGasTemp
|
||||||
// Pop other call parameters.
|
// Pop other call parameters.
|
||||||
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.BigToAddress(addr)
|
toAddr := common.Address(addr.Bytes20())
|
||||||
value = math.U256(value)
|
|
||||||
// Get the arguments from the memory.
|
// Get the arguments from the memory.
|
||||||
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
|
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
|
||||||
|
|
||||||
if value.Sign() != 0 {
|
if !value.IsZero() {
|
||||||
gas += params.CallStipend
|
gas += params.CallStipend
|
||||||
}
|
}
|
||||||
ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value)
|
ret, returnGas, err := interpreter.evm.Call(contract, toAddr, args, gas, value.ToBig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(interpreter.intPool.getZero())
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
stack.push(interpreter.intPool.get().SetUint64(1))
|
temp.SetOne()
|
||||||
}
|
}
|
||||||
|
stack.push(temp)
|
||||||
if err == nil || err == errExecutionReverted {
|
if err == nil || err == errExecutionReverted {
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
@ -777,24 +708,25 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
|
||||||
|
|
||||||
func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
||||||
interpreter.intPool.put(stack.pop())
|
// We use it as a temporary value
|
||||||
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := interpreter.evm.callGasTemp
|
||||||
// Pop other call parameters.
|
// Pop other call parameters.
|
||||||
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.BigToAddress(addr)
|
toAddr := common.Address(addr.Bytes20())
|
||||||
value = math.U256(value)
|
|
||||||
// Get arguments from the memory.
|
// Get arguments from the memory.
|
||||||
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
|
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
|
||||||
|
|
||||||
if value.Sign() != 0 {
|
if !value.IsZero() {
|
||||||
gas += params.CallStipend
|
gas += params.CallStipend
|
||||||
}
|
}
|
||||||
ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value)
|
ret, returnGas, err := interpreter.evm.CallCode(contract, toAddr, args, gas, value.ToBig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(interpreter.intPool.getZero())
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
stack.push(interpreter.intPool.get().SetUint64(1))
|
temp.SetOne()
|
||||||
}
|
}
|
||||||
|
stack.push(temp)
|
||||||
if err == nil || err == errExecutionReverted {
|
if err == nil || err == errExecutionReverted {
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
@ -806,20 +738,22 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, contract *Contract, mem
|
||||||
|
|
||||||
func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
||||||
interpreter.intPool.put(stack.pop())
|
// We use it as a temporary value
|
||||||
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := interpreter.evm.callGasTemp
|
||||||
// Pop other call parameters.
|
// Pop other call parameters.
|
||||||
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.BigToAddress(addr)
|
toAddr := common.Address(addr.Bytes20())
|
||||||
// Get arguments from the memory.
|
// Get arguments from the memory.
|
||||||
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
|
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
|
||||||
|
|
||||||
ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas)
|
ret, returnGas, err := interpreter.evm.DelegateCall(contract, toAddr, args, gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(interpreter.intPool.getZero())
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
stack.push(interpreter.intPool.get().SetUint64(1))
|
temp.SetOne()
|
||||||
}
|
}
|
||||||
|
stack.push(temp)
|
||||||
if err == nil || err == errExecutionReverted {
|
if err == nil || err == errExecutionReverted {
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
@ -831,20 +765,22 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract,
|
||||||
|
|
||||||
func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opStaticCall(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
// Pop gas. The actual gas is in interpreter.evm.callGasTemp.
|
||||||
interpreter.intPool.put(stack.pop())
|
// We use it as a temporary value
|
||||||
|
temp := stack.pop()
|
||||||
gas := interpreter.evm.callGasTemp
|
gas := interpreter.evm.callGasTemp
|
||||||
// Pop other call parameters.
|
// Pop other call parameters.
|
||||||
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
addr, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
|
||||||
toAddr := common.BigToAddress(addr)
|
toAddr := common.Address(addr.Bytes20())
|
||||||
// Get arguments from the memory.
|
// Get arguments from the memory.
|
||||||
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
|
args := memory.GetPtr(inOffset.Int64(), inSize.Int64())
|
||||||
|
|
||||||
ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas)
|
ret, returnGas, err := interpreter.evm.StaticCall(contract, toAddr, args, gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(interpreter.intPool.getZero())
|
temp.Clear()
|
||||||
} else {
|
} else {
|
||||||
stack.push(interpreter.intPool.get().SetUint64(1))
|
temp.SetOne()
|
||||||
}
|
}
|
||||||
|
stack.push(temp)
|
||||||
if err == nil || err == errExecutionReverted {
|
if err == nil || err == errExecutionReverted {
|
||||||
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
}
|
}
|
||||||
|
|
@ -875,8 +811,9 @@ func opStop(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
|
||||||
}
|
}
|
||||||
|
|
||||||
func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opSuicide(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
beneficiary := stack.pop()
|
||||||
balance := interpreter.evm.StateDB.GetBalance(contract.Address())
|
balance := interpreter.evm.StateDB.GetBalance(contract.Address())
|
||||||
interpreter.evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance)
|
interpreter.evm.StateDB.AddBalance(common.Address(beneficiary.Bytes20()), balance)
|
||||||
|
|
||||||
interpreter.evm.StateDB.Suicide(contract.Address())
|
interpreter.evm.StateDB.Suicide(contract.Address())
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
@ -890,7 +827,7 @@ func makeLog(size int) executionFunc {
|
||||||
topics := make([]common.Hash, size)
|
topics := make([]common.Hash, size)
|
||||||
mStart, mSize := stack.pop(), stack.pop()
|
mStart, mSize := stack.pop(), stack.pop()
|
||||||
for i := 0; i < size; i++ {
|
for i := 0; i < size; i++ {
|
||||||
topics[i] = common.BigToHash(stack.pop())
|
topics[i] = common.Hash(stack.pop().Bytes32())
|
||||||
}
|
}
|
||||||
|
|
||||||
d := memory.GetCopy(mStart.Int64(), mSize.Int64())
|
d := memory.GetCopy(mStart.Int64(), mSize.Int64())
|
||||||
|
|
@ -918,7 +855,7 @@ func opPush1(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory
|
||||||
if *pc < codeLen {
|
if *pc < codeLen {
|
||||||
stack.push(integer.SetUint64(uint64(contract.Code[*pc])))
|
stack.push(integer.SetUint64(uint64(contract.Code[*pc])))
|
||||||
} else {
|
} else {
|
||||||
stack.push(integer.SetUint64(0))
|
stack.push(integer.Clear())
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TwoOperandTestcase struct {
|
type TwoOperandTestcase struct {
|
||||||
|
|
@ -97,16 +98,17 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
evmInterpreter = env.interpreter.(*EVMInterpreter)
|
evmInterpreter = env.interpreter.(*EVMInterpreter)
|
||||||
)
|
)
|
||||||
// Stuff a couple of nonzero bigints into pool, to ensure that ops do not rely on pooled integers to be zero
|
// Stuff a couple of nonzero ints into pool, to ensure that ops do not rely on pooled integers to be zero
|
||||||
evmInterpreter.intPool = poolOfIntPools.get()
|
evmInterpreter.intPool = poolOfIntPools.get()
|
||||||
evmInterpreter.intPool.put(big.NewInt(-1337))
|
for i := 0; i < 4; i++ {
|
||||||
evmInterpreter.intPool.put(big.NewInt(-1337))
|
x, _ := uint256.FromBig(big.NewInt(-1337))
|
||||||
evmInterpreter.intPool.put(big.NewInt(-1337))
|
evmInterpreter.intPool.put(x)
|
||||||
|
}
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
x := new(big.Int).SetBytes(common.Hex2Bytes(test.X))
|
x := new(uint256.Int).SetBytes(common.Hex2Bytes(test.X))
|
||||||
y := new(big.Int).SetBytes(common.Hex2Bytes(test.Y))
|
y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Y))
|
||||||
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
||||||
stack.push(x)
|
stack.push(x)
|
||||||
stack.push(y)
|
stack.push(y)
|
||||||
opFn(&pc, evmInterpreter, nil, nil, stack)
|
opFn(&pc, evmInterpreter, nil, nil, stack)
|
||||||
|
|
@ -120,7 +122,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
|
||||||
// 2.pool is not allowed to contain the same pointers twice
|
// 2.pool is not allowed to contain the same pointers twice
|
||||||
if evmInterpreter.intPool.pool.len() > 0 {
|
if evmInterpreter.intPool.pool.len() > 0 {
|
||||||
|
|
||||||
poolvals := make(map[*big.Int]struct{})
|
poolvals := make(map[*uint256.Int]struct{})
|
||||||
poolvals[actual] = struct{}{}
|
poolvals[actual] = struct{}{}
|
||||||
|
|
||||||
for evmInterpreter.intPool.pool.len() > 0 {
|
for evmInterpreter.intPool.pool.len() > 0 {
|
||||||
|
|
@ -208,6 +210,45 @@ func TestSAR(t *testing.T) {
|
||||||
testTwoOperandOp(t, tests, opSAR, "sar")
|
testTwoOperandOp(t, tests, opSAR, "sar")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddMod(t *testing.T) {
|
||||||
|
var (
|
||||||
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
||||||
|
stack = newstack()
|
||||||
|
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||||
|
pc = uint64(0)
|
||||||
|
)
|
||||||
|
tests := []struct {
|
||||||
|
x string
|
||||||
|
y string
|
||||||
|
z string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||||
|
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||||
|
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// x + y = 0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd
|
||||||
|
// in 256 bit repr, fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd
|
||||||
|
evmInterpreter.intPool = poolOfIntPools.get()
|
||||||
|
|
||||||
|
for i, test := range tests {
|
||||||
|
x := new(uint256.Int).SetBytes(common.Hex2Bytes(test.x))
|
||||||
|
y := new(uint256.Int).SetBytes(common.Hex2Bytes(test.y))
|
||||||
|
z := new(uint256.Int).SetBytes(common.Hex2Bytes(test.z))
|
||||||
|
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.expected))
|
||||||
|
stack.push(z)
|
||||||
|
stack.push(y)
|
||||||
|
stack.push(x)
|
||||||
|
opAddmod(&pc, evmInterpreter, nil, nil, stack)
|
||||||
|
actual := stack.pop()
|
||||||
|
if actual.Cmp(expected) != 0 {
|
||||||
|
t.Errorf("Testcase %d, expected %v, got %v", i, expected.Hex(), actual.Hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// getResult is a convenience function to generate the expected values
|
// getResult is a convenience function to generate the expected values
|
||||||
func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
|
func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
|
||||||
var (
|
var (
|
||||||
|
|
@ -219,8 +260,8 @@ func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcas
|
||||||
interpreter.intPool = poolOfIntPools.get()
|
interpreter.intPool = poolOfIntPools.get()
|
||||||
result := make([]TwoOperandTestcase, len(args))
|
result := make([]TwoOperandTestcase, len(args))
|
||||||
for i, param := range args {
|
for i, param := range args {
|
||||||
x := new(big.Int).SetBytes(common.Hex2Bytes(param.x))
|
x := new(uint256.Int).SetBytes(common.Hex2Bytes(param.x))
|
||||||
y := new(big.Int).SetBytes(common.Hex2Bytes(param.y))
|
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
|
||||||
stack.push(x)
|
stack.push(x)
|
||||||
stack.push(y)
|
stack.push(y)
|
||||||
opFn(&pc, interpreter, nil, nil, stack)
|
opFn(&pc, interpreter, nil, nil, stack)
|
||||||
|
|
@ -278,7 +319,8 @@ func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpret
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
for _, arg := range byteArgs {
|
for _, arg := range byteArgs {
|
||||||
a := new(big.Int).SetBytes(arg)
|
a := new(uint256.Int)
|
||||||
|
a.SetBytes(arg)
|
||||||
stack.push(a)
|
stack.push(a)
|
||||||
}
|
}
|
||||||
op(&pc, evmInterpreter, nil, nil, stack)
|
op(&pc, evmInterpreter, nil, nil, stack)
|
||||||
|
|
@ -508,12 +550,12 @@ func TestOpMstore(t *testing.T) {
|
||||||
mem.Resize(64)
|
mem.Resize(64)
|
||||||
pc := uint64(0)
|
pc := uint64(0)
|
||||||
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
||||||
stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0))
|
stack.pushN(new(uint256.Int).SetBytes(common.Hex2Bytes(v)), new(uint256.Int))
|
||||||
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
||||||
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
|
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
|
||||||
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
||||||
}
|
}
|
||||||
stack.pushN(big.NewInt(0x1), big.NewInt(0))
|
stack.pushN(new(uint256.Int).SetUint64(0x1), new(uint256.Int))
|
||||||
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
||||||
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
||||||
t.Fatalf("Mstore failed to overwrite previous value")
|
t.Fatalf("Mstore failed to overwrite previous value")
|
||||||
|
|
@ -533,8 +575,8 @@ func BenchmarkOpMstore(bench *testing.B) {
|
||||||
evmInterpreter.intPool = poolOfIntPools.get()
|
evmInterpreter.intPool = poolOfIntPools.get()
|
||||||
mem.Resize(64)
|
mem.Resize(64)
|
||||||
pc := uint64(0)
|
pc := uint64(0)
|
||||||
memStart := big.NewInt(0)
|
memStart := new(uint256.Int)
|
||||||
value := big.NewInt(0x1337)
|
value := new(uint256.Int).SetUint64(0x1337)
|
||||||
|
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
|
|
@ -555,11 +597,11 @@ func BenchmarkOpSHA3(bench *testing.B) {
|
||||||
evmInterpreter.intPool = poolOfIntPools.get()
|
evmInterpreter.intPool = poolOfIntPools.get()
|
||||||
mem.Resize(32)
|
mem.Resize(32)
|
||||||
pc := uint64(0)
|
pc := uint64(0)
|
||||||
start := big.NewInt(0)
|
start := uint256.NewInt()
|
||||||
|
|
||||||
bench.ResetTimer()
|
bench.ResetTimer()
|
||||||
for i := 0; i < bench.N; i++ {
|
for i := 0; i < bench.N; i++ {
|
||||||
stack.pushN(big.NewInt(32), start)
|
stack.pushN(uint256.NewInt().SetUint64(32), start)
|
||||||
opSha3(&pc, evmInterpreter, nil, mem, stack)
|
opSha3(&pc, evmInterpreter, nil, mem, stack)
|
||||||
}
|
}
|
||||||
poolOfIntPools.put(evmInterpreter.intPool)
|
poolOfIntPools.put(evmInterpreter.intPool)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ package vm
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var checkVal = big.NewInt(-42)
|
var checkVal = big.NewInt(-42)
|
||||||
|
|
@ -26,7 +28,7 @@ var checkVal = big.NewInt(-42)
|
||||||
const poolLimit = 256
|
const poolLimit = 256
|
||||||
|
|
||||||
// intPool is a pool of big integers that
|
// intPool is a pool of big integers that
|
||||||
// can be reused for all big.Int operations.
|
// can be reused for all uint256.Int operations.
|
||||||
type intPool struct {
|
type intPool struct {
|
||||||
pool *Stack
|
pool *Stack
|
||||||
}
|
}
|
||||||
|
|
@ -37,25 +39,25 @@ func newIntPool() *intPool {
|
||||||
|
|
||||||
// get retrieves a big int from the pool, allocating one if the pool is empty.
|
// get retrieves a big int from the pool, allocating one if the pool is empty.
|
||||||
// Note, the returned int's value is arbitrary and will not be zeroed!
|
// Note, the returned int's value is arbitrary and will not be zeroed!
|
||||||
func (p *intPool) get() *big.Int {
|
func (p *intPool) get() *uint256.Int {
|
||||||
if p.pool.len() > 0 {
|
if p.pool.len() > 0 {
|
||||||
return p.pool.pop()
|
return p.pool.pop()
|
||||||
}
|
}
|
||||||
return new(big.Int)
|
return new(uint256.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getZero retrieves a big int from the pool, setting it to zero or allocating
|
// getZero retrieves a big int from the pool, setting it to zero or allocating
|
||||||
// a new one if the pool is empty.
|
// a new one if the pool is empty.
|
||||||
func (p *intPool) getZero() *big.Int {
|
func (p *intPool) getZero() *uint256.Int {
|
||||||
if p.pool.len() > 0 {
|
if p.pool.len() > 0 {
|
||||||
return p.pool.pop().SetUint64(0)
|
return p.pool.pop().Clear()
|
||||||
}
|
}
|
||||||
return new(big.Int)
|
return new(uint256.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// put returns an allocated big int to the pool to be later reused by get calls.
|
// put returns an allocated big int to the pool to be later reused by get calls.
|
||||||
// Note, the values as saved as is; neither put nor get zeroes the ints out!
|
// Note, the values as saved as is; neither put nor get zeroes the ints out!
|
||||||
func (p *intPool) put(is ...*big.Int) {
|
func (p *intPool) put(is ...*uint256.Int) {
|
||||||
if len(p.pool.data) > poolLimit {
|
if len(p.pool.data) > poolLimit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +65,7 @@ func (p *intPool) put(is ...*big.Int) {
|
||||||
// verifyPool is a build flag. Pool verification makes sure the integrity
|
// verifyPool is a build flag. Pool verification makes sure the integrity
|
||||||
// of the integer pool by comparing values to a default value.
|
// of the integer pool by comparing values to a default value.
|
||||||
if verifyPool {
|
if verifyPool {
|
||||||
i.Set(checkVal)
|
i.SetFromBig(checkVal)
|
||||||
}
|
}
|
||||||
p.pool.push(i)
|
p.pool.push(i)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,8 +153,8 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
||||||
// it in the local storage container.
|
// it in the local storage container.
|
||||||
if op == SSTORE && stack.len() >= 2 {
|
if op == SSTORE && stack.len() >= 2 {
|
||||||
var (
|
var (
|
||||||
value = common.BigToHash(stack.data[stack.len()-2])
|
value = common.Hash(stack.data[stack.len()-2].Bytes32())
|
||||||
address = common.BigToHash(stack.data[stack.len()-1])
|
address = common.Hash(stack.data[stack.len()-1].Bytes32())
|
||||||
)
|
)
|
||||||
l.changedValues[contract.Address()][address] = value
|
l.changedValues[contract.Address()][address] = value
|
||||||
}
|
}
|
||||||
|
|
@ -169,7 +169,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
||||||
if !l.cfg.DisableStack {
|
if !l.cfg.DisableStack {
|
||||||
stck = make([]*big.Int, len(stack.Data()))
|
stck = make([]*big.Int, len(stack.Data()))
|
||||||
for i, item := range stack.Data() {
|
for i, item := range stack.Data() {
|
||||||
stck[i] = new(big.Int).Set(item)
|
stck[i] = new(big.Int).Set(item.ToBig())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Copy a snapshot of the current storage to a new container
|
// Copy a snapshot of the current storage to a new container
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,12 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
|
||||||
log.Memory = memory.Data()
|
log.Memory = memory.Data()
|
||||||
}
|
}
|
||||||
if !l.cfg.DisableStack {
|
if !l.cfg.DisableStack {
|
||||||
log.Stack = stack.Data()
|
//TODO(@holiman) improve this
|
||||||
|
logstack := make([]*big.Int, len(stack.Data()))
|
||||||
|
for i, item := range stack.Data() {
|
||||||
|
logstack[i] = item.ToBig()
|
||||||
|
}
|
||||||
|
log.Stack = logstack
|
||||||
}
|
}
|
||||||
return l.encoder.Encode(log)
|
return l.encoder.Encode(log)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
type dummyContractRef struct {
|
type dummyContractRef struct {
|
||||||
|
|
@ -56,8 +57,8 @@ func TestStoreCapture(t *testing.T) {
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
|
||||||
)
|
)
|
||||||
stack.push(big.NewInt(1))
|
stack.push(uint256.NewInt().SetUint64(1))
|
||||||
stack.push(big.NewInt(0))
|
stack.push(uint256.NewInt())
|
||||||
var index common.Hash
|
var index common.Hash
|
||||||
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil)
|
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, contract, 0, nil)
|
||||||
if len(logger.changedValues[contract.Address()]) == 0 {
|
if len(logger.changedValues[contract.Address()]) == 0 {
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,8 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Memory implements a simple memory model for the ethereum virtual machine.
|
// Memory implements a simple memory model for the ethereum virtual machine.
|
||||||
|
|
@ -50,7 +49,7 @@ func (m *Memory) Set(offset, size uint64, value []byte) {
|
||||||
|
|
||||||
// Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to
|
// Set32 sets the 32 bytes starting at offset to the value of val, left-padded with zeroes to
|
||||||
// 32 bytes.
|
// 32 bytes.
|
||||||
func (m *Memory) Set32(offset uint64, val *big.Int) {
|
func (m *Memory) Set32(offset uint64, val *uint256.Int) {
|
||||||
// length of store may never be less than offset + size.
|
// length of store may never be less than offset + size.
|
||||||
// The store should be resized PRIOR to setting the memory
|
// The store should be resized PRIOR to setting the memory
|
||||||
if offset+32 > uint64(len(m.store)) {
|
if offset+32 > uint64(len(m.store)) {
|
||||||
|
|
@ -59,7 +58,7 @@ func (m *Memory) Set32(offset uint64, val *big.Int) {
|
||||||
// Zero the memory area
|
// Zero the memory area
|
||||||
copy(m.store[offset:offset+32], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
copy(m.store[offset:offset+32], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
|
||||||
// Fill in relevant bits
|
// Fill in relevant bits
|
||||||
math.ReadBits(val, m.store[offset:offset+32])
|
val.WriteToSlice(m.store[offset:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize resizes the memory to size
|
// Resize resizes the memory to size
|
||||||
|
|
|
||||||
|
|
@ -18,36 +18,35 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Stack is an object for basic stack operations. Items popped to the stack are
|
// Stack is an object for basic stack operations. Items popped to the stack are
|
||||||
// expected to be changed and modified. stack does not take care of adding newly
|
// expected to be changed and modified. stack does not take care of adding newly
|
||||||
// initialised objects.
|
// initialised objects.
|
||||||
type Stack struct {
|
type Stack struct {
|
||||||
data []*big.Int
|
data []*uint256.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newstack() *Stack {
|
func newstack() *Stack {
|
||||||
return &Stack{data: make([]*big.Int, 0, 1024)}
|
return &Stack{data: make([]*uint256.Int, 0, 1024)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data returns the underlying big.Int array.
|
// Data returns the underlying uint256.Int array.
|
||||||
func (st *Stack) Data() []*big.Int {
|
func (st *Stack) Data() []*uint256.Int {
|
||||||
return st.data
|
return st.data
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) push(d *big.Int) {
|
func (st *Stack) push(d *uint256.Int) {
|
||||||
// NOTE push limit (1024) is checked in baseCheck
|
// NOTE push limit (1024) is checked in baseCheck
|
||||||
//stackItem := new(big.Int).Set(d)
|
|
||||||
//st.data = append(st.data, stackItem)
|
|
||||||
st.data = append(st.data, d)
|
st.data = append(st.data, d)
|
||||||
}
|
}
|
||||||
func (st *Stack) pushN(ds ...*big.Int) {
|
func (st *Stack) pushN(ds ...*uint256.Int) {
|
||||||
st.data = append(st.data, ds...)
|
st.data = append(st.data, ds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) pop() (ret *big.Int) {
|
func (st *Stack) pop() (ret *uint256.Int) {
|
||||||
ret = st.data[len(st.data)-1]
|
ret = st.data[len(st.data)-1]
|
||||||
st.data = st.data[:len(st.data)-1]
|
st.data = st.data[:len(st.data)-1]
|
||||||
return
|
return
|
||||||
|
|
@ -62,15 +61,15 @@ func (st *Stack) swap(n int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) dup(pool *intPool, n int) {
|
func (st *Stack) dup(pool *intPool, n int) {
|
||||||
st.push(pool.get().Set(st.data[st.len()-n]))
|
st.push(pool.get().Copy(st.data[st.len()-n]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) peek() *big.Int {
|
func (st *Stack) peek() *uint256.Int {
|
||||||
return st.data[st.len()-1]
|
return st.data[st.len()-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Back returns the n'th item in stack
|
// Back returns the n'th item in stack
|
||||||
func (st *Stack) Back(n int) *big.Int {
|
func (st *Stack) Back(n int) *uint256.Int {
|
||||||
return st.data[st.len()-n-1]
|
return st.data[st.len()-n-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ func (sw *stackWrapper) peek(idx int) *big.Int {
|
||||||
log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx)
|
log.Warn("Tracer accessed out of bound stack", "size", len(sw.stack.Data()), "index", idx)
|
||||||
return new(big.Int)
|
return new(big.Int)
|
||||||
}
|
}
|
||||||
return sw.stack.Data()[len(sw.stack.Data())-idx-1]
|
return sw.stack.Back(idx).ToBig()
|
||||||
}
|
}
|
||||||
|
|
||||||
// pushObject assembles a JSVM object wrapping a swappable stack and pushes it
|
// pushObject assembles a JSVM object wrapping a swappable stack and pushes it
|
||||||
|
|
|
||||||
1
go.mod
1
go.mod
|
|
@ -33,6 +33,7 @@ require (
|
||||||
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989
|
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989
|
||||||
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277
|
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277
|
||||||
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad
|
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad
|
||||||
|
github.com/holiman/uint256 v0.0.0-20200127182631-07b58676bd8d
|
||||||
github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3
|
github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3
|
||||||
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883
|
github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883
|
||||||
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458
|
github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -61,8 +61,6 @@ github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk
|
||||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||||
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmakYiSlqu2425CHyFXLZZnvm7PDpU8M=
|
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmakYiSlqu2425CHyFXLZZnvm7PDpU8M=
|
||||||
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
github.com/dop251/goja v0.0.0-20191203121440-007eef3bc40f h1:vtCDQseO/Sbu5IZSoc2uzZ7CkSoai7OtpcwGFK5FlyE=
|
|
||||||
github.com/dop251/goja v0.0.0-20191203121440-007eef3bc40f/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
|
|
||||||
github.com/dop251/goja v0.0.0-20200106141417-aaec0e7bde29 h1:Ewd9K+mC725sITA12QQHRqWj78NU4t7EhlFVVgdlzJg=
|
github.com/dop251/goja v0.0.0-20200106141417-aaec0e7bde29 h1:Ewd9K+mC725sITA12QQHRqWj78NU4t7EhlFVVgdlzJg=
|
||||||
github.com/dop251/goja v0.0.0-20200106141417-aaec0e7bde29/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
|
github.com/dop251/goja v0.0.0-20200106141417-aaec0e7bde29/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
|
||||||
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c h1:JHHhtb9XWJrGNMcrVP6vyzO4dusgi/HnceHTgxSejUM=
|
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c h1:JHHhtb9XWJrGNMcrVP6vyzO4dusgi/HnceHTgxSejUM=
|
||||||
|
|
@ -101,6 +99,8 @@ github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277 h1:E0whKx
|
||||||
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
|
||||||
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad h1:eMxs9EL0PvIGS9TTtxg4R+JxuPGav82J8rA+GFnY7po=
|
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad h1:eMxs9EL0PvIGS9TTtxg4R+JxuPGav82J8rA+GFnY7po=
|
||||||
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/holiman/uint256 v0.0.0-20200127182631-07b58676bd8d h1:7/ck99Ry6wQsjJyE0TeMkAPzGo6oMNfaeQ2I7hyG+gE=
|
||||||
|
github.com/holiman/uint256 v0.0.0-20200127182631-07b58676bd8d/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3 h1:DqD8eigqlUm0+znmx7zhL0xvTW3+e1jCekJMfBUADWI=
|
github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3 h1:DqD8eigqlUm0+znmx7zhL0xvTW3+e1jCekJMfBUADWI=
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue