github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/tests/state_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  	"encoding/hex"
    22  	"fmt"
    23  	"io"
    24  	"math/big"
    25  	"strconv"
    26  	"testing"
    27  
    28  	"github.com/ethereumproject/go-ethereum/common"
    29  	"github.com/ethereumproject/go-ethereum/core"
    30  	"github.com/ethereumproject/go-ethereum/core/state"
    31  	"github.com/ethereumproject/go-ethereum/core/vm"
    32  	"github.com/ethereumproject/go-ethereum/crypto"
    33  	"github.com/ethereumproject/go-ethereum/ethdb"
    34  	"github.com/ethereumproject/go-ethereum/logger/glog"
    35  )
    36  
    37  func RunStateTestWithReader(ruleSet RuleSet, r io.Reader, skipTests []string) error {
    38  	tests := make(map[string]VmTest)
    39  	if err := readJson(r, &tests); err != nil {
    40  		return err
    41  	}
    42  
    43  	if err := runStateTests(ruleSet, tests, skipTests); err != nil {
    44  		return err
    45  	}
    46  
    47  	return nil
    48  }
    49  
    50  func RunStateTest(ruleSet RuleSet, p string, skipTests []string) error {
    51  	tests := make(map[string]VmTest)
    52  	if err := readJsonFile(p, &tests); err != nil {
    53  		return err
    54  	}
    55  
    56  	if err := runStateTests(ruleSet, tests, skipTests); err != nil {
    57  		return err
    58  	}
    59  
    60  	return nil
    61  
    62  }
    63  
    64  func BenchStateTest(ruleSet RuleSet, p string, conf bconf, b *testing.B) error {
    65  	tests := make(map[string]VmTest)
    66  	if err := readJsonFile(p, &tests); err != nil {
    67  		return err
    68  	}
    69  	test, ok := tests[conf.name]
    70  	if !ok {
    71  		return fmt.Errorf("test not found: %s", conf.name)
    72  	}
    73  
    74  	// XXX Yeah, yeah...
    75  	env := make(map[string]string)
    76  	env["currentCoinbase"] = test.Env.CurrentCoinbase
    77  	env["currentDifficulty"] = test.Env.CurrentDifficulty
    78  	env["currentGasLimit"] = test.Env.CurrentGasLimit
    79  	env["currentNumber"] = test.Env.CurrentNumber
    80  	env["previousHash"] = test.Env.PreviousHash
    81  	if n, ok := test.Env.CurrentTimestamp.(float64); ok {
    82  		env["currentTimestamp"] = strconv.Itoa(int(n))
    83  	} else {
    84  		env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
    85  	}
    86  
    87  	b.ResetTimer()
    88  	for i := 0; i < b.N; i++ {
    89  		benchStateTest(ruleSet, test, env, b)
    90  	}
    91  
    92  	return nil
    93  }
    94  
    95  func benchStateTest(ruleSet RuleSet, test VmTest, env map[string]string, b *testing.B) {
    96  	b.StopTimer()
    97  	db, _ := ethdb.NewMemDatabase()
    98  	statedb := makePreState(db, test.Pre)
    99  	b.StartTimer()
   100  
   101  	RunState(ruleSet, db, statedb, env, test.Exec)
   102  }
   103  
   104  func runStateTests(ruleSet RuleSet, tests map[string]VmTest, skipTests []string) error {
   105  	skipTest := make(map[string]bool, len(skipTests))
   106  	for _, name := range skipTests {
   107  		skipTest[name] = true
   108  	}
   109  
   110  	for name, test := range tests {
   111  		if skipTest[name] /*|| name != "callcodecallcode_11" */ {
   112  			glog.Infoln("Skipping state test", name)
   113  			continue
   114  		}
   115  
   116  		//fmt.Println("StateTest:", name)
   117  		if err := runStateTest(ruleSet, test); err != nil {
   118  			return fmt.Errorf("%s: %s\n", name, err.Error())
   119  		}
   120  
   121  		//glog.Infoln("State test passed: ", name)
   122  		//fmt.Println(string(statedb.Dump()))
   123  	}
   124  	return nil
   125  
   126  }
   127  
   128  func runStateTest(ruleSet RuleSet, test VmTest) error {
   129  	db, _ := ethdb.NewMemDatabase()
   130  	statedb := makePreState(db, test.Pre)
   131  
   132  	// XXX Yeah, yeah...
   133  	env := make(map[string]string)
   134  	env["currentCoinbase"] = test.Env.CurrentCoinbase
   135  	env["currentDifficulty"] = test.Env.CurrentDifficulty
   136  	env["currentGasLimit"] = test.Env.CurrentGasLimit
   137  	env["currentNumber"] = test.Env.CurrentNumber
   138  	env["previousHash"] = test.Env.PreviousHash
   139  	if n, ok := test.Env.CurrentTimestamp.(float64); ok {
   140  		env["currentTimestamp"] = strconv.Itoa(int(n))
   141  	} else {
   142  		env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
   143  	}
   144  
   145  	var (
   146  		ret []byte
   147  		// gas  *big.Int
   148  		// err  error
   149  		logs vm.Logs
   150  	)
   151  
   152  	ret, logs, _, _ = RunState(ruleSet, db, statedb, env, test.Transaction)
   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 post state
   161  	for addr, account := range test.Post {
   162  		obj := statedb.GetAccount(common.HexToAddress(addr))
   163  		if obj == nil {
   164  			return fmt.Errorf("did not find expected post-state account: %s", addr)
   165  		}
   166  		// Because vm.Account interface does not have Nonce method, so after
   167  		// checking that obj exists, we'll use the StateObject type afterwards
   168  		sobj := statedb.GetOrNewStateObject(common.HexToAddress(addr))
   169  
   170  		if balance, ok := new(big.Int).SetString(account.Balance, 0); !ok {
   171  			panic("malformed test account balance")
   172  		} else if balance.Cmp(obj.Balance()) != 0 {
   173  			return fmt.Errorf("(%x) balance failed. Expected: %v have: %v\n", obj.Address().Bytes()[:4], account.Balance, obj.Balance())
   174  		}
   175  
   176  		if nonce, err := strconv.ParseUint(account.Nonce, 0, 64); err != nil {
   177  			return fmt.Errorf("test account %q malformed nonce: %s", addr, err)
   178  		} else if sobj.Nonce() != nonce {
   179  			return fmt.Errorf("(%x) nonce failed. Expected: %v have: %v\n", obj.Address().Bytes()[:4], account.Nonce, sobj.Nonce())
   180  		}
   181  
   182  		for addr, value := range account.Storage {
   183  			v := statedb.GetState(obj.Address(), common.HexToHash(addr))
   184  			vexp := common.HexToHash(value)
   185  
   186  			if v != vexp {
   187  				return fmt.Errorf("storage failed:\n%x: %s:\nexpected: %x\nhave:     %x\n(%v %v)\n", obj.Address().Bytes(), addr, vexp, v, vexp.Big(), v.Big())
   188  			}
   189  		}
   190  	}
   191  
   192  	root, _ := statedb.CommitTo(db, false)
   193  	if common.HexToHash(test.PostStateRoot) != root {
   194  		return fmt.Errorf("Post state root error. Expected: %s have: %x", test.PostStateRoot, root)
   195  	}
   196  
   197  	// check logs
   198  	if len(test.Logs) > 0 {
   199  		if err := checkLogs(test.Logs, logs); err != nil {
   200  			return err
   201  		}
   202  	}
   203  
   204  	return nil
   205  }
   206  
   207  func RunState(ruleSet RuleSet, db ethdb.Database, statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Logs, *big.Int, error) {
   208  	data := common.FromHex(tx["data"])
   209  	gas, _ := new(big.Int).SetString(tx["gasLimit"], 0)
   210  	price, _ := new(big.Int).SetString(tx["gasPrice"], 0)
   211  	value, _ := new(big.Int).SetString(tx["value"], 0)
   212  	if gas == nil || price == nil || value == nil {
   213  		panic("malformed gas, price or value")
   214  	}
   215  	nonce, err := strconv.ParseUint(tx["nonce"], 0, 64)
   216  	if err != nil {
   217  		panic(err)
   218  	}
   219  
   220  	var to *common.Address
   221  	if len(tx["to"]) > 2 {
   222  		t := common.HexToAddress(tx["to"])
   223  		to = &t
   224  	}
   225  	// Set pre compiled contracts
   226  	vm.Precompiled = vm.PrecompiledContracts()
   227  	snapshot := statedb.Snapshot()
   228  	currentGasLimit, ok := new(big.Int).SetString(env["currentGasLimit"], 0)
   229  	if !ok {
   230  		panic("malformed currentGasLimit")
   231  	}
   232  	gaspool := new(core.GasPool).AddGas(currentGasLimit)
   233  
   234  	key, err := hex.DecodeString(tx["secretKey"])
   235  	if err != nil {
   236  		panic(err)
   237  	}
   238  	addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey)
   239  	message := NewMessage(addr, to, data, value, gas, price, nonce)
   240  	vmenv := NewEnvFromMap(ruleSet, statedb, env, tx)
   241  	vmenv.origin = addr
   242  	ret, _, _, err := core.ApplyMessage(vmenv, message, gaspool)
   243  	if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || core.IsGasLimitErr(err) {
   244  		statedb.RevertToSnapshot(snapshot)
   245  	}
   246  	statedb.CommitTo(db, false)
   247  
   248  	return ret, vmenv.state.Logs(), vmenv.Gas, err
   249  }