github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/tests/vm_test_util.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package tests
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"math/big"
    24  	"strconv"
    25  	"testing"
    26  
    27  	"github.com/ethereumproject/go-ethereum/common"
    28  	"github.com/ethereumproject/go-ethereum/core/state"
    29  	"github.com/ethereumproject/go-ethereum/core/vm"
    30  	"github.com/ethereumproject/go-ethereum/ethdb"
    31  	"github.com/ethereumproject/go-ethereum/logger/glog"
    32  )
    33  
    34  func RunVmTestWithReader(r io.Reader, skipTests []string) error {
    35  	tests := make(map[string]VmTest)
    36  	err := readJson(r, &tests)
    37  	if err != nil {
    38  		return err
    39  	}
    40  
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	if err := runVmTests(tests, skipTests); err != nil {
    46  		return err
    47  	}
    48  
    49  	return nil
    50  }
    51  
    52  type bconf struct {
    53  	name    string
    54  	precomp bool
    55  	jit     bool
    56  }
    57  
    58  func BenchVmTest(p string, conf bconf, b *testing.B) error {
    59  	tests := make(map[string]VmTest)
    60  	err := readJsonFile(p, &tests)
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	test, ok := tests[conf.name]
    66  	if !ok {
    67  		return fmt.Errorf("test not found: %s", conf.name)
    68  	}
    69  
    70  	env := make(map[string]string)
    71  	env["currentCoinbase"] = test.Env.CurrentCoinbase
    72  	env["currentDifficulty"] = test.Env.CurrentDifficulty
    73  	env["currentGasLimit"] = test.Env.CurrentGasLimit
    74  	env["currentNumber"] = test.Env.CurrentNumber
    75  	env["previousHash"] = test.Env.PreviousHash
    76  	if n, ok := test.Env.CurrentTimestamp.(float64); ok {
    77  		env["currentTimestamp"] = strconv.Itoa(int(n))
    78  	} else {
    79  		env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
    80  	}
    81  
    82  	b.ResetTimer()
    83  	for i := 0; i < b.N; i++ {
    84  		benchVmTest(test, env, b)
    85  	}
    86  
    87  	return nil
    88  }
    89  
    90  func benchVmTest(test VmTest, env map[string]string, b *testing.B) {
    91  	b.StopTimer()
    92  	db, _ := ethdb.NewMemDatabase()
    93  	statedb := makePreState(db, test.Pre)
    94  	b.StartTimer()
    95  
    96  	RunVm(statedb, env, test.Exec)
    97  }
    98  
    99  func RunVmTest(p string, skipTests []string) error {
   100  	tests := make(map[string]VmTest)
   101  	err := readJsonFile(p, &tests)
   102  	if err != nil {
   103  		return err
   104  	}
   105  
   106  	if err := runVmTests(tests, skipTests); err != nil {
   107  		return err
   108  	}
   109  
   110  	return nil
   111  }
   112  
   113  func runVmTests(tests map[string]VmTest, skipTests []string) error {
   114  	skipTest := make(map[string]bool, len(skipTests))
   115  	for _, name := range skipTests {
   116  		skipTest[name] = true
   117  	}
   118  
   119  	for name, test := range tests {
   120  		if skipTest[name] {
   121  			glog.Infoln("Skipping VM test", name)
   122  			return nil
   123  		}
   124  
   125  		if err := runVmTest(test); err != nil {
   126  			return fmt.Errorf("%s %s", name, err.Error())
   127  		}
   128  
   129  		glog.Infoln("VM test passed: ", name)
   130  		//fmt.Println(string(statedb.Dump()))
   131  	}
   132  	return nil
   133  }
   134  
   135  func runVmTest(test VmTest) error {
   136  	db, _ := ethdb.NewMemDatabase()
   137  	statedb := makePreState(db, test.Pre)
   138  
   139  	// XXX Yeah, yeah...
   140  	env := make(map[string]string)
   141  	env["currentCoinbase"] = test.Env.CurrentCoinbase
   142  	env["currentDifficulty"] = test.Env.CurrentDifficulty
   143  	env["currentGasLimit"] = test.Env.CurrentGasLimit
   144  	env["currentNumber"] = test.Env.CurrentNumber
   145  	env["previousHash"] = test.Env.PreviousHash
   146  	if n, ok := test.Env.CurrentTimestamp.(float64); ok {
   147  		env["currentTimestamp"] = strconv.Itoa(int(n))
   148  	} else {
   149  		env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
   150  	}
   151  
   152  	ret, logs, gas, err := RunVm(statedb, env, test.Exec)
   153  
   154  	// Compare expected and actual return
   155  	rexp := common.FromHex(test.Out)
   156  	if bytes.Compare(rexp, ret) != 0 {
   157  		return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret)
   158  	}
   159  
   160  	// Check gas usage
   161  	if test.Gas == "" && err == nil {
   162  		return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successfull")
   163  	} else {
   164  		want, ok := new(big.Int).SetString(test.Gas, 0)
   165  		if test.Gas == "" {
   166  			want = new(big.Int)
   167  		} else if !ok {
   168  			return fmt.Errorf("malformed test gas %q", test.Gas)
   169  		}
   170  		if want.Cmp(gas) != 0 {
   171  			return fmt.Errorf("gas failed. Expected %v, got %v\n", want, gas)
   172  		}
   173  	}
   174  
   175  	// check post state
   176  	for addr, account := range test.Post {
   177  		obj := statedb.GetAccount(common.HexToAddress(addr))
   178  		if obj == nil {
   179  			continue
   180  		}
   181  		for addr, value := range account.Storage {
   182  			v := statedb.GetState(obj.Address(), common.HexToHash(addr))
   183  			vexp := common.HexToHash(value)
   184  			if v != vexp {
   185  				return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", obj.Address().Bytes()[0:4], addr, vexp, v, vexp.Big(), v.Big())
   186  			}
   187  		}
   188  	}
   189  
   190  	// check logs
   191  	if len(test.Logs) > 0 {
   192  		lerr := checkLogs(test.Logs, logs)
   193  		if lerr != nil {
   194  			return lerr
   195  		}
   196  	}
   197  
   198  	return nil
   199  }
   200  
   201  func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs, *big.Int, error) {
   202  	var (
   203  		to       = common.HexToAddress(exec["address"])
   204  		from     = common.HexToAddress(exec["caller"])
   205  		data     = common.FromHex(exec["data"])
   206  		gas, _   = new(big.Int).SetString(exec["gas"], 0)
   207  		price, _ = new(big.Int).SetString(exec["gasPrice"], 0)
   208  		value, _ = new(big.Int).SetString(exec["value"], 0)
   209  	)
   210  	if gas == nil || price == nil || value == nil {
   211  		panic("malformed gas, price or value")
   212  	}
   213  	// Reset the pre-compiled contracts for VM tests.
   214  	vm.Precompiled = make(map[string]*vm.PrecompiledAccount)
   215  
   216  	caller := state.GetOrNewStateObject(from)
   217  
   218  	vmenv := NewEnvFromMap(RuleSet{
   219  		HomesteadBlock:           big.NewInt(1150000),
   220  		HomesteadGasRepriceBlock: big.NewInt(2500000),
   221  		DiehardBlock:             big.NewInt(3000000),
   222  		ExplosionBlock:           big.NewInt(5000000),
   223  	}, state, env, exec)
   224  	vmenv.vmTest = true
   225  	vmenv.skipTransfer = true
   226  	vmenv.initial = true
   227  	ret, err := vmenv.Call(caller, to, data, gas, price, value)
   228  
   229  	return ret, vmenv.state.Logs(), vmenv.Gas, err
   230  }