36b78abe61
This PR makes it easy to generate and execute testcases for VM arithmetic operations. By enabling and running the testcase TestWriteExpectedValues, a set of json files are created which contain input and output for each arith operation. The test TestJsonTestcases executes all of those tests. While meaningless as is, this PR makes it less risky to make changes (optimizations) to the vm operations, since there will be a larger body of testcases.
641 lines
24 KiB
Go
641 lines
24 KiB
Go
// Copyright 2017 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package vm
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
)
|
|
|
|
type TwoOperandTestcase struct {
|
|
X string
|
|
Y string
|
|
Expected string
|
|
}
|
|
|
|
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 = 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))
|
|
y := new(big.Int).SetBytes(common.Hex2Bytes(test.Y))
|
|
expected := new(big.Int).SetBytes(common.Hex2Bytes(test.Expected))
|
|
stack.push(x)
|
|
stack.push(y)
|
|
opFn(&pc, evmInterpreter, nil, nil, stack)
|
|
actual := stack.pop()
|
|
|
|
if actual.Cmp(expected) != 0 {
|
|
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
|
|
// 2.pool is not allowed to contain the same pointers twice
|
|
if evmInterpreter.intPool.pool.len() > 0 {
|
|
|
|
poolvals := make(map[*big.Int]struct{})
|
|
poolvals[actual] = struct{}{}
|
|
|
|
for evmInterpreter.intPool.pool.len() > 0 {
|
|
key := evmInterpreter.intPool.get()
|
|
if _, exist := poolvals[key]; exist {
|
|
t.Errorf("Testcase %v %d, pool contains double-entry", name, i)
|
|
}
|
|
poolvals[key] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
poolOfIntPools.put(evmInterpreter.intPool)
|
|
}
|
|
|
|
func TestByteOp(t *testing.T) {
|
|
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"},
|
|
}
|
|
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 := []TwoOperandTestcase{
|
|
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000002"},
|
|
{"0000000000000000000000000000000000000000000000000000000000000001", "ff", "8000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"0000000000000000000000000000000000000000000000000000000000000001", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"0000000000000000000000000000000000000000000000000000000000000001", "0101", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "8000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe"},
|
|
}
|
|
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 := []TwoOperandTestcase{
|
|
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
|
|
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"8000000000000000000000000000000000000000000000000000000000000000", "01", "4000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"8000000000000000000000000000000000000000000000000000000000000000", "ff", "0000000000000000000000000000000000000000000000000000000000000001"},
|
|
{"8000000000000000000000000000000000000000000000000000000000000000", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"8000000000000000000000000000000000000000000000000000000000000000", "0101", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "0000000000000000000000000000000000000000000000000000000000000001"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
}
|
|
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 := []TwoOperandTestcase{
|
|
{"0000000000000000000000000000000000000000000000000000000000000001", "00", "0000000000000000000000000000000000000000000000000000000000000001"},
|
|
{"0000000000000000000000000000000000000000000000000000000000000001", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"8000000000000000000000000000000000000000000000000000000000000000", "01", "c000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"8000000000000000000000000000000000000000000000000000000000000000", "ff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"8000000000000000000000000000000000000000000000000000000000000000", "0100", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"8000000000000000000000000000000000000000000000000000000000000000", "0101", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "00", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "01", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"},
|
|
{"0000000000000000000000000000000000000000000000000000000000000000", "01", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"4000000000000000000000000000000000000000000000000000000000000000", "fe", "0000000000000000000000000000000000000000000000000000000000000001"},
|
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "f8", "000000000000000000000000000000000000000000000000000000000000007f"},
|
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "fe", "0000000000000000000000000000000000000000000000000000000000000001"},
|
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "ff", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
{"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", "0100", "0000000000000000000000000000000000000000000000000000000000000000"},
|
|
}
|
|
|
|
testTwoOperandOp(t, tests, opSAR, "sar")
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
|
|
func opBenchmark(bench *testing.B, op func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
|
|
var (
|
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
|
stack = newstack()
|
|
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
|
)
|
|
|
|
env.interpreter = evmInterpreter
|
|
evmInterpreter.intPool = poolOfIntPools.get()
|
|
// convert args
|
|
byteArgs := make([][]byte, len(args))
|
|
for i, arg := range args {
|
|
byteArgs[i] = common.Hex2Bytes(arg)
|
|
}
|
|
pc := uint64(0)
|
|
bench.ResetTimer()
|
|
for i := 0; i < bench.N; i++ {
|
|
for _, arg := range byteArgs {
|
|
a := new(big.Int).SetBytes(arg)
|
|
stack.push(a)
|
|
}
|
|
op(&pc, evmInterpreter, nil, nil, stack)
|
|
stack.pop()
|
|
}
|
|
poolOfIntPools.put(evmInterpreter.intPool)
|
|
}
|
|
|
|
func BenchmarkOpAdd64(b *testing.B) {
|
|
x := "ffffffff"
|
|
y := "fd37f3e2bba2c4f"
|
|
|
|
opBenchmark(b, opAdd, x, y)
|
|
}
|
|
|
|
func BenchmarkOpAdd128(b *testing.B) {
|
|
x := "ffffffffffffffff"
|
|
y := "f5470b43c6549b016288e9a65629687"
|
|
|
|
opBenchmark(b, opAdd, x, y)
|
|
}
|
|
|
|
func BenchmarkOpAdd256(b *testing.B) {
|
|
x := "0802431afcbce1fc194c9eaa417b2fb67dc75a95db0bc7ec6b1c8af11df6a1da9"
|
|
y := "a1f5aac137876480252e5dcac62c354ec0d42b76b0642b6181ed099849ea1d57"
|
|
|
|
opBenchmark(b, opAdd, x, y)
|
|
}
|
|
|
|
func BenchmarkOpSub64(b *testing.B) {
|
|
x := "51022b6317003a9d"
|
|
y := "a20456c62e00753a"
|
|
|
|
opBenchmark(b, opSub, x, y)
|
|
}
|
|
|
|
func BenchmarkOpSub128(b *testing.B) {
|
|
x := "4dde30faaacdc14d00327aac314e915d"
|
|
y := "9bbc61f5559b829a0064f558629d22ba"
|
|
|
|
opBenchmark(b, opSub, x, y)
|
|
}
|
|
|
|
func BenchmarkOpSub256(b *testing.B) {
|
|
x := "4bfcd8bb2ac462735b48a17580690283980aa2d679f091c64364594df113ea37"
|
|
y := "97f9b1765588c4e6b69142eb00d20507301545acf3e1238c86c8b29be227d46e"
|
|
|
|
opBenchmark(b, opSub, x, y)
|
|
}
|
|
|
|
func BenchmarkOpMul(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opMul, x, y)
|
|
}
|
|
|
|
func BenchmarkOpDiv256(b *testing.B) {
|
|
x := "ff3f9014f20db29ae04af2c2d265de17"
|
|
y := "fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611"
|
|
opBenchmark(b, opDiv, x, y)
|
|
}
|
|
|
|
func BenchmarkOpDiv128(b *testing.B) {
|
|
x := "fdedc7f10142ff97"
|
|
y := "fbdfda0e2ce356173d1993d5f70a2b11"
|
|
opBenchmark(b, opDiv, x, y)
|
|
}
|
|
|
|
func BenchmarkOpDiv64(b *testing.B) {
|
|
x := "fcb34eb3"
|
|
y := "f97180878e839129"
|
|
opBenchmark(b, opDiv, x, y)
|
|
}
|
|
|
|
func BenchmarkOpSdiv(b *testing.B) {
|
|
x := "ff3f9014f20db29ae04af2c2d265de17"
|
|
y := "fe7fb0d1f59dfe9492ffbf73683fd1e870eec79504c60144cc7f5fc2bad1e611"
|
|
|
|
opBenchmark(b, opSdiv, x, y)
|
|
}
|
|
|
|
func BenchmarkOpMod(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opMod, x, y)
|
|
}
|
|
|
|
func BenchmarkOpSmod(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opSmod, x, y)
|
|
}
|
|
|
|
func BenchmarkOpExp(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opExp, x, y)
|
|
}
|
|
|
|
func BenchmarkOpSignExtend(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opSignExtend, x, y)
|
|
}
|
|
|
|
func BenchmarkOpLt(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opLt, x, y)
|
|
}
|
|
|
|
func BenchmarkOpGt(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opGt, x, y)
|
|
}
|
|
|
|
func BenchmarkOpSlt(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opSlt, x, y)
|
|
}
|
|
|
|
func BenchmarkOpSgt(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opSgt, x, y)
|
|
}
|
|
|
|
func BenchmarkOpEq(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opEq, x, y)
|
|
}
|
|
func BenchmarkOpEq2(b *testing.B) {
|
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
|
y := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201fffffffe"
|
|
opBenchmark(b, opEq, x, y)
|
|
}
|
|
func BenchmarkOpAnd(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opAnd, x, y)
|
|
}
|
|
|
|
func BenchmarkOpOr(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opOr, x, y)
|
|
}
|
|
|
|
func BenchmarkOpXor(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opXor, x, y)
|
|
}
|
|
|
|
func BenchmarkOpByte(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opByte, x, y)
|
|
}
|
|
|
|
func BenchmarkOpAddmod(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opAddmod, x, y, z)
|
|
}
|
|
|
|
func BenchmarkOpMulmod(b *testing.B) {
|
|
x := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
y := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
z := "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffffffff"
|
|
|
|
opBenchmark(b, opMulmod, x, y, z)
|
|
}
|
|
|
|
func BenchmarkOpSHL(b *testing.B) {
|
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
|
y := "ff"
|
|
|
|
opBenchmark(b, opSHL, x, y)
|
|
}
|
|
func BenchmarkOpSHR(b *testing.B) {
|
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
|
y := "ff"
|
|
|
|
opBenchmark(b, opSHR, x, y)
|
|
}
|
|
func BenchmarkOpSAR(b *testing.B) {
|
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
|
y := "ff"
|
|
|
|
opBenchmark(b, opSAR, x, y)
|
|
}
|
|
func BenchmarkOpIsZero(b *testing.B) {
|
|
x := "FBCDEF090807060504030201ffffffffFBCDEF090807060504030201ffffffff"
|
|
opBenchmark(b, opIszero, x)
|
|
}
|
|
|
|
func TestOpMstore(t *testing.T) {
|
|
var (
|
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
|
stack = newstack()
|
|
mem = NewMemory()
|
|
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
|
)
|
|
|
|
env.interpreter = evmInterpreter
|
|
evmInterpreter.intPool = poolOfIntPools.get()
|
|
mem.Resize(64)
|
|
pc := uint64(0)
|
|
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
|
|
stack.pushN(new(big.Int).SetBytes(common.Hex2Bytes(v)), big.NewInt(0))
|
|
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
|
if got := common.Bytes2Hex(mem.Get(0, 32)); got != v {
|
|
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
|
|
}
|
|
stack.pushN(big.NewInt(0x1), big.NewInt(0))
|
|
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
|
if common.Bytes2Hex(mem.Get(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
|
|
t.Fatalf("Mstore failed to overwrite previous value")
|
|
}
|
|
poolOfIntPools.put(evmInterpreter.intPool)
|
|
}
|
|
|
|
func BenchmarkOpMstore(bench *testing.B) {
|
|
var (
|
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
|
stack = newstack()
|
|
mem = NewMemory()
|
|
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
|
)
|
|
|
|
env.interpreter = evmInterpreter
|
|
evmInterpreter.intPool = poolOfIntPools.get()
|
|
mem.Resize(64)
|
|
pc := uint64(0)
|
|
memStart := big.NewInt(0)
|
|
value := big.NewInt(0x1337)
|
|
|
|
bench.ResetTimer()
|
|
for i := 0; i < bench.N; i++ {
|
|
stack.pushN(value, memStart)
|
|
opMstore(&pc, evmInterpreter, nil, mem, stack)
|
|
}
|
|
poolOfIntPools.put(evmInterpreter.intPool)
|
|
}
|
|
|
|
func BenchmarkOpSHA3(bench *testing.B) {
|
|
var (
|
|
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
|
stack = newstack()
|
|
mem = NewMemory()
|
|
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
|
)
|
|
env.interpreter = evmInterpreter
|
|
evmInterpreter.intPool = poolOfIntPools.get()
|
|
mem.Resize(32)
|
|
pc := uint64(0)
|
|
start := big.NewInt(0)
|
|
|
|
bench.ResetTimer()
|
|
for i := 0; i < bench.N; i++ {
|
|
stack.pushN(big.NewInt(32), start)
|
|
opSha3(&pc, evmInterpreter, nil, mem, stack)
|
|
}
|
|
poolOfIntPools.put(evmInterpreter.intPool)
|
|
}
|
|
|
|
func TestCreate2Addreses(t *testing.T) {
|
|
type testcase struct {
|
|
origin string
|
|
salt string
|
|
code string
|
|
expected string
|
|
}
|
|
|
|
for i, tt := range []testcase{
|
|
{
|
|
origin: "0x0000000000000000000000000000000000000000",
|
|
salt: "0x0000000000000000000000000000000000000000",
|
|
code: "0x00",
|
|
expected: "0x4d1a2e2bb4f88f0250f26ffff098b0b30b26bf38",
|
|
},
|
|
{
|
|
origin: "0xdeadbeef00000000000000000000000000000000",
|
|
salt: "0x0000000000000000000000000000000000000000",
|
|
code: "0x00",
|
|
expected: "0xB928f69Bb1D91Cd65274e3c79d8986362984fDA3",
|
|
},
|
|
{
|
|
origin: "0xdeadbeef00000000000000000000000000000000",
|
|
salt: "0xfeed000000000000000000000000000000000000",
|
|
code: "0x00",
|
|
expected: "0xD04116cDd17beBE565EB2422F2497E06cC1C9833",
|
|
},
|
|
{
|
|
origin: "0x0000000000000000000000000000000000000000",
|
|
salt: "0x0000000000000000000000000000000000000000",
|
|
code: "0xdeadbeef",
|
|
expected: "0x70f2b2914A2a4b783FaEFb75f459A580616Fcb5e",
|
|
},
|
|
{
|
|
origin: "0x00000000000000000000000000000000deadbeef",
|
|
salt: "0xcafebabe",
|
|
code: "0xdeadbeef",
|
|
expected: "0x60f3f640a8508fC6a86d45DF051962668E1e8AC7",
|
|
},
|
|
{
|
|
origin: "0x00000000000000000000000000000000deadbeef",
|
|
salt: "0xcafebabe",
|
|
code: "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
|
|
expected: "0x1d8bfDC5D46DC4f61D6b6115972536eBE6A8854C",
|
|
},
|
|
{
|
|
origin: "0x0000000000000000000000000000000000000000",
|
|
salt: "0x0000000000000000000000000000000000000000",
|
|
code: "0x",
|
|
expected: "0xE33C0C7F7df4809055C3ebA6c09CFe4BaF1BD9e0",
|
|
},
|
|
} {
|
|
|
|
origin := common.BytesToAddress(common.FromHex(tt.origin))
|
|
salt := common.BytesToHash(common.FromHex(tt.salt))
|
|
code := common.FromHex(tt.code)
|
|
codeHash := crypto.Keccak256(code)
|
|
address := crypto.CreateAddress2(origin, salt, codeHash)
|
|
/*
|
|
stack := newstack()
|
|
// salt, but we don't need that for this test
|
|
stack.push(big.NewInt(int64(len(code)))) //size
|
|
stack.push(big.NewInt(0)) // memstart
|
|
stack.push(big.NewInt(0)) // value
|
|
gas, _ := gasCreate2(params.GasTable{}, nil, nil, stack, nil, 0)
|
|
fmt.Printf("Example %d\n* address `0x%x`\n* salt `0x%x`\n* init_code `0x%x`\n* gas (assuming no mem expansion): `%v`\n* result: `%s`\n\n", i,origin, salt, code, gas, address.String())
|
|
*/
|
|
expected := common.BytesToAddress(common.FromHex(tt.expected))
|
|
if !bytes.Equal(expected.Bytes(), address.Bytes()) {
|
|
t.Errorf("test %d: expected %s, got %s", i, expected.String(), address.String())
|
|
}
|
|
|
|
}
|
|
}
|