core/vm: optimize eq, slt, sgt and iszero + tests (#16047)

* vm: optimize eq, slt, sgt and iszero + tests

* core/vm: fix error in slt/sgt, found by vmtests. Added testcase

* core/vm: make slt/sgt cleaner
This commit is contained in:
Martin Holst Swende
2018-03-08 13:48:19 +01:00
committed by Péter Szilágyi
parent 85d5f2c661
commit 4871e25f5f
2 changed files with 61 additions and 25 deletions

View File

@ -30,6 +30,8 @@ import (
var (
bigZero = new(big.Int)
tt255 = math.BigPow(2, 255)
tt256 = math.BigPow(2, 256)
errWriteProtection = errors.New("evm: write protection")
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
errExecutionReverted = errors.New("evm: execution reverted")
@ -191,50 +193,71 @@ func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack
}
func opSlt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop())
if x.Cmp(math.S256(y)) < 0 {
stack.push(evm.interpreter.intPool.get().SetUint64(1))
} else {
stack.push(new(big.Int))
}
x, y := stack.pop(), stack.peek()
evm.interpreter.intPool.put(x, y)
xSign := x.Cmp(tt255)
ySign := y.Cmp(tt255)
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)
}
}
evm.interpreter.intPool.put(x)
return nil, nil
}
func opSgt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := math.S256(stack.pop()), math.S256(stack.pop())
if x.Cmp(y) > 0 {
stack.push(evm.interpreter.intPool.get().SetUint64(1))
} else {
stack.push(new(big.Int))
}
x, y := stack.pop(), stack.peek()
evm.interpreter.intPool.put(x, y)
xSign := x.Cmp(tt255)
ySign := y.Cmp(tt255)
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)
}
}
evm.interpreter.intPool.put(x)
return nil, nil
}
func opEq(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x, y := stack.pop(), stack.pop()
x, y := stack.pop(), stack.peek()
if x.Cmp(y) == 0 {
stack.push(evm.interpreter.intPool.get().SetUint64(1))
y.SetUint64(1)
} else {
stack.push(new(big.Int))
y.SetUint64(0)
}
evm.interpreter.intPool.put(x, y)
evm.interpreter.intPool.put(x)
return nil, nil
}
func opIszero(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
x := stack.pop()
x := stack.peek()
if x.Sign() > 0 {
stack.push(new(big.Int))
x.SetUint64(0)
} else {
stack.push(evm.interpreter.intPool.get().SetUint64(1))
x.SetUint64(1)
}
evm.interpreter.intPool.put(x)
return nil, nil
}