github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/tests/state_test_util.go (about)

     1  // Copyright 2014 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/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/core"
    30  	"github.com/ethereum/go-ethereum/core/state"
    31  	"github.com/ethereum/go-ethereum/core/vm"
    32  	"github.com/ethereum/go-ethereum/crypto"
    33  	"github.com/ethereum/go-ethereum/ethdb"
    34  	"github.com/ethereum/go-ethereum/logger/glog"
    35  )
    36  
    37  func RunStateTestWithReader(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(tests, skipTests); err != nil {
    44  		return err
    45  	}
    46  
    47  	return nil
    48  }
    49  
    50  func RunStateTest(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(tests, skipTests); err != nil {
    57  		return err
    58  	}
    59  
    60  	return nil
    61  
    62  }
    63  
    64  func BenchStateTest(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  	pJit := vm.EnableJit
    75  	vm.EnableJit = conf.jit
    76  	pForceJit := vm.ForceJit
    77  	vm.ForceJit = conf.precomp
    78  
    79  	// XXX Yeah, yeah...
    80  	env := make(map[string]string)
    81  	env["currentCoinbase"] = test.Env.CurrentCoinbase
    82  	env["currentDifficulty"] = test.Env.CurrentDifficulty
    83  	env["currentGasLimit"] = test.Env.CurrentGasLimit
    84  	env["currentNumber"] = test.Env.CurrentNumber
    85  	env["previousHash"] = test.Env.PreviousHash
    86  	if n, ok := test.Env.CurrentTimestamp.(float64); ok {
    87  		env["currentTimestamp"] = strconv.Itoa(int(n))
    88  	} else {
    89  		env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
    90  	}
    91  
    92  	b.ResetTimer()
    93  	for i := 0; i < b.N; i++ {
    94  		benchStateTest(test, env, b)
    95  	}
    96  
    97  	vm.EnableJit = pJit
    98  	vm.ForceJit = pForceJit
    99  
   100  	return nil
   101  }
   102  
   103  func benchStateTest(test VmTest, env map[string]string, b *testing.B) {
   104  	b.StopTimer()
   105  	db, _ := ethdb.NewMemDatabase()
   106  	statedb := state.New(common.Hash{}, db)
   107  	for addr, account := range test.Pre {
   108  		obj := StateObjectFromAccount(db, addr, account)
   109  		statedb.SetStateObject(obj)
   110  		for a, v := range account.Storage {
   111  			obj.SetState(common.HexToHash(a), common.HexToHash(v))
   112  		}
   113  	}
   114  	b.StartTimer()
   115  
   116  	RunState(statedb, env, test.Exec)
   117  }
   118  
   119  func runStateTests(tests map[string]VmTest, skipTests []string) error {
   120  	skipTest := make(map[string]bool, len(skipTests))
   121  	for _, name := range skipTests {
   122  		skipTest[name] = true
   123  	}
   124  
   125  	for name, test := range tests {
   126  		if skipTest[name] {
   127  			glog.Infoln("Skipping state test", name)
   128  			return nil
   129  		}
   130  
   131  		if err := runStateTest(test); err != nil {
   132  			return fmt.Errorf("%s: %s\n", name, err.Error())
   133  		}
   134  
   135  		glog.Infoln("State test passed: ", name)
   136  		//fmt.Println(string(statedb.Dump()))
   137  	}
   138  	return nil
   139  
   140  }
   141  
   142  func runStateTest(test VmTest) error {
   143  	db, _ := ethdb.NewMemDatabase()
   144  	statedb := state.New(common.Hash{}, db)
   145  	for addr, account := range test.Pre {
   146  		obj := StateObjectFromAccount(db, addr, account)
   147  		statedb.SetStateObject(obj)
   148  		for a, v := range account.Storage {
   149  			obj.SetState(common.HexToHash(a), common.HexToHash(v))
   150  		}
   151  	}
   152  
   153  	// XXX Yeah, yeah...
   154  	env := make(map[string]string)
   155  	env["currentCoinbase"] = test.Env.CurrentCoinbase
   156  	env["currentDifficulty"] = test.Env.CurrentDifficulty
   157  	env["currentGasLimit"] = test.Env.CurrentGasLimit
   158  	env["currentNumber"] = test.Env.CurrentNumber
   159  	env["previousHash"] = test.Env.PreviousHash
   160  	if n, ok := test.Env.CurrentTimestamp.(float64); ok {
   161  		env["currentTimestamp"] = strconv.Itoa(int(n))
   162  	} else {
   163  		env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
   164  	}
   165  
   166  	var (
   167  		ret []byte
   168  		// gas  *big.Int
   169  		// err  error
   170  		logs state.Logs
   171  	)
   172  
   173  	ret, logs, _, _ = RunState(statedb, env, test.Transaction)
   174  
   175  	// // Compare expected  and actual return
   176  	rexp := common.FromHex(test.Out)
   177  	if bytes.Compare(rexp, ret) != 0 {
   178  		return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret)
   179  	}
   180  
   181  	// check post state
   182  	for addr, account := range test.Post {
   183  		obj := statedb.GetStateObject(common.HexToAddress(addr))
   184  		if obj == nil {
   185  			continue
   186  		}
   187  
   188  		if obj.Balance().Cmp(common.Big(account.Balance)) != 0 {
   189  			return fmt.Errorf("(%x) balance failed. Expected %v, got %v => %v\n", obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance()))
   190  		}
   191  
   192  		if obj.Nonce() != common.String2Big(account.Nonce).Uint64() {
   193  			return fmt.Errorf("(%x) nonce failed. Expected %v, got %v\n", obj.Address().Bytes()[:4], account.Nonce, obj.Nonce())
   194  		}
   195  
   196  		for addr, value := range account.Storage {
   197  			v := obj.GetState(common.HexToHash(addr))
   198  			vexp := common.HexToHash(value)
   199  
   200  			if v != vexp {
   201  				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())
   202  			}
   203  		}
   204  	}
   205  
   206  	statedb.Sync()
   207  	if common.HexToHash(test.PostStateRoot) != statedb.Root() {
   208  		return fmt.Errorf("Post state root error. Expected %s, got %x", test.PostStateRoot, statedb.Root())
   209  	}
   210  
   211  	// check logs
   212  	if len(test.Logs) > 0 {
   213  		if err := checkLogs(test.Logs, logs); err != nil {
   214  			return err
   215  		}
   216  	}
   217  
   218  	return nil
   219  }
   220  
   221  func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state.Logs, *big.Int, error) {
   222  	var (
   223  		data  = common.FromHex(tx["data"])
   224  		gas   = common.Big(tx["gasLimit"])
   225  		price = common.Big(tx["gasPrice"])
   226  		value = common.Big(tx["value"])
   227  		nonce = common.Big(tx["nonce"]).Uint64()
   228  		caddr = common.HexToAddress(env["currentCoinbase"])
   229  	)
   230  
   231  	var to *common.Address
   232  	if len(tx["to"]) > 2 {
   233  		t := common.HexToAddress(tx["to"])
   234  		to = &t
   235  	}
   236  	// Set pre compiled contracts
   237  	vm.Precompiled = vm.PrecompiledContracts()
   238  
   239  	snapshot := statedb.Copy()
   240  	coinbase := statedb.GetOrNewStateObject(caddr)
   241  	coinbase.SetGasLimit(common.Big(env["currentGasLimit"]))
   242  
   243  	key, _ := hex.DecodeString(tx["secretKey"])
   244  	addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey)
   245  	message := NewMessage(addr, to, data, value, gas, price, nonce)
   246  	vmenv := NewEnvFromMap(statedb, env, tx)
   247  	vmenv.origin = addr
   248  	ret, _, err := core.ApplyMessage(vmenv, message, coinbase)
   249  	if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || state.IsGasLimitErr(err) {
   250  		statedb.Set(snapshot)
   251  	}
   252  	statedb.SyncObjects()
   253  
   254  	return ret, vmenv.state.Logs(), vmenv.Gas, err
   255  }