github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/cmd/evm/staterunner.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU 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  // go-ethereum 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 General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package main
    18  
    19  import (
    20  	"bufio"
    21  	"encoding/json"
    22  	"fmt"
    23  	"os"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/ethereum/go-ethereum/core/rawdb"
    27  	"github.com/ethereum/go-ethereum/core/state"
    28  	"github.com/ethereum/go-ethereum/core/vm"
    29  	"github.com/ethereum/go-ethereum/eth/tracers/logger"
    30  	"github.com/ethereum/go-ethereum/tests"
    31  	"github.com/urfave/cli/v2"
    32  )
    33  
    34  var stateTestCommand = &cli.Command{
    35  	Action:    stateTestCmd,
    36  	Name:      "statetest",
    37  	Usage:     "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).",
    38  	ArgsUsage: "<file>",
    39  }
    40  
    41  // StatetestResult contains the execution status after running a state test, any
    42  // error that might have occurred and a dump of the final state if requested.
    43  type StatetestResult struct {
    44  	Name  string       `json:"name"`
    45  	Pass  bool         `json:"pass"`
    46  	Root  *common.Hash `json:"stateRoot,omitempty"`
    47  	Fork  string       `json:"fork"`
    48  	Error string       `json:"error,omitempty"`
    49  	State *state.Dump  `json:"state,omitempty"`
    50  }
    51  
    52  func stateTestCmd(ctx *cli.Context) error {
    53  	// Configure the EVM logger
    54  	config := &logger.Config{
    55  		EnableMemory:     !ctx.Bool(DisableMemoryFlag.Name),
    56  		DisableStack:     ctx.Bool(DisableStackFlag.Name),
    57  		DisableStorage:   ctx.Bool(DisableStorageFlag.Name),
    58  		EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
    59  	}
    60  	var cfg vm.Config
    61  	switch {
    62  	case ctx.Bool(MachineFlag.Name):
    63  		cfg.Tracer = logger.NewJSONLogger(config, os.Stderr)
    64  
    65  	case ctx.Bool(DebugFlag.Name):
    66  		cfg.Tracer = logger.NewStructLogger(config).Hooks()
    67  	}
    68  	// Load the test content from the input file
    69  	if len(ctx.Args().First()) != 0 {
    70  		return runStateTest(ctx.Args().First(), cfg, ctx.Bool(DumpFlag.Name))
    71  	}
    72  	// Read filenames from stdin and execute back-to-back
    73  	scanner := bufio.NewScanner(os.Stdin)
    74  	for scanner.Scan() {
    75  		fname := scanner.Text()
    76  		if len(fname) == 0 {
    77  			return nil
    78  		}
    79  		if err := runStateTest(fname, cfg, ctx.Bool(DumpFlag.Name)); err != nil {
    80  			return err
    81  		}
    82  	}
    83  	return nil
    84  }
    85  
    86  // runStateTest loads the state-test given by fname, and executes the test.
    87  func runStateTest(fname string, cfg vm.Config, dump bool) error {
    88  	src, err := os.ReadFile(fname)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	var testsByName map[string]tests.StateTest
    93  	if err := json.Unmarshal(src, &testsByName); err != nil {
    94  		return err
    95  	}
    96  
    97  	// Iterate over all the tests, run them and aggregate the results
    98  	results := make([]StatetestResult, 0, len(testsByName))
    99  	for key, test := range testsByName {
   100  		for _, st := range test.Subtests() {
   101  			// Run the test and aggregate the result
   102  			result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true}
   103  			test.Run(st, cfg, false, rawdb.HashScheme, func(err error, tstate *tests.StateTestState) {
   104  				var root common.Hash
   105  				if tstate.StateDB != nil {
   106  					root = tstate.StateDB.IntermediateRoot(false)
   107  					result.Root = &root
   108  					fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
   109  					if dump { // Dump any state to aid debugging
   110  						cpy, _ := state.New(root, tstate.StateDB.Database(), nil)
   111  						dump := cpy.RawDump(nil)
   112  						result.State = &dump
   113  					}
   114  				}
   115  				if err != nil {
   116  					// Test failed, mark as so
   117  					result.Pass, result.Error = false, err.Error()
   118  				}
   119  			})
   120  			results = append(results, *result)
   121  		}
   122  	}
   123  	out, _ := json.MarshalIndent(results, "", "  ")
   124  	fmt.Println(string(out))
   125  	return nil
   126  }