aboutsummaryrefslogtreecommitdiffstats
path: root/core/vm/instructions_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/vm/instructions_test.go')
-rw-r--r--core/vm/instructions_test.go225
1 files changed, 138 insertions, 87 deletions
diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go
index 8a48d765d..50d0a9dda 100644
--- a/core/vm/instructions_test.go
+++ b/core/vm/instructions_test.go
@@ -18,6 +18,9 @@ package vm
import (
"bytes"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
"math/big"
"testing"
@@ -26,32 +29,91 @@ import (
"github.com/ethereum/go-ethereum/params"
)
-type twoOperandTest struct {
- x string
- y string
- expected string
+type TwoOperandTestcase struct {
+ X string
+ Y string
+ Expected string
}
-func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
+type twoOperandParams struct {
+ x string
+ y string
+}
+
+var commonParams []*twoOperandParams
+var twoOpMethods map[string]executionFunc
+
+func init() {
+
+ // Params is a list of common edgecases that should be used for some common tests
+ params := []string{
+ "0000000000000000000000000000000000000000000000000000000000000000", // 0
+ "0000000000000000000000000000000000000000000000000000000000000001", // +1
+ "0000000000000000000000000000000000000000000000000000000000000005", // +5
+ "7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe", // + max -1
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // + max
+ "8000000000000000000000000000000000000000000000000000000000000000", // - max
+ "8000000000000000000000000000000000000000000000000000000000000001", // - max+1
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", // - 5
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // - 1
+ }
+ // Params are combined so each param is used on each 'side'
+ commonParams = make([]*twoOperandParams, len(params)*len(params))
+ for i, x := range params {
+ for j, y := range params {
+ commonParams[i*len(params)+j] = &twoOperandParams{x, y}
+ }
+ }
+ twoOpMethods = map[string]executionFunc{
+ "add": opAdd,
+ "sub": opSub,
+ "mul": opMul,
+ "div": opDiv,
+ "sdiv": opSdiv,
+ "mod": opMod,
+ "smod": opSmod,
+ "exp": opExp,
+ "signext": opSignExtend,
+ "lt": opLt,
+ "gt": opGt,
+ "slt": opSlt,
+ "sgt": opSgt,
+ "eq": opEq,
+ "and": opAnd,
+ "or": opOr,
+ "xor": opXor,
+ "byte": opByte,
+ "shl": opSHL,
+ "shr": opSHR,
+ "sar": opSAR,
+ }
+}
+
+func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) {
+
var (
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
stack = newstack()
pc = uint64(0)
- evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
+ evmInterpreter = env.interpreter.(*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
evmInterpreter.intPool = poolOfIntPools.get()
+ evmInterpreter.intPool.put(big.NewInt(-1337))
+ evmInterpreter.intPool.put(big.NewInt(-1337))
+ evmInterpreter.intPool.put(big.NewInt(-1337))
+
for i, test := range tests {
- x := new(big.Int).SetBytes(common.Hex2Bytes(test.x))
- shift := new(big.Int).SetBytes(common.Hex2Bytes(test.y))
- expected := new(big.Int).SetBytes(common.Hex2Bytes(test.expected))
+ x := new(big.Int).SetBytes(common.Hex2Bytes(test.X))
+ y := new(big.Int).SetBytes(common.Hex2Bytes(test.Y))
+ expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected))
stack.push(x)
- stack.push(shift)
+ stack.push(y)
opFn(&pc, evmInterpreter, nil, nil, stack)
actual := stack.pop()
+
if actual.Cmp(expected) != 0 {
- t.Errorf("Testcase %d, expected %v, got %v", i, expected, actual)
+ t.Errorf("Testcase %v %d, %v(%x, %x): expected %x, got %x", name, i, name, x, y, expected, actual)
}
// Check pool usage
// 1.pool is not allowed to contain anything on the stack
@@ -64,7 +126,7 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
for evmInterpreter.intPool.pool.len() > 0 {
key := evmInterpreter.intPool.get()
if _, exist := poolvals[key]; exist {
- t.Errorf("Testcase %d, pool contains double-entry", i)
+ t.Errorf("Testcase %v %d, pool contains double-entry", name, i)
}
poolvals[key] = struct{}{}
}
@@ -74,47 +136,22 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
}
func TestByteOp(t *testing.T) {
- var (
- env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
- stack = newstack()
- evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
- )
-
- env.interpreter = evmInterpreter
- evmInterpreter.intPool = poolOfIntPools.get()
- tests := []struct {
- v string
- th uint64
- expected *big.Int
- }{
- {"ABCDEF0908070605040302010000000000000000000000000000000000000000", 0, big.NewInt(0xAB)},
- {"ABCDEF0908070605040302010000000000000000000000000000000000000000", 1, big.NewInt(0xCD)},
- {"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 0, big.NewInt(0x00)},
- {"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", 1, big.NewInt(0xCD)},
- {"0000000000000000000000000000000000000000000000000000000000102030", 31, big.NewInt(0x30)},
- {"0000000000000000000000000000000000000000000000000000000000102030", 30, big.NewInt(0x20)},
- {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 32, big.NewInt(0x0)},
- {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0xFFFFFFFFFFFFFFFF, big.NewInt(0x0)},
- }
- pc := uint64(0)
- for _, test := range tests {
- val := new(big.Int).SetBytes(common.Hex2Bytes(test.v))
- th := new(big.Int).SetUint64(test.th)
- stack.push(val)
- stack.push(th)
- opByte(&pc, evmInterpreter, nil, nil, stack)
- actual := stack.pop()
- if actual.Cmp(test.expected) != 0 {
- t.Fatalf("Expected [%v] %v:th byte to be %v, was %v.", test.v, test.th, test.expected, actual)
- }
+ tests := []TwoOperandTestcase{
+ {"ABCDEF0908070605040302010000000000000000000000000000000000000000", "00", "AB"},
+ {"ABCDEF0908070605040302010000000000000000000000000000000000000000", "01", "CD"},
+ {"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", "00", "00"},
+ {"00CDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff", "01", "CD"},
+ {"0000000000000000000000000000000000000000000000000000000000102030", "1F", "30"},
+ {"0000000000000000000000000000000000000000000000000000000000102030", "1E", "20"},
+ {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "20", "00"},
+ {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "FFFFFFFFFFFFFFFF", "00"},
}
- poolOfIntPools.put(evmInterpreter.intPool)
+ testTwoOperandOp(t, tests, opByte, "byte")
}
func TestSHL(t *testing.T) {
// Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shl-shift-left
- tests := []twoOperandTest{
- {"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
+ tests := []TwoOperandTestcase{
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000002"},
{"0000000000000000000000000000000000000000000000000000000000000001", "ff", "8000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000001", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
@@ -126,12 +163,12 @@ func TestSHL(t *testing.T) {
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"},
}
- testTwoOperandOp(t, tests, opSHL)
+ testTwoOperandOp(t, tests, opSHL, "shl")
}
func TestSHR(t *testing.T) {
// Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#shr-logical-shift-right
- tests := []twoOperandTest{
+ tests := []TwoOperandTestcase{
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000000", "01", "4000000000000000000000000000000000000000000000000000000000000000"},
@@ -144,12 +181,12 @@ func TestSHR(t *testing.T) {
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
}
- testTwoOperandOp(t, tests, opSHR)
+ testTwoOperandOp(t, tests, opSHR, "shr")
}
func TestSAR(t *testing.T) {
// Testcases from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-145.md#sar-arithmetic-shift-right
- tests := []twoOperandTest{
+ tests := []TwoOperandTestcase{
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
{"8000000000000000000000000000000000000000000000000000000000000000", "01", "c000000000000000000000000000000000000000000000000000000000000000"},
@@ -168,44 +205,58 @@ func TestSAR(t *testing.T) {
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
}
- testTwoOperandOp(t, tests, opSAR)
+ testTwoOperandOp(t, tests, opSAR, "sar")
}
-func TestSGT(t *testing.T) {
- tests := []twoOperandTest{
+// getResult is a convenience function to generate the expected values
+func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase {
+ var (
+ env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
+ stack = newstack()
+ pc = uint64(0)
+ interpreter = env.interpreter.(*EVMInterpreter)
+ )
+ interpreter.intPool = poolOfIntPools.get()
+ result := make([]TwoOperandTestcase, len(args))
+ for i, param := range args {
+ x := new(big.Int).SetBytes(common.Hex2Bytes(param.x))
+ y := new(big.Int).SetBytes(common.Hex2Bytes(param.y))
+ stack.push(x)
+ stack.push(y)
+ opFn(&pc, interpreter, nil, nil, stack)
+ actual := stack.pop()
+ result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
+ }
+ return result
+}
- {"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"0000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
- {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
- {"0000000000000000000000000000000000000000000000000000000000000001", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
- {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000001"},
- {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000000"},
+// utility function to fill the json-file with testcases
+// Enable this test to generate the 'testcases_xx.json' files
+func xTestWriteExpectedValues(t *testing.T) {
+ for name, method := range twoOpMethods {
+ data, err := json.Marshal(getResult(commonParams, method))
+ if err != nil {
+ t.Fatal(err)
+ }
+ _ = ioutil.WriteFile(fmt.Sprintf("testdata/testcases_%v.json", name), data, 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
}
- testTwoOperandOp(t, tests, opSgt)
-}
-
-func TestSLT(t *testing.T) {
- tests := []twoOperandTest{
- {"0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"0000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
- {"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"0000000000000000000000000000000000000000000000000000000000000001", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000001"},
- {"8000000000000000000000000000000000000000000000000000000000000001", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"8000000000000000000000000000000000000000000000000000000000000001", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "8000000000000000000000000000000000000000000000000000000000000001", "0000000000000000000000000000000000000000000000000000000000000001"},
- {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "0000000000000000000000000000000000000000000000000000000000000000"},
- {"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb", "0000000000000000000000000000000000000000000000000000000000000001"},
+ t.Fatal("This test should not be activated")
+}
+
+// TestJsonTestcases runs through all the testcases defined as json-files
+func TestJsonTestcases(t *testing.T) {
+ for name := range twoOpMethods {
+ data, err := ioutil.ReadFile(fmt.Sprintf("testdata/testcases_%v.json", name))
+ if err != nil {
+ t.Fatal("Failed to read file", err)
+ }
+ var testcases []TwoOperandTestcase
+ json.Unmarshal(data, &testcases)
+ testTwoOperandOp(t, testcases, twoOpMethods[name], name)
}
- testTwoOperandOp(t, tests, opSlt)
}
func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {